From 24b18645b9b69f68c1cb426b4714589ca6fe280d Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Mon, 22 Oct 2018 15:07:00 -0400 Subject: [PATCH 001/249] src,win: informative stack traces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refresh `Win32SymbolDebuggingContext::LookupSymbol` to use more APIs PR-URL: https://github.com/nodejs/node/pull/23822 Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-undecorated-symbol-names Reviewed-By: Tobias Nießen --- src/debug_utils.cc | 139 +++++++++++++++++++++++++++++++++++---------- src/debug_utils.h | 14 ++++- 2 files changed, 123 insertions(+), 30 deletions(-) diff --git a/src/debug_utils.cc b/src/debug_utils.cc index a24c51de39cf2d..77ea219bfc880a 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -100,35 +100,104 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext { USE(SymInitialize(current_process_, nullptr, true)); } - ~Win32SymbolDebuggingContext() { + ~Win32SymbolDebuggingContext() override { USE(SymCleanup(current_process_)); } - SymbolInfo LookupSymbol(void* address) override { - // Ref: https://msdn.microsoft.com/en-en/library/windows/desktop/ms680578(v=vs.85).aspx - char info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; - SYMBOL_INFO* info = reinterpret_cast(info_buf); - char demangled[MAX_SYM_NAME]; + using NameAndDisplacement = std::pair; + NameAndDisplacement WrappedSymFromAddr(DWORD64 dwAddress) const { + // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address + // Patches: + // Use `fprintf(stderr, ` instead of `printf` + // `sym.filename = pSymbol->Name` on success + // `current_process_` instead of `hProcess. + DWORD64 dwDisplacement = 0; + // Patch: made into arg - DWORD64 dwAddress = SOME_ADDRESS; + + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + const auto pSymbol = reinterpret_cast(buffer); + + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + + if (SymFromAddr(current_process_, dwAddress, &dwDisplacement, pSymbol)) { + // SymFromAddr returned success + return NameAndDisplacement(pSymbol->Name, dwDisplacement); + } else { + // SymFromAddr failed + const DWORD error = GetLastError(); // "eat" the error anyway +#ifdef DEBUG + fprintf(stderr, "SymFromAddr returned error : %lu\n", error); +#endif + } + // End MSDN code - info->MaxNameLen = MAX_SYM_NAME; - info->SizeOfStruct = sizeof(SYMBOL_INFO); + return NameAndDisplacement(); + } - SymbolInfo ret; - const bool have_info = SymFromAddr(current_process_, - reinterpret_cast(address), - nullptr, - info); - if (have_info && strlen(info->Name) == 0) { - if (UnDecorateSymbolName(info->Name, - demangled, - sizeof(demangled), - UNDNAME_COMPLETE)) { - ret.name = demangled; - } else { - ret.name = info->Name; - } + SymbolInfo WrappedGetLine(DWORD64 dwAddress) const { + SymbolInfo sym{}; + + // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-symbol-information-by-address + // Patches: + // Use `fprintf(stderr, ` instead of `printf`. + // Assign values to `sym` on success. + // `current_process_` instead of `hProcess. + + // Patch: made into arg - DWORD64 dwAddress; + DWORD dwDisplacement; + IMAGEHLP_LINE64 line; + + SymSetOptions(SYMOPT_LOAD_LINES); + + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + // Patch: made into arg - dwAddress = 0x1000000; + + if (SymGetLineFromAddr64(current_process_, dwAddress, + &dwDisplacement, &line)) { + // SymGetLineFromAddr64 returned success + sym.filename = line.FileName; + sym.line = line.LineNumber; + } else { + // SymGetLineFromAddr64 failed + const DWORD error = GetLastError(); // "eat" the error anyway +#ifdef DEBUG + fprintf(stderr, "SymGetLineFromAddr64 returned error : %lu\n", error); +#endif + } + // End MSDN code + + return sym; + } + + // Fills the SymbolInfo::name of the io/out argument `sym` + std::string WrappedUnDecorateSymbolName(const char* name) const { + // Refs: https://docs.microsoft.com/en-us/windows/desktop/Debug/retrieving-undecorated-symbol-names + // Patches: + // Use `fprintf(stderr, ` instead of `printf`. + // return `szUndName` instead of `printf` on success + char szUndName[MAX_SYM_NAME]; + if (UnDecorateSymbolName(name, szUndName, sizeof(szUndName), + UNDNAME_COMPLETE)) { + // UnDecorateSymbolName returned success + return szUndName; + } else { + // UnDecorateSymbolName failed + const DWORD error = GetLastError(); // "eat" the error anyway +#ifdef DEBUG + fprintf(stderr, "UnDecorateSymbolName returned error %lu\n", error); +#endif } + return nullptr; + } + SymbolInfo LookupSymbol(void* address) override { + const DWORD64 dw_address = reinterpret_cast(address); + SymbolInfo ret = WrappedGetLine(dw_address); + std::tie(ret.name, ret.dis) = WrappedSymFromAddr(dw_address); + if (!ret.name.empty()) { + ret.name = WrappedUnDecorateSymbolName(ret.name.c_str()); + } return ret; } @@ -145,6 +214,13 @@ class Win32SymbolDebuggingContext final : public NativeSymbolDebuggingContext { return CaptureStackBackTrace(0, count, frames, nullptr); } + Win32SymbolDebuggingContext(const Win32SymbolDebuggingContext&) = delete; + Win32SymbolDebuggingContext(Win32SymbolDebuggingContext&&) = delete; + Win32SymbolDebuggingContext operator=(const Win32SymbolDebuggingContext&) + = delete; + Win32SymbolDebuggingContext operator=(Win32SymbolDebuggingContext&&) + = delete; + private: HANDLE current_process_; }; @@ -158,13 +234,18 @@ NativeSymbolDebuggingContext::New() { #endif // __POSIX__ std::string NativeSymbolDebuggingContext::SymbolInfo::Display() const { - std::string ret = name; + std::ostringstream oss; + oss << name; + if (dis != 0) { + oss << "+" << dis; + } if (!filename.empty()) { - ret += " ["; - ret += filename; - ret += ']'; + oss << " [" << filename << ']'; + } + if (line != 0) { + oss << ":L" << line; } - return ret; + return oss.str(); } void DumpBacktrace(FILE* fp) { @@ -173,8 +254,8 @@ void DumpBacktrace(FILE* fp) { const int size = sym_ctx->GetStackTrace(frames, arraysize(frames)); for (int i = 1; i < size; i += 1) { void* frame = frames[i]; - fprintf(fp, "%2d: %p %s\n", - i, frame, sym_ctx->LookupSymbol(frame).Display().c_str()); + NativeSymbolDebuggingContext::SymbolInfo s = sym_ctx->LookupSymbol(frame); + fprintf(fp, "%2d: %p %s\n", i, frame, s.Display().c_str()); } } diff --git a/src/debug_utils.h b/src/debug_utils.h index 2fd9e7dab7f8f4..c6c8e03b51fd64 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -6,6 +6,7 @@ #include "async_wrap.h" #include "env.h" #include +#include // Use FORCE_INLINE on functions that have a debug-category-enabled check first // and then ideally only a single function call following it, to maintain @@ -93,14 +94,25 @@ class NativeSymbolDebuggingContext { public: std::string name; std::string filename; + size_t line = 0; + size_t dis = 0; std::string Display() const; }; + NativeSymbolDebuggingContext() = default; virtual ~NativeSymbolDebuggingContext() {} - virtual SymbolInfo LookupSymbol(void* address) { return { "", "" }; } + + virtual SymbolInfo LookupSymbol(void* address) { return {}; } virtual bool IsMapped(void* address) { return false; } virtual int GetStackTrace(void** frames, int count) { return 0; } + + NativeSymbolDebuggingContext(const NativeSymbolDebuggingContext&) = delete; + NativeSymbolDebuggingContext(NativeSymbolDebuggingContext&&) = delete; + NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&) + = delete; + NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&) + = delete; }; // Variant of `uv_loop_close` that tries to be as helpful as possible From 164f2444a070f44ad6e01c204801afaa9bf1f41f Mon Sep 17 00:00:00 2001 From: ZYSzys <17367077526@163.com> Date: Fri, 26 Oct 2018 23:24:01 +0800 Subject: [PATCH 002/249] lib: remove useless cwd in posix.resolve MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23902 Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Tobias Nießen Reviewed-By: James M Snell --- lib/path.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/path.js b/lib/path.js index c8d92f14af04de..798682ca0f1a6b 100644 --- a/lib/path.js +++ b/lib/path.js @@ -1073,16 +1073,13 @@ const posix = { resolve: function resolve() { var resolvedPath = ''; var resolvedAbsolute = false; - var cwd; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path; if (i >= 0) path = arguments[i]; else { - if (cwd === undefined) - cwd = process.cwd(); - path = cwd; + path = process.cwd(); } assertPath(path); From 5ff1e67ff710f29acee1e62acf268fe0f47ecbf3 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 24 Oct 2018 21:15:22 +0800 Subject: [PATCH 003/249] lib: fix code cache generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit e7f710c1 broke the code cache generation since internalBinding is now passed in through the wrapper and cannot be redeclared. This patch fixes that. Refs: https://github.com/nodejs/node/issues/21563 PR-URL: https://github.com/nodejs/node/pull/23855 Reviewed-By: Michaël Zasso Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/bootstrap/cache.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/internal/bootstrap/cache.js b/lib/internal/bootstrap/cache.js index 41fe1e3a914ba0..6181228b033228 100644 --- a/lib/internal/bootstrap/cache.js +++ b/lib/internal/bootstrap/cache.js @@ -6,8 +6,9 @@ // cannot be tampered with even with --expose-internals const { - NativeModule, internalBinding + NativeModule } = require('internal/bootstrap/loaders'); +const { hasTracing } = process.binding('config'); function getCodeCache(id) { const cached = NativeModule.getCached(id); @@ -42,6 +43,16 @@ const cannotUseCache = [ 'internal/bootstrap/node' ].concat(depsModule); +// Skip modules that cannot be required when they are not +// built into the binary. +if (process.config.variables.v8_enable_inspector !== 1) { + cannotUseCache.push('inspector'); + cannotUseCache.push('internal/util/inspector'); +} +if (!hasTracing) { + cannotUseCache.push('trace_events'); +} + module.exports = { cachableBuiltins: Object.keys(NativeModule._source).filter( (key) => !cannotUseCache.includes(key) From 7a2134c41465bd243df39394fff58f97d0a51a23 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 24 Oct 2018 23:24:31 +0800 Subject: [PATCH 004/249] test: run code cache test by default and test generator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add the code cache tests to the default test suite, and test the bookkeeping when the binary is not built with the code cache. - Test the code cache generator to make sure we do not accidentally break it - until we enable code cache in the CI. Refs: https://github.com/nodejs/node/issues/21563 PR-URL: https://github.com/nodejs/node/pull/23855 Reviewed-By: Michaël Zasso Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- test/code-cache/test-code-cache-generator.js | 58 ++++++++++++++++++++ test/code-cache/test-code-cache.js | 46 ++++++++++------ tools/test.py | 1 - 3 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 test/code-cache/test-code-cache-generator.js diff --git a/test/code-cache/test-code-cache-generator.js b/test/code-cache/test-code-cache-generator.js new file mode 100644 index 00000000000000..972d89629c0a23 --- /dev/null +++ b/test/code-cache/test-code-cache-generator.js @@ -0,0 +1,58 @@ +'use strict'; + +// This test verifies that the binary is compiled with code cache and the +// cache is used when built in modules are compiled. + +const common = require('../common'); + +const tmpdir = require('../common/tmpdir'); +const { spawnSync } = require('child_process'); +const assert = require('assert'); +const path = require('path'); +const fs = require('fs'); +const readline = require('readline'); + +const generator = path.join( + __dirname, '..', '..', 'tools', 'generate_code_cache.js' +); +tmpdir.refresh(); +const dest = path.join(tmpdir.path, 'cache.cc'); + +// Run tools/generate_code_cache.js +const child = spawnSync( + process.execPath, + ['--expose-internals', generator, dest] +); +assert.ifError(child.error); +if (child.status !== 0) { + console.log(child.stderr.toString()); + assert.strictEqual(child.status, 0); +} + +// Verifies that: +// - node::DefineCodeCache() +// - node::DefineCodeCacheHash() +// are defined in the generated code. +// See src/node_code_cache_stub.cc for explanations. + +const rl = readline.createInterface({ + input: fs.createReadStream(dest), + crlfDelay: Infinity +}); + +let hasCacheDef = false; +let hasHashDef = false; + +rl.on('line', common.mustCallAtLeast((line) => { + if (line.includes('DefineCodeCache(')) { + hasCacheDef = true; + } + if (line.includes('DefineCodeCacheHash(')) { + hasHashDef = true; + } +}, 2)); + +rl.on('close', common.mustCall(() => { + assert.ok(hasCacheDef); + assert.ok(hasHashDef); +})); diff --git a/test/code-cache/test-code-cache.js b/test/code-cache/test-code-cache.js index b05e764e8ad290..c1bfa80f4342f3 100644 --- a/test/code-cache/test-code-cache.js +++ b/test/code-cache/test-code-cache.js @@ -1,8 +1,9 @@ 'use strict'; // Flags: --expose-internals -// This test verifies that the binary is compiled with code cache and the -// cache is used when built in modules are compiled. +// This test verifies that if the binary is compiled with code cache, +// and the cache is used when built in modules are compiled. +// Otherwise, verifies that no cache is used when compiling builtins. require('../common'); const assert = require('assert'); @@ -18,23 +19,36 @@ const { compiledWithoutCache } = require('internal/bootstrap/cache'); -assert.strictEqual( - typeof process.config.variables.node_code_cache_path, - 'string' -); - -assert.deepStrictEqual(compiledWithoutCache, []); - const loadedModules = process.moduleLoadList .filter((m) => m.startsWith('NativeModule')) .map((m) => m.replace('NativeModule ', '')); -for (const key of loadedModules) { - assert(compiledWithCache.includes(key), - `"${key}" should've been compiled with code cache`); -} +// The binary is not configured with code cache, verifies that the builtins +// are all compiled without cache and we are doing the bookkeeping right. +if (process.config.variables.node_code_cache_path === undefined) { + assert.deepStrictEqual(compiledWithCache, []); + assert.notStrictEqual(compiledWithoutCache.length, 0); + + for (const key of loadedModules) { + assert(compiledWithoutCache.includes(key), + `"${key}" should not have been compiled with code cache`); + } -for (const key of cachableBuiltins) { - assert(isUint8Array(codeCache[key]) && codeCache[key].length > 0, - `Code cache for "${key}" should've been generated`); +} else { + // The binary is configured with code cache. + assert.strictEqual( + typeof process.config.variables.node_code_cache_path, + 'string' + ); + assert.deepStrictEqual(compiledWithoutCache, []); + + for (const key of loadedModules) { + assert(compiledWithCache.includes(key), + `"${key}" should've been compiled with code cache`); + } + + for (const key of cachableBuiltins) { + assert(isUint8Array(codeCache[key]) && codeCache[key].length > 0, + `Code cache for "${key}" should've been generated`); + } } diff --git a/tools/test.py b/tools/test.py index 3d0ba43beca8b5..cd361196653043 100755 --- a/tools/test.py +++ b/tools/test.py @@ -1498,7 +1498,6 @@ def PrintCrashed(code): IGNORED_SUITES = [ 'addons', 'addons-napi', - 'code-cache', 'doctool', 'internet', 'pummel', From d6bcf8b98b7e8ddd6c5467f56542ce4c242ae915 Mon Sep 17 00:00:00 2001 From: Mathias Buus Date: Tue, 21 Aug 2018 20:05:12 +0200 Subject: [PATCH 005/249] stream: add auto-destroy mode PR-URL: https://github.com/nodejs/node/pull/22795 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Anna Henningsen Reviewed-By: Jeremiah Senkpiel --- doc/api/stream.md | 17 +++++ lib/_stream_readable.js | 23 +++++-- lib/_stream_writable.js | 26 +++++-- lib/internal/streams/destroy.js | 20 +++++- test/parallel/test-stream-auto-destroy.js | 84 +++++++++++++++++++++++ 5 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 test/parallel/test-stream-auto-destroy.js diff --git a/doc/api/stream.md b/doc/api/stream.md index fb2f2da28d1a87..f2e1c2a0c4ff9e 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -1493,6 +1493,11 @@ changes: pr-url: https://github.com/nodejs/node/pull/18438 description: > Add `emitClose` option to specify if `'close'` is emitted on destroy + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/22795 + description: > + Add `autoDestroy` option to automatically `destroy()` the stream + when it emits `'finish'` or errors --> * `options` {Object} @@ -1521,6 +1526,8 @@ changes: [`stream._destroy()`][writable-_destroy] method. * `final` {Function} Implementation for the [`stream._final()`][stream-_final] method. + * `autoDestroy` {boolean} Whether this stream should automatically call + `.destroy()` on itself after ending. **Default:** `false`. ```js const { Writable } = require('stream'); @@ -1756,6 +1763,14 @@ Custom `Readable` streams *must* call the `new stream.Readable([options])` constructor and implement the `readable._read()` method. #### new stream.Readable([options]) + * `options` {Object} * `highWaterMark` {number} The maximum [number of bytes][hwm-gotcha] to store @@ -1770,6 +1785,8 @@ constructor and implement the `readable._read()` method. method. * `destroy` {Function} Implementation for the [`stream._destroy()`][readable-_destroy] method. + * `autoDestroy` {boolean} Whether this stream should automatically call + `.destroy()` on itself after ending. **Default:** `false`. ```js const { Readable } = require('stream'); diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 488d10a10b5bbd..2a2122e0e553cd 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -46,6 +46,7 @@ let createReadableStreamAsyncIterator; util.inherits(Readable, Stream); +const { errorOrDestroy } = destroyImpl; const kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; function prependListener(emitter, event, fn) { @@ -117,6 +118,9 @@ function ReadableState(options, stream, isDuplex) { // Should close be emitted on destroy. Defaults to true. this.emitClose = options.emitClose !== false; + // Should .destroy() be called after 'end' (and potentially 'finish') + this.autoDestroy = !!options.autoDestroy; + // has it been destroyed this.destroyed = false; @@ -235,7 +239,7 @@ function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { if (!skipChunkCheck) er = chunkInvalid(state, chunk); if (er) { - stream.emit('error', er); + errorOrDestroy(stream, er); } else if (state.objectMode || chunk && chunk.length > 0) { if (typeof chunk !== 'string' && !state.objectMode && @@ -245,11 +249,11 @@ function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { if (addToFront) { if (state.endEmitted) - stream.emit('error', new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); + errorOrDestroy(stream, new ERR_STREAM_UNSHIFT_AFTER_END_EVENT()); else addChunk(stream, state, chunk, true); } else if (state.ended) { - stream.emit('error', new ERR_STREAM_PUSH_AFTER_EOF()); + errorOrDestroy(stream, new ERR_STREAM_PUSH_AFTER_EOF()); } else if (state.destroyed) { return false; } else { @@ -581,7 +585,7 @@ function maybeReadMore_(stream, state) { // for virtual (non-string, non-buffer) streams, "length" is somewhat // arbitrary, and perhaps not very meaningful. Readable.prototype._read = function(n) { - this.emit('error', new ERR_METHOD_NOT_IMPLEMENTED('_read()')); + errorOrDestroy(this, new ERR_METHOD_NOT_IMPLEMENTED('_read()')); }; Readable.prototype.pipe = function(dest, pipeOpts) { @@ -687,7 +691,7 @@ Readable.prototype.pipe = function(dest, pipeOpts) { unpipe(); dest.removeListener('error', onerror); if (EE.listenerCount(dest, 'error') === 0) - dest.emit('error', er); + errorOrDestroy(dest, er); } // Make sure our error handler is attached before userland ones. @@ -1092,5 +1096,14 @@ function endReadableNT(state, stream) { state.endEmitted = true; stream.readable = false; stream.emit('end'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the writable side is ready for autoDestroy as well + const wState = stream._writableState; + if (!wState || (wState.autoDestroy && wState.finished)) { + stream.destroy(); + } + } } } diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 3bad957912b323..160179cd0e84fa 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -45,6 +45,8 @@ const { ERR_UNKNOWN_ENCODING } = require('internal/errors').codes; +const { errorOrDestroy } = destroyImpl; + util.inherits(Writable, Stream); function nop() {} @@ -147,6 +149,9 @@ function WritableState(options, stream, isDuplex) { // Should close be emitted on destroy. Defaults to true. this.emitClose = options.emitClose !== false; + // Should .destroy() be called after 'finish' (and potentially 'end') + this.autoDestroy = !!options.autoDestroy; + // count buffered requests this.bufferedRequestCount = 0; @@ -235,14 +240,14 @@ function Writable(options) { // Otherwise people can pipe Writable streams, which is just wrong. Writable.prototype.pipe = function() { - this.emit('error', new ERR_STREAM_CANNOT_PIPE()); + errorOrDestroy(this, new ERR_STREAM_CANNOT_PIPE()); }; function writeAfterEnd(stream, cb) { var er = new ERR_STREAM_WRITE_AFTER_END(); // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); + errorOrDestroy(stream, er); process.nextTick(cb, er); } @@ -258,7 +263,7 @@ function validChunk(stream, state, chunk, cb) { er = new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk); } if (er) { - stream.emit('error', er); + errorOrDestroy(stream, er); process.nextTick(cb, er); return false; } @@ -422,13 +427,13 @@ function onwriteError(stream, state, sync, er, cb) { // after error process.nextTick(finishMaybe, stream, state); stream._writableState.errorEmitted = true; - stream.emit('error', er); + errorOrDestroy(stream, er); } else { // the caller expect this to happen before if // it is async cb(er); stream._writableState.errorEmitted = true; - stream.emit('error', er); + errorOrDestroy(stream, er); // this can emit finish, but finish must // always follow error finishMaybe(stream, state); @@ -612,7 +617,7 @@ function callFinal(stream, state) { stream._final((err) => { state.pendingcb--; if (err) { - stream.emit('error', err); + errorOrDestroy(stream, err); } state.prefinished = true; stream.emit('prefinish'); @@ -639,6 +644,15 @@ function finishMaybe(stream, state) { if (state.pendingcb === 0) { state.finished = true; stream.emit('finish'); + + if (state.autoDestroy) { + // In case of duplex streams we need a way to detect + // if the readable side is ready for autoDestroy as well + const rState = stream._readableState; + if (!rState || (rState.autoDestroy && rState.endEmitted)) { + stream.destroy(); + } + } } } return need; diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 3a0383cc3cea70..ce9d2545e45022 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -82,7 +82,25 @@ function emitErrorNT(self, err) { self.emit('error', err); } +function errorOrDestroy(stream, err) { + // We have tests that rely on errors being emitted + // in the same tick, so changing this is semver major. + // For now when you opt-in to autoDestroy we allow + // the error to be emitted nextTick. In a future + // semver major update we should change the default to this. + + const rState = stream._readableState; + const wState = stream._writableState; + + if ((rState && rState.autoDestroy) || (wState && wState.autoDestroy)) + stream.destroy(err); + else + stream.emit('error', err); +} + + module.exports = { destroy, - undestroy + undestroy, + errorOrDestroy }; diff --git a/test/parallel/test-stream-auto-destroy.js b/test/parallel/test-stream-auto-destroy.js new file mode 100644 index 00000000000000..7bce8a56368313 --- /dev/null +++ b/test/parallel/test-stream-auto-destroy.js @@ -0,0 +1,84 @@ +'use strict'; +const common = require('../common'); +const stream = require('stream'); +const assert = require('assert'); + +{ + const r = new stream.Readable({ + autoDestroy: true, + read() { + this.push('hello'); + this.push('world'); + this.push(null); + }, + destroy: common.mustCall((err, cb) => cb()) + }); + + let ended = false; + + r.resume(); + + r.on('end', common.mustCall(() => { + ended = true; + })); + + r.on('close', common.mustCall(() => { + assert(ended); + })); +} + +{ + const w = new stream.Writable({ + autoDestroy: true, + write(data, enc, cb) { + cb(null); + }, + destroy: common.mustCall((err, cb) => cb()) + }); + + let finished = false; + + w.write('hello'); + w.write('world'); + w.end(); + + w.on('finish', common.mustCall(() => { + finished = true; + })); + + w.on('close', common.mustCall(() => { + assert(finished); + })); +} + +{ + const t = new stream.Transform({ + autoDestroy: true, + transform(data, enc, cb) { + cb(null, data); + }, + destroy: common.mustCall((err, cb) => cb()) + }); + + let ended = false; + let finished = false; + + t.write('hello'); + t.write('world'); + t.end(); + + t.resume(); + + t.on('end', common.mustCall(() => { + ended = true; + })); + + t.on('finish', common.mustCall(() => { + finished = true; + })); + + t.on('close', common.mustCall(() => { + assert(ended); + assert(finished); + })); +} From 063b40edc16f1618626cd6313b1742fcceada472 Mon Sep 17 00:00:00 2001 From: Ouyang Yadong Date: Thu, 25 Oct 2018 14:05:41 +0800 Subject: [PATCH 006/249] src: use "constants" string instead of creating new one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the same "constants" string in c++. PR-URL: https://github.com/nodejs/node/pull/23894 Reviewed-By: Anna Henningsen Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Сковорода Никита Андреевич --- src/node_http2.cc | 2 +- src/pipe_wrap.cc | 2 +- src/tcp_wrap.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/node_http2.cc b/src/node_http2.cc index ce5523a9d22aa8..a77f123d32a0bf 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -3111,7 +3111,7 @@ HTTP_STATUS_CODES(V) env->SetMethod(target, "packSettings", PackSettings); target->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "constants"), + env->constants_string(), constants).FromJust(); target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "nameForErrorCode"), diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index eb1e06876c2d86..66b9677cc92fec 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -109,7 +109,7 @@ void PipeWrap::Initialize(Local target, NODE_DEFINE_CONSTANT(constants, UV_READABLE); NODE_DEFINE_CONSTANT(constants, UV_WRITABLE); target->Set(context, - FIXED_ONE_BYTE_STRING(env->isolate(), "constants"), + env->constants_string(), constants).FromJust(); } diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index cda30d84105735..d462eff15d391c 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -124,7 +124,7 @@ void TCPWrap::Initialize(Local target, NODE_DEFINE_CONSTANT(constants, SOCKET); NODE_DEFINE_CONSTANT(constants, SERVER); target->Set(context, - FIXED_ONE_BYTE_STRING(env->isolate(), "constants"), + env->constants_string(), constants).FromJust(); } From 55adc25968ae0242bd4ed91af370232a4c42c948 Mon Sep 17 00:00:00 2001 From: Ouyang Yadong Date: Mon, 29 Oct 2018 07:36:19 -0400 Subject: [PATCH 007/249] lib: enable TypedArray and DataView for the v8 module This commit allow passing `TypedArray` and `DataView` to: - v8.deserialize() - new v8.Deserializer() - v8.serializer.writeRawBytes() PR-URL: https://github.com/nodejs/node/pull/23953 Refs: https://github.com/nodejs/node/issues/1826 Reviewed-By: James M Snell Reviewed-By: Ben Noordhuis Reviewed-By: Refael Ackermann --- doc/api/v8.md | 6 +-- src/node_serdes.cc | 8 ++-- test/parallel/test-v8-serdes.js | 84 +++++++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) diff --git a/doc/api/v8.md b/doc/api/v8.md index 4a04e89319927d..6ce474a9baea30 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -185,7 +185,7 @@ Uses a [`DefaultSerializer`][] to serialize `value` into a buffer. added: v8.0.0 --> -* `buffer` {Buffer|Uint8Array} A buffer returned by [`serialize()`][]. +* `buffer` {Buffer|TypedArray|DataView} A buffer returned by [`serialize()`][]. Uses a [`DefaultDeserializer`][] with default options to read a JS value from a buffer. @@ -252,7 +252,7 @@ For use inside of a custom [`serializer._writeHostObject()`][]. #### serializer.writeRawBytes(buffer) -* `buffer` {Buffer|Uint8Array} +* `buffer` {Buffer|TypedArray|DataView} Write raw bytes into the serializer’s internal buffer. The deserializer will require a way to compute the length of the buffer. @@ -308,7 +308,7 @@ added: v8.0.0 #### new Deserializer(buffer) -* `buffer` {Buffer|Uint8Array} A buffer returned by +* `buffer` {Buffer|TypedArray|DataView} A buffer returned by [`serializer.releaseBuffer()`][]. Creates a new `Deserializer` object. diff --git a/src/node_serdes.cc b/src/node_serdes.cc index bb7890a7300e16..0a410944458d99 100644 --- a/src/node_serdes.cc +++ b/src/node_serdes.cc @@ -266,9 +266,9 @@ void SerializerContext::WriteRawBytes(const FunctionCallbackInfo& args) { SerializerContext* ctx; ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Holder()); - if (!args[0]->IsUint8Array()) { + if (!args[0]->IsArrayBufferView()) { return node::THROW_ERR_INVALID_ARG_TYPE( - ctx->env(), "source must be a Uint8Array"); + ctx->env(), "source must be a TypedArray or a DataView"); } ctx->serializer_.WriteRawBytes(Buffer::Data(args[0]), @@ -317,9 +317,9 @@ MaybeLocal DeserializerContext::ReadHostObject(Isolate* isolate) { void DeserializerContext::New(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - if (!args[0]->IsUint8Array()) { + if (!args[0]->IsArrayBufferView()) { return node::THROW_ERR_INVALID_ARG_TYPE( - env, "buffer must be a Uint8Array"); + env, "buffer must be a TypedArray or a DataView"); } new DeserializerContext(env, args.This(), args[0]); diff --git a/test/parallel/test-v8-serdes.js b/test/parallel/test-v8-serdes.js index 94f10dbfe9fb09..c019674f4592e4 100644 --- a/test/parallel/test-v8-serdes.js +++ b/test/parallel/test-v8-serdes.js @@ -98,6 +98,47 @@ const deserializerTypeError = assert.strictEqual(des.readValue().val, hostObject); } +// This test ensures that `v8.Serializer.writeRawBytes()` support +// `TypedArray` and `DataView`. +{ + const text = 'hostObjectTag'; + const data = Buffer.from(text); + const arrayBufferViews = common.getArrayBufferViews(data); + + // `buf` is one of `TypedArray` or `DataView`. + function testWriteRawBytes(buf) { + let writeHostObjectCalled = false; + const ser = new v8.DefaultSerializer(); + + ser._writeHostObject = common.mustCall((object) => { + writeHostObjectCalled = true; + ser.writeUint32(buf.byteLength); + ser.writeRawBytes(buf); + }); + + ser.writeHeader(); + ser.writeValue({ val: hostObject }); + + const des = new v8.DefaultDeserializer(ser.releaseBuffer()); + des._readHostObject = common.mustCall(() => { + assert.strictEqual(writeHostObjectCalled, true); + const length = des.readUint32(); + const buf = des.readRawBytes(length); + assert.strictEqual(buf.toString(), text); + + return hostObject; + }); + + des.readHeader(); + + assert.strictEqual(des.readValue().val, hostObject); + } + + arrayBufferViews.forEach((buf) => { + testWriteRawBytes(buf); + }); +} + { const ser = new v8.DefaultSerializer(); ser._writeHostObject = common.mustCall((object) => { @@ -146,3 +187,46 @@ const deserializerTypeError = assert.throws(v8.Serializer, serializerTypeError); assert.throws(v8.Deserializer, deserializerTypeError); } + + +// `v8.deserialize()` and `new v8.Deserializer()` should support both +// `TypedArray` and `DataView`. +{ + for (const obj of objects) { + const buf = v8.serialize(obj); + + for (const arrayBufferView of common.getArrayBufferViews(buf)) { + assert.deepStrictEqual(v8.deserialize(arrayBufferView), obj); + } + + for (const arrayBufferView of common.getArrayBufferViews(buf)) { + const deserializer = new v8.DefaultDeserializer(arrayBufferView); + deserializer.readHeader(); + const value = deserializer.readValue(); + assert.deepStrictEqual(value, obj); + + const serializer = new v8.DefaultSerializer(); + serializer.writeHeader(); + serializer.writeValue(value); + assert.deepStrictEqual(buf, serializer.releaseBuffer()); + } + } +} + +{ + const INVALID_SOURCE = 'INVALID_SOURCE_TYPE'; + const serializer = new v8.Serializer(); + serializer.writeHeader(); + assert.throws( + () => serializer.writeRawBytes(INVALID_SOURCE), + /^TypeError: source must be a TypedArray or a DataView$/, + ); + assert.throws( + () => v8.deserialize(INVALID_SOURCE), + /^TypeError: buffer must be a TypedArray or a DataView$/, + ); + assert.throws( + () => new v8.Deserializer(INVALID_SOURCE), + /^TypeError: buffer must be a TypedArray or a DataView$/, + ); +} From e7133f1e7c2c71b2f5a180472c7d120e2b37bc74 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Tue, 16 Oct 2018 18:25:44 -0400 Subject: [PATCH 008/249] build: configure default v8_optimized_debug Under the assumption that debugging is more often focused on node core source. This setting compiles V8 with only partial optimizations, DCHECKS, and debug symbols, so it is still very much debuggable, but it is much faster. It does disable SLOW_DCHECKS, but at the advice of the V8 team, those are more important for deep V8 debugging. Override is configurable with `./configure --v8-non-optimized-debug`. PR-URL: https://github.com/nodejs/node/pull/23704 Reviewed-By: Joyee Cheung Reviewed-By: Ujjwal Sharma --- common.gypi | 3 --- configure.py | 8 +++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index bacd496538a383..d9a0ac67278ce6 100644 --- a/common.gypi +++ b/common.gypi @@ -28,9 +28,6 @@ 'openssl_fips%': '', - # Default to -O0 for debug builds. - 'v8_optimized_debug%': 0, - # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. 'v8_embedder_string': '-node.7', diff --git a/configure.py b/configure.py index 5bc53630f3985b..05a7fbc4cc93a0 100755 --- a/configure.py +++ b/configure.py @@ -566,6 +566,12 @@ default=False, help='get more output from this script') +parser.add_option('--v8-non-optimized-debug', + action='store_true', + dest='v8_non_optimized_debug', + default=False, + help='compile V8 with minimal optimizations and with runtime checks') + # Create compile_commands.json in out/Debug and out/Release. parser.add_option('-C', action='store_true', @@ -1138,7 +1144,7 @@ def configure_library(lib, output): def configure_v8(o): o['variables']['v8_enable_gdbjit'] = 1 if options.gdb else 0 o['variables']['v8_no_strict_aliasing'] = 1 # Work around compiler bugs. - o['variables']['v8_optimized_debug'] = 0 # Compile with -O0 in debug builds. + o['variables']['v8_optimized_debug'] = 0 if options.v8_non_optimized_debug else 1 o['variables']['v8_random_seed'] = 0 # Use a random seed for hash tables. o['variables']['v8_promise_internal_field_count'] = 1 # Add internal field to promises for async hooks. o['variables']['v8_use_snapshot'] = 'false' if options.without_snapshot else 'true' From ef8b5b4094bcec3f67ae49d18b048d5164fcd362 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Mon, 15 Oct 2018 18:32:11 -0400 Subject: [PATCH 009/249] deps,v8: fix gypfile bug PR-URL: https://github.com/nodejs/node/pull/23704 Reviewed-By: Joyee Cheung Reviewed-By: Ujjwal Sharma --- common.gypi | 2 +- deps/v8/gypfiles/toolchain.gypi | 258 ++++++++++++++------------------ deps/v8/gypfiles/v8.gyp | 21 +-- 3 files changed, 115 insertions(+), 166 deletions(-) diff --git a/common.gypi b/common.gypi index d9a0ac67278ce6..779073a635bebe 100644 --- a/common.gypi +++ b/common.gypi @@ -30,7 +30,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.7', + 'v8_embedder_string': '-node.8', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/deps/v8/gypfiles/toolchain.gypi b/deps/v8/gypfiles/toolchain.gypi index ea8f1c2f00da56..4860c5b7724e20 100644 --- a/deps/v8/gypfiles/toolchain.gypi +++ b/deps/v8/gypfiles/toolchain.gypi @@ -1134,121 +1134,7 @@ }], ], # conditions 'configurations': { - # Abstract configuration for v8_optimized_debug == 0. - 'DebugBase0': { - 'abstract': 1, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '0', - 'conditions': [ - ['component=="shared_library" or force_dynamic_crt==1', { - 'RuntimeLibrary': '3', # /MDd - }, { - 'RuntimeLibrary': '1', # /MTd - }], - ], - }, - 'VCLinkerTool': { - 'LinkIncremental': '2', - }, - }, - 'variables': { - 'v8_enable_slow_dchecks%': 1, - }, - 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix"', { - 'cflags!': [ - '-O3', - '-O2', - '-O1', - '-Os', - ], - 'cflags': [ - '-fdata-sections', - '-ffunction-sections', - ], - }], - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '0', # -O0 - }, - }], - ['v8_enable_slow_dchecks==1', { - 'defines': [ - 'ENABLE_SLOW_DCHECKS', - ], - }], - ], - }, # DebugBase0 - # Abstract configuration for v8_optimized_debug == 1. - 'DebugBase1': { - 'abstract': 1, - 'msvs_settings': { - 'VCCLCompilerTool': { - 'Optimization': '2', - 'InlineFunctionExpansion': '2', - 'EnableIntrinsicFunctions': 'true', - 'FavorSizeOrSpeed': '0', - 'StringPooling': 'true', - 'BasicRuntimeChecks': '0', - 'conditions': [ - ['component=="shared_library" or force_dynamic_crt==1', { - 'RuntimeLibrary': '3', #/MDd - }, { - 'RuntimeLibrary': '1', #/MTd - }], - ], - }, - 'VCLinkerTool': { - 'LinkIncremental': '1', - 'OptimizeReferences': '2', - 'EnableCOMDATFolding': '2', - }, - }, - 'variables': { - 'v8_enable_slow_dchecks%': 0, - }, - 'conditions': [ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ - OS=="qnx" or OS=="aix"', { - 'cflags!': [ - '-O0', - '-O1', - '-Os', - ], - 'cflags': [ - '-fdata-sections', - '-ffunction-sections', - ], - 'conditions': [ - # Don't use -O3 with sanitizers. - ['asan==0 and msan==0 and lsan==0 \ - and tsan==0 and ubsan==0 and ubsan_vptr==0', { - 'cflags': ['-O3'], - 'cflags!': ['-O2'], - }, { - 'cflags': ['-O2'], - 'cflags!': ['-O3'], - }], - ], - }], - ['OS=="mac"', { - 'xcode_settings': { - 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 - 'GCC_STRICT_ALIASING': 'YES', - }, - }], - ['v8_enable_slow_dchecks==1', { - 'defines': [ - 'ENABLE_SLOW_DCHECKS', - ], - }], - ], - }, # DebugBase1 - # Common settings for the Debug configuration. - 'DebugBaseCommon': { - 'abstract': 1, + 'Debug': { 'defines': [ 'ENABLE_DISASSEMBLER', 'V8_ENABLE_CHECKS', @@ -1311,27 +1197,126 @@ }], ], }], - ], - }, # DebugBaseCommon - 'Debug': { - 'inherit_from': ['DebugBaseCommon'], - 'conditions': [ ['v8_optimized_debug==0', { - 'inherit_from': ['DebugBase0'], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '0', + 'conditions': [ + ['component=="shared_library" or force_dynamic_crt==1', { + 'RuntimeLibrary': '3', # /MDd + }, { + 'RuntimeLibrary': '1', # /MTd + }], + ], + }, + 'VCLinkerTool': { + 'LinkIncremental': '2', + }, + }, + 'variables': { + 'v8_enable_slow_dchecks%': 1, + }, + 'conditions': [ + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ + OS=="qnx" or OS=="aix"', { + 'cflags!': [ + '-O3', + '-O2', + '-O1', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '0', # -O0 + }, + }], + ['v8_enable_slow_dchecks==1', { + 'defines': [ + 'ENABLE_SLOW_DCHECKS', + ], + }], + ], }, { - 'inherit_from': ['DebugBase1'], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'Optimization': '2', + 'InlineFunctionExpansion': '2', + 'EnableIntrinsicFunctions': 'true', + 'FavorSizeOrSpeed': '0', + 'StringPooling': 'true', + 'BasicRuntimeChecks': '0', + 'conditions': [ + ['component=="shared_library" or force_dynamic_crt==1', { + 'RuntimeLibrary': '3', #/MDd + }, { + 'RuntimeLibrary': '1', #/MTd + }], + ], + }, + 'VCLinkerTool': { + 'LinkIncremental': '1', + 'OptimizeReferences': '2', + 'EnableCOMDATFolding': '2', + }, + }, + 'variables': { + 'v8_enable_slow_dchecks%': 0, + }, + 'conditions': [ + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" or \ + OS=="qnx" or OS=="aix"', { + 'cflags!': [ + '-O0', + '-O1', + '-Os', + ], + 'cflags': [ + '-fdata-sections', + '-ffunction-sections', + ], + 'conditions': [ + # Don't use -O3 with sanitizers. + ['asan==0 and msan==0 and lsan==0 \ + and tsan==0 and ubsan==0 and ubsan_vptr==0', { + 'cflags': ['-O3'], + 'cflags!': ['-O2'], + }, { + 'cflags': ['-O2'], + 'cflags!': ['-O3'], + }], + ], + }], + ['OS=="mac"', { + 'xcode_settings': { + 'GCC_OPTIMIZATION_LEVEL': '3', # -O3 + 'GCC_STRICT_ALIASING': 'YES', + }, + }], + ['v8_enable_slow_dchecks==1', { + 'defines': [ + 'ENABLE_SLOW_DCHECKS', + ], + }], + ], }], # Temporary refs: https://github.com/nodejs/node/pull/23801 ['v8_enable_handle_zapping==1', { 'defines': ['ENABLE_HANDLE_ZAPPING',], }], ], - }, # Debug - 'ReleaseBase': { - 'abstract': 1, + + }, # DebugBaseCommon + 'Release': { 'variables': { 'v8_enable_slow_dchecks%': 0, }, + # Temporary refs: https://github.com/nodejs/node/pull/23801 + 'defines!': ['ENABLE_HANDLE_ZAPPING',], 'conditions': [ ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd" \ or OS=="aix"', { @@ -1407,29 +1392,6 @@ }], ], # conditions }, # Release - 'Release': { - 'inherit_from': ['ReleaseBase'], - # Temporary refs: https://github.com/nodejs/node/pull/23801 - 'defines!': ['ENABLE_HANDLE_ZAPPING',], - }, # Debug - 'conditions': [ - [ 'OS=="win"', { - # TODO(bradnelson): add a gyp mechanism to make this more graceful. - 'Debug_x64': { - 'inherit_from': ['DebugBaseCommon'], - 'conditions': [ - ['v8_optimized_debug==0', { - 'inherit_from': ['DebugBase0'], - }, { - 'inherit_from': ['DebugBase1'], - }], - ], - }, - 'Release_x64': { - 'inherit_from': ['ReleaseBase'], - }, - }], - ], }, # configurations 'msvs_disabled_warnings': [ 4245, # Conversion with signed/unsigned mismatch. diff --git a/deps/v8/gypfiles/v8.gyp b/deps/v8/gypfiles/v8.gyp index f47cf075bb63bf..0c257025caeae4 100644 --- a/deps/v8/gypfiles/v8.gyp +++ b/deps/v8/gypfiles/v8.gyp @@ -2539,23 +2539,10 @@ '_HAS_EXCEPTIONS=0', 'BUILDING_V8_SHARED=1', ], - # This is defined trough `configurations` for GYP+ninja compatibility - 'configurations': { - 'Debug': { - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeTypeInfo': 'true', - 'ExceptionHandling': 1, - }, - } - }, - 'Release': { - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeTypeInfo': 'true', - 'ExceptionHandling': 1, - }, - } + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeTypeInfo': 'true', + 'ExceptionHandling': 1, }, }, 'sources': [ From 4651cd721d3659e4841da1b9f7d35e8f884e65ab Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Mon, 29 Oct 2018 14:40:38 -0400 Subject: [PATCH 010/249] build: add -Werror=undefined-inline to clang builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23961 Refs: https://github.com/nodejs/node/pull/23954 Refs: https://github.com/nodejs/node/pull/23910 Refs: https://github.com/nodejs/node/pull/23880 Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung --- node.gypi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node.gypi b/node.gypi index 0b27e6ad2c1ac4..eba49be69c3cc5 100644 --- a/node.gypi +++ b/node.gypi @@ -32,9 +32,13 @@ '-Wendif-labels', '-W', '-Wno-unused-parameter', + '-Werror=undefined-inline', ], }, 'conditions': [ + ['clang==1', { + 'cflags': [ '-Werror=undefined-inline', ] + }], [ 'node_shared=="false"', { 'msvs_settings': { 'VCManifestTool': { From 90872c4c6ee4089013837ad85d160ad2ac7b1ee0 Mon Sep 17 00:00:00 2001 From: Suresh Srinivas Date: Mon, 29 Oct 2018 16:47:27 -0700 Subject: [PATCH 011/249] src: fix fully-static & large-pages combination Fixes: https://github.com/nodejs/node/issues/23906 Refs: https://github.com/nodejs/node/pull/22079 This change to ld.implicit.script moves libc static code to .lpstub area and avoids the issue detailed in 23906 Quick performance comparision on web-tooling shows 3% improvement for the combination over fully-static cycles 376,235,487,455 390,007,877,315 instructions 700,341,146,973 714,773,201,182 itlb_misses_walk_completed 20,654,246 28,908,381 itlb_misses_walk_completed_4k 19,884,666 28,865,118 itlb_misses_walk_completed_2m_4m 769,391 43,251 Score 9.13 8.86 PR-URL: https://github.com/nodejs/node/pull/23964 Reviewed-By: Refael Ackermann Reviewed-By: Ben Noordhuis --- src/large_pages/ld.implicit.script | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/large_pages/ld.implicit.script b/src/large_pages/ld.implicit.script index ad7ce1b2e2e5cf..7f12e4bd7df9e5 100644 --- a/src/large_pages/ld.implicit.script +++ b/src/large_pages/ld.implicit.script @@ -1,8 +1,10 @@ SECTIONS { - .lpstub : { *(.lpstub) } + .lpstub : { + *libc.a:*(.text .text.*) + *(.lpstub) + } } PROVIDE (__nodetext = .); PROVIDE (_nodetext = .); PROVIDE (nodetext = .); INSERT BEFORE .text; - From 762679efeca43f3d697d3075760f644da3413092 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 29 Oct 2018 10:27:34 +0100 Subject: [PATCH 012/249] build: make benchmark/napi all prereq order-only This commit makes the all prerequisites order-only to prevent this target's rules to be executed every time which is currently the case as the all target is a phony target and will be executed every time. PR-URL: https://github.com/nodejs/node/pull/23951 Reviewed-By: Richard Lau Reviewed-By: Franziska Hinkelmann Reviewed-By: Refael Ackermann --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 88be22fcace3ec..aa8d75242c00f5 100644 --- a/Makefile +++ b/Makefile @@ -308,19 +308,19 @@ test-valgrind: all test-check-deopts: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) --check-deopts parallel sequential -benchmark/napi/function_call/build/Release/binding.node: all \ +benchmark/napi/function_call/build/Release/binding.node: \ benchmark/napi/function_call/napi_binding.c \ benchmark/napi/function_call/binding.cc \ - benchmark/napi/function_call/binding.gyp + benchmark/napi/function_call/binding.gyp | all $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ --python="$(PYTHON)" \ --directory="$(shell pwd)/benchmark/napi/function_call" \ --nodedir="$(shell pwd)" -benchmark/napi/function_args/build/Release/binding.node: all \ +benchmark/napi/function_args/build/Release/binding.node: \ benchmark/napi/function_args/napi_binding.c \ benchmark/napi/function_args/binding.cc \ - benchmark/napi/function_args/binding.gyp + benchmark/napi/function_args/binding.gyp | all $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ --python="$(PYTHON)" \ --directory="$(shell pwd)/benchmark/napi/function_args" \ From b182e2e8b20b2b77b9f62198547780ee103c8a79 Mon Sep 17 00:00:00 2001 From: Ouyang Yadong Date: Wed, 31 Oct 2018 16:53:38 +0800 Subject: [PATCH 013/249] doc: add types and their corresponding return values This commit supplements some types and their corresponding return values in docs, including `AsyncResource`, `DiffieHellman`, `ECDH`, `https.Server`, `repl.REPLServer`. PR-URL: https://github.com/nodejs/node/pull/23998 Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca --- doc/api/async_hooks.md | 2 ++ doc/api/crypto.md | 5 ++++- doc/api/https.md | 3 +++ doc/api/repl.md | 1 + doc/api/tls.md | 5 +++++ tools/doc/type-parser.js | 7 +++++++ 6 files changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index ff3e14b96c250e..0e061a9a238615 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -704,6 +704,8 @@ alternative. #### asyncResource.emitDestroy() +* Returns: {AsyncResource} A reference to `asyncResource`. + Call all `destroy` hooks. This should only ever be called once. An error will be thrown if it is called more than once. This **must** be manually called. If the resource is left to be collected by the GC then the `destroy` hooks will diff --git a/doc/api/crypto.md b/doc/api/crypto.md index c00fad6578891e..d12eb6d1360d38 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1533,6 +1533,7 @@ changes: * `generator` {number | string | Buffer | TypedArray | DataView} **Default:** `2` * `generatorEncoding` {string} +* Returns: {DiffieHellman} Creates a `DiffieHellman` key exchange object using the supplied `prime` and an optional specific `generator`. @@ -1556,6 +1557,7 @@ added: v0.5.0 * `primeLength` {number} * `generator` {number | string | Buffer | TypedArray | DataView} **Default:** `2` +* Returns: {DiffieHellman} Creates a `DiffieHellman` key exchange object and generates a prime of `primeLength` bits using an optional specific numeric `generator`. @@ -1566,6 +1568,7 @@ If `generator` is not specified, the value `2` is used. added: v0.11.14 --> * `curveName` {string} +* Returns: {ECDH} Creates an Elliptic Curve Diffie-Hellman (`ECDH`) key exchange object using a predefined curve specified by the `curveName` string. Use @@ -1818,7 +1821,7 @@ console.log(curves); // ['Oakley-EC2N-3', 'Oakley-EC2N-4', ...] added: v0.7.5 --> * `groupName` {string} -* Returns: {Object} +* Returns: {DiffieHellman} Creates a predefined `DiffieHellman` key exchange object. The supported groups are: `'modp1'`, `'modp2'`, `'modp5'` (defined in diff --git a/doc/api/https.md b/doc/api/https.md index 66c96f2c6708c9..777fbab741c85f 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -28,6 +28,7 @@ This class is a subclass of `tls.Server` and emits events same as added: v0.1.90 --> * `callback` {Function} +* Returns: {https.Server} See [`server.close()`][`http.close()`] from the HTTP module for details. @@ -49,6 +50,7 @@ added: v0.11.2 --> * `msecs` {number} **Default:** `120000` (2 minutes) * `callback` {Function} +* Returns: {https.Server} See [`http.Server#setTimeout()`][]. @@ -75,6 +77,7 @@ added: v0.3.4 * `options` {Object} Accepts `options` from [`tls.createServer()`][], [`tls.createSecureContext()`][] and [`http.createServer()`][]. * `requestListener` {Function} A listener to be added to the `'request'` event. +* Returns: {https.Server} ```js // curl -k https://localhost:8000/ diff --git a/doc/api/repl.md b/doc/api/repl.md index d010265327e5fa..09fe9ebcbece61 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -499,6 +499,7 @@ changes: * `breakEvalOnSigint` - Stop evaluating the current piece of code when `SIGINT` is received, i.e. `Ctrl+C` is pressed. This cannot be used together with a custom `eval` function. **Default:** `false`. +* Returns: {repl.REPLServer} The `repl.start()` method creates and starts a [`repl.REPLServer`][] instance. diff --git a/doc/api/tls.md b/doc/api/tls.md index 8700839c400b38..ec36b4e57128ec 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -378,6 +378,7 @@ added: v0.3.2 * `callback` {Function} A listener callback that will be registered to listen for the server instance's `'close'` event. +* Returns: {tls.Server} The `server.close()` method stops the server from accepting new connections. @@ -926,6 +927,7 @@ changes: * ...: [`tls.createSecureContext()`][] options that are used if the `secureContext` option is missing, otherwise they are ignored. * `callback` {Function} +* Returns: {tls.TLSSocket} The `callback` function, if specified, will be added as a listener for the [`'secureConnect'`][] event. @@ -1000,6 +1002,7 @@ added: v0.11.3 * `path` {string} Default value for `options.path`. * `options` {Object} See [`tls.connect()`][]. * `callback` {Function} See [`tls.connect()`][]. +* Returns: {tls.TLSSocket} Same as [`tls.connect()`][] except that `path` can be provided as an argument instead of an option. @@ -1015,6 +1018,7 @@ added: v0.11.3 * `host` {string} Default value for `options.host`. * `options` {Object} See [`tls.connect()`][]. * `callback` {Function} See [`tls.connect()`][]. +* Returns: {tls.TLSSocket} Same as [`tls.connect()`][] except that `port` and `host` can be provided as arguments instead of options. @@ -1191,6 +1195,7 @@ changes: * ...: Any [`tls.createSecureContext()`][] option can be provided. For servers, the identity options (`pfx` or `key`/`cert`) are usually required. * `secureConnectionListener` {Function} +* Returns: {tls.Server} Creates a new [`tls.Server`][]. The `secureConnectionListener`, if provided, is automatically set as a listener for the [`'secureConnection'`][] event. diff --git a/tools/doc/type-parser.js b/tools/doc/type-parser.js index b57dc6957a9ae0..49d888e88b9900 100644 --- a/tools/doc/type-parser.js +++ b/tools/doc/type-parser.js @@ -36,6 +36,7 @@ const customTypesMap = { `${jsDocPrefix}Reference/Iteration_protocols#The_iterator_protocol`, 'AsyncHook': 'async_hooks.html#async_hooks_async_hooks_createhook_callbacks', + 'AsyncResource': 'async_hooks.html#async_hooks_class_asyncresource', 'Buffer': 'buffer.html#buffer_class_buffer', @@ -45,6 +46,8 @@ const customTypesMap = { 'Cipher': 'crypto.html#crypto_class_cipher', 'Decipher': 'crypto.html#crypto_class_decipher', + 'DiffieHellman': 'crypto.html#crypto_class_diffiehellman', + 'ECDH': 'crypto.html#crypto_class_ecdh', 'Hash': 'crypto.html#crypto_class_hash', 'Hmac': 'crypto.html#crypto_class_hmac', 'Sign': 'crypto.html#crypto_class_sign', @@ -83,6 +86,8 @@ const customTypesMap = { 'Http2Stream': 'http2.html#http2_class_http2stream', 'ServerHttp2Stream': 'http2.html#http2_class_serverhttp2stream', + 'https.Server': 'https.html#https_class_https_server', + 'module': 'modules.html#modules_the_module_object', 'Handle': 'net.html#net_server_listen_handle_backlog_callback', @@ -101,6 +106,8 @@ const customTypesMap = { 'readline.Interface': 'readline.html#readline_class_interface', + 'repl.REPLServer': 'repl.html#repl_class_replserver', + 'Stream': 'stream.html#stream_stream', 'stream.Duplex': 'stream.html#stream_class_stream_duplex', 'stream.Readable': 'stream.html#stream_class_stream_readable', From 846e450f512c7ed25fc0777f1f3ebe687e39fca9 Mon Sep 17 00:00:00 2001 From: Jagannath Bhat Date: Tue, 30 Oct 2018 23:01:18 +0530 Subject: [PATCH 014/249] doc: improve BUILDING.md PR-URL: https://github.com/nodejs/node/pull/23976 Reviewed-By: Anna Henningsen Reviewed-By: Denys Otrishko Reviewed-By: Vse Mozhet Byt Reviewed-By: Richard Lau Reviewed-By: James M Snell Reviewed-By: Rich Trott --- BUILDING.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 7c5bd632f24ab0..462e7b4a0104b6 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -96,8 +96,8 @@ platforms in production. by Joyent. SmartOS images >= 16.4 are not supported because GCC 4.8 runtime libraries are not available in their pkgsrc repository -2: Tier 1 support for building on Windows is only on 64 bit - hosts. Support is experimental for 32 bit hosts. +2: Tier 1 support for building on Windows is only on 64-bit + hosts. Support is experimental for 32-bit hosts. 3: On Windows, running Node.js in Windows terminal emulators like `mintty` requires the usage of [winpty](https://github.com/rprichard/winpty) @@ -115,7 +115,7 @@ platforms in production. ### Supported toolchains -Depending on host platform, the selection of toolchains may vary. +Depending on the host platform, the selection of toolchains may vary. #### Unix @@ -127,11 +127,11 @@ Depending on host platform, the selection of toolchains may vary. #### Windows -* Visual Studio 2017 with the Windows 10 SDK on a 64 bit host. +* Visual Studio 2017 with the Windows 10 SDK on a 64-bit host. #### OpenSSL asm support -OpenSSL-1.1.0 requires the following asssembler version for use of asm +OpenSSL-1.1.0 requires the following assembler version for use of asm support on x86_64 and ia32. * gas (GNU assembler) version 2.23 or higher @@ -365,7 +365,7 @@ These core dumps are useful for debugging when provided with the corresponding original debug binary and system information. Reading the core dump requires `gdb` built on the same platform the core dump -was captured on (i.e. 64 bit `gdb` for `node` built on a 64 bit system, Linux +was captured on (i.e. 64-bit `gdb` for `node` built on a 64-bit system, Linux `gdb` for `node` built on Linux) otherwise you will get errors like `not in executable format: File format not recognized`. @@ -484,7 +484,7 @@ $ ./configure --without-intl $ pkg-config --modversion icu-i18n && ./configure --with-intl=system-icu ``` -If you are cross compiling, your `pkg-config` must be able to supply a path +If you are cross-compiling, your `pkg-config` must be able to supply a path that works for both your host and target environments. #### Build with a specific ICU: @@ -532,7 +532,7 @@ This version of Node.js does not support FIPS. ## Building Node.js with external core modules It is possible to specify one or more JavaScript text files to be bundled in -the binary as builtin modules when building Node.js. +the binary as built-in modules when building Node.js. ### Unix/macOS From b8a71bed0220fe8dae3c89489a576dc9595e6f6a Mon Sep 17 00:00:00 2001 From: Jagannath Bhat Date: Tue, 30 Oct 2018 23:08:04 +0530 Subject: [PATCH 015/249] doc: improve COLLABORATOR_GUIDE PR-URL: https://github.com/nodejs/node/pull/23977 Reviewed-By: Denys Otrishko Reviewed-By: Vse Mozhet Byt Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- COLLABORATOR_GUIDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 7cfc6388c549b5..fd26ea5f15d0db 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -497,7 +497,7 @@ This should be done where a pull request: Assign the `tsc-review` label or @-mention the `@nodejs/tsc` GitHub team if you want to elevate an issue to the [TSC][]. -Do not use the GitHub UI on the right hand side to assign to +Do not use the GitHub UI on the right-hand side to assign to `@nodejs/tsc` or request a review from `@nodejs/tsc`. The TSC should serve as the final arbiter where required. @@ -528,7 +528,7 @@ The TSC should serve as the final arbiter where required. you are unsure exactly how to format the commit messages, use the commit log as a reference. See [this commit][commit-example] as an example. -For PRs from first time contributors, be [welcoming](#welcoming-first-time-contributors). +For PRs from first-time contributors, be [welcoming](#welcoming-first-time-contributors). Also, verify that their git settings are to their liking. All commits should be self-contained, meaning every commit should pass all From 8bffd9093399582a42976da90969f974f1fbf6fd Mon Sep 17 00:00:00 2001 From: Ali Ijaz Sheikh Date: Tue, 30 Oct 2018 16:59:53 -0700 Subject: [PATCH 016/249] test: fix test-fs-watch-system-limit On some systems the default inotify limits might be too high for the test to actually fail. Detect and skip the test in such environments. PR-URL: https://github.com/nodejs/node/pull/23986 Reviewed-By: Richard Lau Reviewed-By: Luigi Pinca --- test/sequential/test-fs-watch-system-limit.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/sequential/test-fs-watch-system-limit.js b/test/sequential/test-fs-watch-system-limit.js index e896cbf83b965a..8b9cb62ad0a007 100644 --- a/test/sequential/test-fs-watch-system-limit.js +++ b/test/sequential/test-fs-watch-system-limit.js @@ -2,6 +2,7 @@ const common = require('../common'); const assert = require('assert'); const child_process = require('child_process'); +const fs = require('fs'); const stream = require('stream'); if (!common.isLinux) @@ -9,6 +10,20 @@ if (!common.isLinux) if (!common.enoughTestCpu) common.skip('This test is resource-intensive'); +try { + // Ensure inotify limit is low enough for the test to actually exercise the + // limit with small enough resources. + const limit = Number( + fs.readFileSync('/proc/sys/fs/inotify/max_user_watches', 'utf8')); + if (limit > 16384) + common.skip('inotify limit is quite large'); +} catch (e) { + if (e.code === 'ENOENT') + common.skip('the inotify /proc subsystem does not exist'); + // Fail on other errors. + throw e; +} + const processes = []; const gatherStderr = new stream.PassThrough(); gatherStderr.setEncoding('utf8'); From 1dd819151514cfbdb76316c6a9fb47200afdd088 Mon Sep 17 00:00:00 2001 From: Geoffrey Booth Date: Mon, 1 Oct 2018 22:12:47 -0700 Subject: [PATCH 017/249] module: support multi-dot file extension Support multi-dot file extensions like '.coffee.md' in Module.load. PR-URL: https://github.com/nodejs/node/pull/23416 Reviewed-By: Anna Henningsen Reviewed-By: John-David Dalton --- lib/internal/modules/cjs/loader.js | 19 +++- .../test-module-deleted-extensions.js | 18 ---- test/parallel/test-module-multi-extensions.js | 94 +++++++++++++++++++ 3 files changed, 111 insertions(+), 20 deletions(-) delete mode 100644 test/known_issues/test-module-deleted-extensions.js create mode 100644 test/parallel/test-module-multi-extensions.js diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 975c688edab3d7..4a5fc596c0511d 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -219,6 +219,22 @@ function tryExtensions(p, exts, isMain) { return false; } +// find the longest (possibly multi-dot) extension registered in +// Module._extensions +function findLongestRegisteredExtension(filename) { + const name = path.basename(filename); + let currentExtension; + let index; + let startIndex = 0; + while ((index = name.indexOf('.', startIndex)) !== -1) { + startIndex = index + 1; + if (index === 0) continue; // Skip dotfiles like .gitignore + currentExtension = name.slice(index); + if (Module._extensions[currentExtension]) return currentExtension; + } + return '.js'; +} + var warned = false; Module._findPath = function(request, paths, isMain) { if (path.isAbsolute(request)) { @@ -600,8 +616,7 @@ Module.prototype.load = function(filename) { this.filename = filename; this.paths = Module._nodeModulePaths(path.dirname(filename)); - var extension = path.extname(filename) || '.js'; - if (!Module._extensions[extension]) extension = '.js'; + var extension = findLongestRegisteredExtension(filename); Module._extensions[extension](this, filename); this.loaded = true; diff --git a/test/known_issues/test-module-deleted-extensions.js b/test/known_issues/test-module-deleted-extensions.js deleted file mode 100644 index 3a51e8725eec60..00000000000000 --- a/test/known_issues/test-module-deleted-extensions.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; -// Refs: https://github.com/nodejs/node/issues/4778 -const common = require('../common'); -const assert = require('assert'); -const fs = require('fs'); -const path = require('path'); -const tmpdir = require('../common/tmpdir'); -const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); - -tmpdir.refresh(); -fs.writeFileSync(file, '', 'utf8'); -require.extensions['.foo.bar'] = (module, path) => {}; -delete require.extensions['.foo.bar']; -require.extensions['.bar'] = common.mustCall((module, path) => { - assert.strictEqual(module.id, file); - assert.strictEqual(path, file); -}); -require(path.join(tmpdir.path, 'test-extensions')); diff --git a/test/parallel/test-module-multi-extensions.js b/test/parallel/test-module-multi-extensions.js new file mode 100644 index 00000000000000..be17bc5d025508 --- /dev/null +++ b/test/parallel/test-module-multi-extensions.js @@ -0,0 +1,94 @@ +'use strict'; + +// Refs: https://github.com/nodejs/node/issues/4778 + +const common = require('../common'); +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const Module = require('module'); +const tmpdir = require('../common/tmpdir'); +const file = path.join(tmpdir.path, 'test-extensions.foo.bar'); +const dotfile = path.join(tmpdir.path, '.bar'); +const dotfileWithExtension = path.join(tmpdir.path, '.foo.bar'); + +tmpdir.refresh(); +fs.writeFileSync(file, 'console.log(__filename);', 'utf8'); +fs.writeFileSync(dotfile, 'console.log(__filename);', 'utf8'); +fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); + +{ + require.extensions['.bar'] = common.mustNotCall(); + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions'); + require(modulePath); + require(file); + delete require.cache[file]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions'); + require(modulePath); + assert.throws( + () => require(`${modulePath}.foo`), + new Error(`Cannot find module '${modulePath}.foo'`) + ); + require(`${modulePath}.foo.bar`); + delete require.cache[file]; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + const modulePath = path.join(tmpdir.path, 'test-extensions'); + assert.throws( + () => require(modulePath), + new Error(`Cannot find module '${modulePath}'`) + ); + delete require.cache[file]; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustNotCall(); + require.extensions['.foo.bar'] = common.mustCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions.foo'); + require(modulePath); + delete require.cache[file]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.foo.bar'] = common.mustNotCall(); + const modulePath = path.join(tmpdir.path, 'test-extensions.foo'); + assert.throws( + () => require(modulePath), + new Error(`Cannot find module '${modulePath}'`) + ); + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustNotCall(); + require(dotfile); + delete require.cache[dotfile]; + delete require.extensions['.bar']; + Module._pathCache = Object.create(null); +} + +{ + require.extensions['.bar'] = common.mustCall(); + require.extensions['.foo.bar'] = common.mustNotCall(); + require(dotfileWithExtension); + delete require.cache[dotfileWithExtension]; + delete require.extensions['.bar']; + delete require.extensions['.foo.bar']; + Module._pathCache = Object.create(null); +} From 4af63ee5d9247e152fdf65dda746c702d4cbe57c Mon Sep 17 00:00:00 2001 From: Shobhit Chittora Date: Mon, 20 Aug 2018 21:32:31 +0530 Subject: [PATCH 018/249] child_process: handle undefined/null for fork() args PR-URL: https://github.com/nodejs/node/pull/22416 Fixes: https://github.com/nodejs/node/issues/20749 Reviewed-By: James M Snell Reviewed-By: Denys Otrishko Reviewed-By: Matheus Marchini --- lib/child_process.js | 5 +++ test/fixtures/child-process-echo-options.js | 1 + .../test-child-process-fork-options.js | 37 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 test/fixtures/child-process-echo-options.js create mode 100644 test/parallel/test-child-process-fork-options.js diff --git a/lib/child_process.js b/lib/child_process.js index 7ac3a3bcc0a7f3..e2b7a3292069d1 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -69,6 +69,11 @@ exports.fork = function fork(modulePath /* , args, options */) { args = arguments[pos++]; } + if (pos < arguments.length && + (arguments[pos] === undefined || arguments[pos] === null)) { + pos++; + } + if (pos < arguments.length && arguments[pos] != null) { if (typeof arguments[pos] !== 'object') { throw new ERR_INVALID_ARG_VALUE(`arguments[${pos}]`, arguments[pos]); diff --git a/test/fixtures/child-process-echo-options.js b/test/fixtures/child-process-echo-options.js new file mode 100644 index 00000000000000..04f3f8dcffe6a9 --- /dev/null +++ b/test/fixtures/child-process-echo-options.js @@ -0,0 +1 @@ +process.send({ env: process.env }); diff --git a/test/parallel/test-child-process-fork-options.js b/test/parallel/test-child-process-fork-options.js new file mode 100644 index 00000000000000..5efb9bdbb49735 --- /dev/null +++ b/test/parallel/test-child-process-fork-options.js @@ -0,0 +1,37 @@ +'use strict'; +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +// This test ensures that fork should parse options +// correctly if args is undefined or null + +const assert = require('assert'); +const { fork } = require('child_process'); + +const expectedEnv = { foo: 'bar' }; + +{ + const cp = fork(fixtures.path('child-process-echo-options.js'), undefined, + { env: Object.assign({}, process.env, expectedEnv) }); + + cp.on('message', common.mustCall(({ env }) => { + assert.strictEqual(env.foo, expectedEnv.foo); + })); + + cp.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} + +{ + const cp = fork(fixtures.path('child-process-echo-options.js'), null, + { env: Object.assign({}, process.env, expectedEnv) }); + + cp.on('message', common.mustCall(({ env }) => { + assert.strictEqual(env.foo, expectedEnv.foo); + })); + + cp.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} From dccf4a6c380f7c9cc27960ec34cae536da94e7f8 Mon Sep 17 00:00:00 2001 From: mritunjaygoutam12 Date: Tue, 30 Oct 2018 12:59:02 +0530 Subject: [PATCH 019/249] test: add property for RangeError in test-buffer-copy PR-URL: https://github.com/nodejs/node/pull/23968 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig --- test/parallel/test-buffer-copy.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-buffer-copy.js b/test/parallel/test-buffer-copy.js index 8ede5101463b05..6fb6a4ec707ef0 100644 --- a/test/parallel/test-buffer-copy.js +++ b/test/parallel/test-buffer-copy.js @@ -1,10 +1,17 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const b = Buffer.allocUnsafe(1024); const c = Buffer.allocUnsafe(512); + +const errorProperty = { + code: 'ERR_OUT_OF_RANGE', + type: RangeError, + message: 'Index out of range' +}; + let cntr = 0; { @@ -96,9 +103,9 @@ bb.fill('hello crazy world'); b.copy(c, 0, 100, 10); // copy throws at negative sourceStart -assert.throws(function() { - Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1); -}, RangeError); +common.expectsError( + () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1), + errorProperty); { // check sourceEnd resets to targetEnd if former is greater than the latter @@ -111,7 +118,8 @@ assert.throws(function() { } // throw with negative sourceEnd -assert.throws(() => b.copy(c, 0, 0, -1), RangeError); +common.expectsError( + () => b.copy(c, 0, -1), errorProperty); // when sourceStart is greater than sourceEnd, zero copied assert.strictEqual(b.copy(c, 0, 100, 10), 0); From 63778b7ae1753dbd252797df577d11f52433eafd Mon Sep 17 00:00:00 2001 From: Esteban Sotillo Date: Mon, 29 Oct 2018 15:22:43 +0100 Subject: [PATCH 020/249] test: fix strictEqual arguments order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23956 Reviewed-By: Colin Ihrig Reviewed-By: Michaël Zasso Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat Reviewed-By: Franziska Hinkelmann --- test/parallel/test-http2-write-empty-string.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-http2-write-empty-string.js b/test/parallel/test-http2-write-empty-string.js index 6e6ce5254ddcfc..ea591176a47251 100644 --- a/test/parallel/test-http2-write-empty-string.js +++ b/test/parallel/test-http2-write-empty-string.js @@ -25,7 +25,7 @@ server.listen(0, common.mustCall(function() { let res = ''; req.on('response', common.mustCall(function(headers) { - assert.strictEqual(200, headers[':status']); + assert.strictEqual(headers[':status'], 200); })); req.on('data', (chunk) => { @@ -33,7 +33,7 @@ server.listen(0, common.mustCall(function() { }); req.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', res); + assert.strictEqual(res, '1\n2\n3\n'); client.close(); })); From 1b97dbd6b5d925df1b9bcbe51131511ae2bb68bb Mon Sep 17 00:00:00 2001 From: Jerome Covington Date: Sun, 28 Oct 2018 13:55:59 -0400 Subject: [PATCH 021/249] test: assert that invalidcmd throws error code Update invalidcmd test case in test-child-process-spawn-typeerror to assert on specific expected error code. PR-URL: https://github.com/nodejs/node/pull/23942 Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Rich Trott --- test/parallel/test-child-process-spawn-typeerror.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/parallel/test-child-process-spawn-typeerror.js b/test/parallel/test-child-process-spawn-typeerror.js index 31a1867df945f7..82acaf8e088038 100644 --- a/test/parallel/test-child-process-spawn-typeerror.js +++ b/test/parallel/test-child-process-spawn-typeerror.js @@ -33,12 +33,11 @@ const invalidArgValueError = common.expectsError({ code: 'ERR_INVALID_ARG_VALUE', type: TypeError }, 14); const invalidArgTypeError = - common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 12); + common.expectsError({ code: 'ERR_INVALID_ARG_TYPE', type: TypeError }, 13); assert.throws(function() { - const child = spawn(invalidcmd, 'this is not an array'); - child.on('error', common.mustNotCall()); -}, TypeError); + spawn(invalidcmd, 'this is not an array'); +}, invalidArgTypeError); // Verify that valid argument combinations do not throw. spawn(cmd); From 4d7fbc3e0fa1e94d8640d545cae8bef835963633 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Tue, 30 Oct 2018 14:34:20 -0400 Subject: [PATCH 022/249] tools: update alternative docs versions Add `11.x` and mark `10.x` as `lts`. PR-URL: https://github.com/nodejs/node/pull/23980 Reviewed-By: Refael Ackermann Reviewed-By: Vse Mozhet Byt Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca --- tools/doc/html.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/doc/html.js b/tools/doc/html.js index fd74563dd7fc97..9c9c355574d4e5 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -404,7 +404,8 @@ function altDocs(filename, docCreated) { const [, docCreatedMajor, docCreatedMinor] = docCreated.map(Number); const host = 'https://nodejs.org'; const versions = [ - { num: '10.x' }, + { num: '11.x' }, + { num: '10.x', lts: true }, { num: '9.x' }, { num: '8.x', lts: true }, { num: '7.x' }, From 7b7155e90bf51debb36059248ee82dd45651d5b4 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 30 Oct 2018 23:14:11 -0700 Subject: [PATCH 023/249] doc: revise CHANGELOG.md text Make the text shorter and clearer. PR-URL: https://github.com/nodejs/node/pull/23988 Reviewed-By: Trivikram Kamat Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- CHANGELOG.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6569f47757dca9..d0012a1c48e4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,5 @@ # Node.js Changelog - - -To make the changelog easier to both use and manage, it has been split into -multiple files organized according to significant major and minor Node.js -release lines. - Select a Node.js version below to view the changelog history: * [Node.js 11](doc/changelogs/CHANGELOG_V11.md) - **Current** @@ -129,10 +123,9 @@ release. ### Notes -* Release streams marked with `LTS` are currently covered by the - [Node.js Long Term Support plan](https://github.com/nodejs/Release). -* Release versions displayed in **bold** text represent the most - recent actively supported release. +* The [Node.js Long Term Support plan](https://github.com/nodejs/Release) covers + LTS releases. +* Release versions in **bold** text are the most recent supported releases. ---- ---- From 879402b4229db1cac23848f9399a83edf20114e8 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 30 Oct 2018 23:22:04 -0700 Subject: [PATCH 024/249] doc: simplify CODE_OF_CONDUCT.md PR-URL: https://github.com/nodejs/node/pull/23989 Reviewed-By: Refael Ackermann Reviewed-By: Richard Lau Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig Reviewed-By: Vse Mozhet Byt Reviewed-By: Michael Dawson Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- CODE_OF_CONDUCT.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5a935352a1f9f0..4c211405596cb4 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,8 +1,4 @@ # Code of Conduct -The Node.js Code of Conduct document has moved to -https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md. Please update -links to this document accordingly. - -The Node.js Moderation policy can be found at -https://github.com/nodejs/admin/blob/master/Moderation-Policy.md +* [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) +* [Node.js Moderation Policy](https://github.com/nodejs/admin/blob/master/Moderation-Policy.md) From 399d64b331a75b64d75def562a6f4a2975ba833b Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 30 Oct 2018 23:41:03 -0700 Subject: [PATCH 025/249] doc: revise COLLABORATOR_GUIDE.md Simplify text/content. PR-URL: https://github.com/nodejs/node/pull/23990 Reviewed-By: Ben Noordhuis Reviewed-By: Richard Lau Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig Reviewed-By: Vse Mozhet Byt Reviewed-By: Michael Dawson Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- COLLABORATOR_GUIDE.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index fd26ea5f15d0db..7fa6fee197aabc 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -28,7 +28,7 @@ - [Using `git-node`](#using-git-node) - [Technical HOWTO](#technical-howto) - [Troubleshooting](#troubleshooting) - - [I Just Made a Mistake](#i-just-made-a-mistake) + - [I Made a Mistake](#i-made-a-mistake) - [Long Term Support](#long-term-support) - [What is LTS?](#what-is-lts) - [How does LTS work?](#how-does-lts-work) @@ -38,13 +38,10 @@ - [How is an LTS release cut?](#how-is-an-lts-release-cut) * [Who to CC in the issue tracker](#who-to-cc-in-the-issue-tracker) -This document contains information for Collaborators of the Node.js -project regarding managing the project's code, documentation, and issue tracker. - -Collaborators should be familiar with the guidelines for new -contributors in [CONTRIBUTING.md](./CONTRIBUTING.md) and also -understand the project governance model as outlined in -[GOVERNANCE.md](./GOVERNANCE.md). +This document explains how Collaborators manage the Node.js project. +Collaborators should understand the +[guidelines for new contributors](CONTRIBUTING.md) and the +[project governance model](GOVERNANCE.md). ## Issues and Pull Requests @@ -747,7 +744,7 @@ make -j4 test git push upstream master ``` -### I Just Made a Mistake +### I Made a Mistake * Ping a TSC member. * `#node-dev` on freenode From 7012f72a12777c80c8ad97e21af22bf6840be632 Mon Sep 17 00:00:00 2001 From: Jagannath Bhat Date: Tue, 30 Oct 2018 23:12:09 +0530 Subject: [PATCH 026/249] doc: address bits of proof reading work PR-URL: https://github.com/nodejs/node/pull/23978 Reviewed-By: Anna Henningsen Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell Reviewed-By: Rich Trott --- GOVERNANCE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 40ef6e7bbe5fcb..da6706e87f0d8c 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -45,7 +45,7 @@ be accepted unless: * Discussions and/or additional changes result in no Collaborators objecting to the change. Previously-objecting Collaborators do not necessarily have to - sign-off on the change, but they should not be opposed to it. + sign off on the change, but they should not be opposed to it. * The change is escalated to the TSC and the TSC votes to approve the change. This should only happen if disagreements between Collaborators cannot be resolved through discussion. @@ -123,7 +123,7 @@ The meeting chair is responsible for ensuring that minutes are taken and that a pull request with the minutes is submitted after the meeting. Due to the challenges of scheduling a global meeting with participants in -several timezones, the TSC will seek to resolve as many agenda items as possible +several time zones, the TSC will seek to resolve as many agenda items as possible outside of meetings using [the TSC issue tracker](https://github.com/nodejs/TSC/issues). The process in the issue tracker is: @@ -196,7 +196,7 @@ completed within a month after the nomination is accepted. ## Consensus Seeking Process -The TSC follows a [Consensus Seeking][] decision making model as described by +The TSC follows a [Consensus Seeking][] decision-making model as described by the [TSC Charter][]. [collaborators-discussions]: https://github.com/orgs/nodejs/teams/collaborators/discussions From 38b0525bc33362a86ca221e6c36335b1f6467374 Mon Sep 17 00:00:00 2001 From: ZYSzys <17367077526@163.com> Date: Tue, 30 Oct 2018 19:14:09 +0800 Subject: [PATCH 027/249] src: use v8:: for consistency in util MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/23934 Reviewed-By: Anna Henningsen Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca Reviewed-By: James M Snell Reviewed-By: Franziska Hinkelmann --- src/node_util.cc | 20 +++++++++++++------- src/util.cc | 4 ++-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/node_util.cc b/src/node_util.cc index c183f314a1394f..ac39be407dd47f 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -6,19 +6,25 @@ namespace util { using v8::ALL_PROPERTIES; using v8::Array; +using v8::Boolean; using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; +using v8::IndexFilter; using v8::Integer; using v8::Isolate; +using v8::KeyCollectionMode; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::ONLY_CONFIGURABLE; using v8::ONLY_ENUMERABLE; using v8::ONLY_WRITABLE; using v8::Private; using v8::Promise; +using v8::PropertyFilter; using v8::Proxy; +using v8::ReadOnly; using v8::SKIP_STRINGS; using v8::SKIP_SYMBOLS; using v8::String; @@ -37,13 +43,13 @@ static void GetOwnNonIndexProperties( Local properties; - v8::PropertyFilter filter = - static_cast(args[1].As()->Value()); + PropertyFilter filter = + static_cast(args[1].As()->Value()); if (!object->GetPropertyNames( - context, v8::KeyCollectionMode::kOwnOnly, + context, KeyCollectionMode::kOwnOnly, filter, - v8::IndexFilter::kSkipIndices) + IndexFilter::kSkipIndices) .ToLocal(&properties)) { return; } @@ -96,7 +102,7 @@ static void PreviewEntries(const FunctionCallbackInfo& args) { return args.GetReturnValue().Set(entries); Local ret = Array::New(env->isolate(), 2); ret->Set(env->context(), 0, entries).FromJust(); - ret->Set(env->context(), 1, v8::Boolean::New(env->isolate(), is_key_value)) + ret->Set(env->context(), 1, Boolean::New(env->isolate(), is_key_value)) .FromJust(); return args.GetReturnValue().Set(ret); } @@ -171,7 +177,7 @@ void SafeGetenv(const FunctionCallbackInfo& args) { args.GetReturnValue() .Set(String::NewFromUtf8( args.GetIsolate(), text.c_str(), - v8::NewStringType::kNormal).ToLocalChecked()); + NewStringType::kNormal).ToLocalChecked()); } void EnqueueMicrotask(const FunctionCallbackInfo& args) { @@ -202,7 +208,7 @@ void Initialize(Local target, env->context(), OneByteString(env->isolate(), "pushValToArrayMax"), Integer::NewFromUnsigned(env->isolate(), NODE_PUSH_VAL_TO_ARRAY_MAX), - v8::ReadOnly).FromJust(); + ReadOnly).FromJust(); #define V(name) \ target->Set(context, \ diff --git a/src/util.cc b/src/util.cc index a0f0b0bf89657d..9f0b8ebc9d7596 100644 --- a/src/util.cc +++ b/src/util.cc @@ -102,7 +102,7 @@ BufferValue::BufferValue(Isolate* isolate, Local value) { void LowMemoryNotification() { if (v8_initialized) { - auto isolate = v8::Isolate::GetCurrent(); + auto isolate = Isolate::GetCurrent(); if (isolate != nullptr) { isolate->LowMemoryNotification(); } @@ -134,7 +134,7 @@ std::set ParseCommaSeparatedSet(const std::string& in) { return out; } -void ThrowErrStringTooLong(v8::Isolate* isolate) { +void ThrowErrStringTooLong(Isolate* isolate) { isolate->ThrowException(ERR_STRING_TOO_LONG(isolate)); } From 84e5807b1e4001ea9f9827d8adf4db12e7b60a6f Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sun, 28 Oct 2018 17:51:10 -0700 Subject: [PATCH 028/249] src: fix CreatePlatform header param mismatch PR-URL: https://github.com/nodejs/node/pull/23947 Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Ali Ijaz Sheikh Reviewed-By: Matheus Marchini --- src/node.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/node.h b/src/node.h index 98db32895295c3..5bbaa11def5c86 100644 --- a/src/node.h +++ b/src/node.h @@ -100,15 +100,16 @@ // Forward-declare libuv loop struct uv_loop_s; -// Forward-declare TracingController, used by CreatePlatform. -namespace v8 { -class TracingController; -} - // Forward-declare these functions now to stop MSVS from becoming // terminally confused when it's done in node_internals.h namespace node { +namespace tracing { + +class TracingController; + +} + NODE_EXTERN v8::Local ErrnoException(v8::Isolate* isolate, int errorno, const char* syscall = nullptr, @@ -275,7 +276,7 @@ NODE_EXTERN MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform(); NODE_EXTERN MultiIsolatePlatform* CreatePlatform( int thread_pool_size, - v8::TracingController* tracing_controller); + node::tracing::TracingController* tracing_controller); MultiIsolatePlatform* InitializeV8Platform(int thread_pool_size); NODE_EXTERN void FreePlatform(MultiIsolatePlatform* platform); From 23311814101de07f3bb2967e80086a35eaeeafe2 Mon Sep 17 00:00:00 2001 From: Benjamin Chen Date: Tue, 18 Sep 2018 01:28:41 -0400 Subject: [PATCH 029/249] vm: allow `cachedData` to also be TypedArray|DataView PR-URL: https://github.com/nodejs/node/pull/22921 Refs: https://github.com/nodejs/node/issues/1826 Refs: https://github.com/nodejs/node/pull/22921#issuecomment-422350213 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Denys Otrishko Reviewed-By: Refael Ackermann --- doc/api/vm.md | 13 +++++++------ lib/vm.js | 15 +++++++++------ src/node_contextify.cc | 14 +++++++------- test/parallel/test-vm-basic.js | 8 +++++--- test/parallel/test-vm-cached-data.js | 16 +++++++++------- 5 files changed, 37 insertions(+), 29 deletions(-) diff --git a/doc/api/vm.md b/doc/api/vm.md index c4b7e3f9b381ed..ae4daec7166eb6 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -434,10 +434,10 @@ changes: in stack traces produced by this script. * `columnOffset` {number} Specifies the column number offset that is displayed in stack traces produced by this script. - * `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache - data for the supplied source. When supplied, the `cachedDataRejected` value - will be set to either `true` or `false` depending on acceptance of the data - by V8. + * `cachedData` {Buffer|TypedArray|DataView} Provides an optional `Buffer` or + `TypedArray`, or `DataView` with V8's code cache data for the supplied + source. When supplied, the `cachedDataRejected` value will be set to + either `true` or `false` depending on acceptance of the data by V8. * `produceCachedData` {boolean} When `true` and no `cachedData` is present, V8 will attempt to produce code cache data for `code`. Upon success, a `Buffer` with V8's code cache data will be produced and stored in the @@ -669,8 +669,9 @@ added: v10.10.0 in stack traces produced by this script. **Default:** `0`. * `columnOffset` {number} Specifies the column number offset that is displayed in stack traces produced by this script. **Default:** `0`. - * `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache - data for the supplied source. + * `cachedData` {Buffer|TypedArray|DataView} Provides an optional `Buffer` or + `TypedArray`, or `DataView` with V8's code cache data for the supplied + source. * `produceCachedData` {boolean} Specifies whether to produce new cache data. **Default:** `false`. * `parsingContext` {Object} The [contextified][] sandbox in which the said diff --git a/lib/vm.js b/lib/vm.js index 1bb948fa550531..6e735bca4a76d9 100644 --- a/lib/vm.js +++ b/lib/vm.js @@ -32,7 +32,7 @@ const { ERR_INVALID_ARG_TYPE, ERR_VM_MODULE_NOT_MODULE, } = require('internal/errors').codes; -const { isModuleNamespaceObject, isUint8Array } = require('util').types; +const { isModuleNamespaceObject, isArrayBufferView } = require('util').types; const { validateInt32, validateUint32 } = require('internal/validators'); const kParsingContext = Symbol('script parsing context'); @@ -64,9 +64,12 @@ class Script extends ContextifyScript { } validateInt32(lineOffset, 'options.lineOffset'); validateInt32(columnOffset, 'options.columnOffset'); - if (cachedData !== undefined && !isUint8Array(cachedData)) { - throw new ERR_INVALID_ARG_TYPE('options.cachedData', - ['Buffer', 'Uint8Array'], cachedData); + if (cachedData !== undefined && !isArrayBufferView(cachedData)) { + throw new ERR_INVALID_ARG_TYPE( + 'options.cachedData', + ['Buffer', 'TypedArray', 'DataView'], + cachedData + ); } if (typeof produceCachedData !== 'boolean') { throw new ERR_INVALID_ARG_TYPE('options.produceCachedData', 'boolean', @@ -346,10 +349,10 @@ function compileFunction(code, params, options = {}) { } validateUint32(columnOffset, 'options.columnOffset'); validateUint32(lineOffset, 'options.lineOffset'); - if (cachedData !== undefined && !isUint8Array(cachedData)) { + if (cachedData !== undefined && !isArrayBufferView(cachedData)) { throw new ERR_INVALID_ARG_TYPE( 'options.cachedData', - 'Uint8Array', + ['Buffer', 'TypedArray', 'DataView'], cachedData ); } diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 3fbc616fda0284..79943f1ad6a7a4 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -33,6 +33,7 @@ namespace contextify { using v8::Array; using v8::ArrayBuffer; +using v8::ArrayBufferView; using v8::Boolean; using v8::Context; using v8::EscapableHandleScope; @@ -64,7 +65,6 @@ using v8::String; using v8::Symbol; using v8::TryCatch; using v8::Uint32; -using v8::Uint8Array; using v8::UnboundScript; using v8::Value; using v8::WeakCallbackInfo; @@ -629,7 +629,7 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { Local line_offset; Local column_offset; - Local cached_data_buf; + Local cached_data_buf; bool produce_cached_data = false; Local parsing_context = context; @@ -642,8 +642,8 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { CHECK(args[3]->IsNumber()); column_offset = args[3].As(); if (!args[4]->IsUndefined()) { - CHECK(args[4]->IsUint8Array()); - cached_data_buf = args[4].As(); + CHECK(args[4]->IsArrayBufferView()); + cached_data_buf = args[4].As(); } CHECK(args[5]->IsBoolean()); produce_cached_data = args[5]->IsTrue(); @@ -994,10 +994,10 @@ void ContextifyContext::CompileFunction( Local column_offset = args[3].As(); // Argument 5: cached data (optional) - Local cached_data_buf; + Local cached_data_buf; if (!args[4]->IsUndefined()) { - CHECK(args[4]->IsUint8Array()); - cached_data_buf = args[4].As(); + CHECK(args[4]->IsArrayBufferView()); + cached_data_buf = args[4].As(); } // Argument 6: produce cache data diff --git a/test/parallel/test-vm-basic.js b/test/parallel/test-vm-basic.js index 54b7c45ff8043a..df0c7df1062c14 100644 --- a/test/parallel/test-vm-basic.js +++ b/test/parallel/test-vm-basic.js @@ -178,18 +178,20 @@ const vm = require('vm'); 'filename': 'string', 'columnOffset': 'number', 'lineOffset': 'number', - 'cachedData': 'Uint8Array', + 'cachedData': 'Buffer, TypedArray, or DataView', 'produceCachedData': 'boolean', }; for (const option in optionTypes) { + const typeErrorMessage = `The "options.${option}" property must be ` + + `${option === 'cachedData' ? 'one of' : 'of'} type`; common.expectsError(() => { vm.compileFunction('', undefined, { [option]: null }); }, { type: TypeError, code: 'ERR_INVALID_ARG_TYPE', - message: `The "options.${option}" property must be of type ` + - `${optionTypes[option]}. Received type object` + message: typeErrorMessage + + ` ${optionTypes[option]}. Received type object` }); } diff --git a/test/parallel/test-vm-cached-data.js b/test/parallel/test-vm-cached-data.js index e3947d1ae6c166..1b14999cdbc2f7 100644 --- a/test/parallel/test-vm-cached-data.js +++ b/test/parallel/test-vm-cached-data.js @@ -41,12 +41,14 @@ function testProduceConsume() { const data = produce(source); - // It should consume code cache - const script = new vm.Script(source, { - cachedData: data - }); - assert(!script.cachedDataRejected); - assert.strictEqual(script.runInThisContext()(), 'original'); + for (const cachedData of common.getArrayBufferViews(data)) { + // It should consume code cache + const script = new vm.Script(source, { + cachedData + }); + assert(!script.cachedDataRejected); + assert.strictEqual(script.runInThisContext()(), 'original'); + } } testProduceConsume(); @@ -91,5 +93,5 @@ common.expectsError(() => { }, { code: 'ERR_INVALID_ARG_TYPE', type: TypeError, - message: /must be one of type Buffer or Uint8Array/ + message: /must be one of type Buffer, TypedArray, or DataView/ }); From b3f3ebf3b35f8872f59f5926f5cb80362182cbcb Mon Sep 17 00:00:00 2001 From: Anto Aravinth Date: Thu, 1 Nov 2018 22:16:01 +0530 Subject: [PATCH 030/249] lib: repl multiline history support PR-URL: https://github.com/nodejs/node/pull/22153 Reviewed-By: John-David Dalton Reviewed-By: James M Snell --- lib/readline.js | 25 +++++++++++++++++++ lib/repl.js | 2 ++ test/parallel/test-repl-persistent-history.js | 7 ++++++ 3 files changed, 34 insertions(+) diff --git a/lib/readline.js b/lib/readline.js index 4eeefb227ca746..f22d84f1a0df77 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -217,6 +217,7 @@ function Interface(input, output, completer, terminal) { // Current line this.line = ''; + this.multiline = ''; this._setRawMode(true); this.terminal = true; @@ -327,6 +328,7 @@ Interface.prototype._addHistory = function() { if (dupIndex !== -1) this.history.splice(dupIndex, 1); } + this.multiline += this.line; this.history.unshift(this.line); // Only store so many @@ -337,6 +339,29 @@ Interface.prototype._addHistory = function() { return this.history[0]; }; +// Called when a multiline is seen by the repl +Interface.prototype.undoHistory = function() { + if (this.terminal) { + this.history.shift(); + } +}; + +// If it's a multiline code, then add history +// accordingly. +Interface.prototype.multilineHistory = function() { + // check if we got a multiline code + if (this.multiline !== '' && this.terminal) { + const dupIndex = this.history.indexOf(this.multiline); + if (dupIndex !== -1) this.history.splice(dupIndex, 1); + // Remove the last entered line as multiline + // already contains them. + this.history.shift(); + this.history.unshift(this.multiline); + } + + // clear the multiline buffer + this.multiline = ''; +}; Interface.prototype._refreshLine = function() { // line length diff --git a/lib/repl.js b/lib/repl.js index dafbd20d500383..2ecb5abaa4005c 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -779,6 +779,7 @@ exports.start = function(prompt, REPLServer.prototype.clearBufferedCommand = function clearBufferedCommand() { this[kBufferedCommandSymbol] = ''; + REPLServer.super_.prototype.multilineHistory.call(this); }; REPLServer.prototype.close = function close() { @@ -893,6 +894,7 @@ REPLServer.prototype.displayPrompt = function(preserveCursor) { const len = this.lines.level.length ? this.lines.level.length - 1 : 0; const levelInd = '..'.repeat(len); prompt += levelInd + ' '; + REPLServer.super_.prototype.undoHistory.call(this); } // Do not overwrite `_initialPrompt` here diff --git a/test/parallel/test-repl-persistent-history.js b/test/parallel/test-repl-persistent-history.js index bb10085eccfcf6..32bab3c8ed9f83 100644 --- a/test/parallel/test-repl-persistent-history.js +++ b/test/parallel/test-repl-persistent-history.js @@ -111,6 +111,13 @@ const tests = [ test: [UP], expected: [prompt, replFailedRead, prompt, replDisabled, prompt] }, + { // Tests multiline history + env: {}, + test: ['{', '}', UP, CLEAR], + expected: [prompt, '{', '... ', '}', '{}\n', + prompt, `${prompt}{}`, prompt], + clean: false + }, { before: function before() { if (common.isWindows) { From d729f3e1982cbc2b2506102cf4e54a8604341776 Mon Sep 17 00:00:00 2001 From: Gerhard Stoebich Date: Wed, 31 Oct 2018 15:45:07 +0100 Subject: [PATCH 031/249] doc: correct async_hooks resource names Correct async hooks resource names to match the implementation: `FSREQWRAP` => `FSREQCALLBACK` `TCPSERVER` => `TCPSERVERWRAP` PR-URL: https://github.com/nodejs/node/pull/24001 Refs: https://github.com/nodejs/node/pull/21971 Refs: https://github.com/nodejs/node/pull/17157 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- doc/api/async_hooks.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 0e061a9a238615..b99c5fee718865 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -63,7 +63,7 @@ function init(asyncId, type, triggerAsyncId, resource) { } // before is called just before the resource's callback is called. It can be // called 0-N times for handles (e.g. TCPWrap), and will be called exactly 1 -// time for requests (e.g. FSReqWrap). +// time for requests (e.g. FSReqCallback). function before(asyncId) { } // after is called just after the resource's callback has finished. @@ -236,9 +236,9 @@ The `type` is a string identifying the type of resource that caused resource's constructor. ```text -FSEVENTWRAP, FSREQWRAP, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER, +FSEVENTWRAP, FSREQCALLBACK, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER, JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP, SHUTDOWNWRAP, -SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVER, TCPWRAP, TTYWRAP, +SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVERWRAP, TCPWRAP, TTYWRAP, UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST, RANDOMBYTESREQUEST, TLSWRAP, Microtask, Timeout, Immediate, TickObject ``` From a1b75d0cbfe140a0a906e948ed4607151c8cb5f2 Mon Sep 17 00:00:00 2001 From: Ivan Filenko Date: Fri, 2 Nov 2018 00:15:48 +0300 Subject: [PATCH 032/249] doc: fix dublication in net.createServer() docs PR-URL: https://github.com/nodejs/node/pull/24026 Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca --- doc/api/net.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/api/net.md b/doc/api/net.md index eb48ab8d00c87f..a8cd321dca968d 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -886,6 +886,7 @@ added: v0.7.0 --> * `options` {Object} * `connectListener` {Function} + Alias to [`net.createConnection(options[, connectListener])`][`net.createConnection(options)`]. @@ -1028,10 +1029,6 @@ then returns the `net.Socket` that starts the connection. -* `options` {Object} -* `connectionListener` {Function} - -Creates a new TCP or [IPC][] server. * `options` {Object} * `allowHalfOpen` {boolean} Indicates whether half-opened TCP @@ -1042,6 +1039,8 @@ Creates a new TCP or [IPC][] server. [`'connection'`][] event. * Returns: {net.Server} +Creates a new TCP or [IPC][] server. + If `allowHalfOpen` is set to `true`, when the other end of the socket sends a FIN packet, the server will only send a FIN packet back when [`socket.end()`][] is explicitly called, until then the connection is From 6e4f23834400b42c0579bf840800003f61f54d19 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Fri, 26 Oct 2018 08:29:04 -0400 Subject: [PATCH 033/249] deps,v8: cherry-pick dc704497 Original commit message: undef min,max macros on windows This blocks building with official clang-cl and Windows SDK Refs: https://github.com/nodejs/node/issues/19630 Change-Id: I41fdf934f486c660df7a9e0dd284f6eb3c294dd4 Reviewed-on: https://chromium-review.googlesource.com/c/1297479 Commit-Queue: Jakob Gruber Reviewed-by: Jakob Gruber Cr-Commit-Position: refs/heads/master@{#57053} PR-URL: https://github.com/nodejs/node/pull/23985 Refs: https://github.com/v8/v8/commit/dc704497ee84245931533c3575dd250d4b498300 Reviewed-By: Richard Lau Reviewed-By: Ben Noordhuis Reviewed-By: Colin Ihrig --- common.gypi | 2 +- deps/v8/src/base/debug/stack_trace_win.cc | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/common.gypi b/common.gypi index 779073a635bebe..e3758393c0b654 100644 --- a/common.gypi +++ b/common.gypi @@ -30,7 +30,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.8', + 'v8_embedder_string': '-node.9', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/deps/v8/src/base/debug/stack_trace_win.cc b/deps/v8/src/base/debug/stack_trace_win.cc index 6b221312332411..3fe66d97ada531 100644 --- a/deps/v8/src/base/debug/stack_trace_win.cc +++ b/deps/v8/src/base/debug/stack_trace_win.cc @@ -7,6 +7,13 @@ #include "src/base/debug/stack_trace.h" +// This file can't use "src/base/win32-headers.h" because it defines symbols +// that lead to compilation errors. But `NOMINMAX` should be defined to disable +// defining of the `min` and `max` MACROS. +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include #include #include From b86a89b9ad1609b92d75534ed571572add33d43a Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 31 Oct 2018 12:09:18 +0100 Subject: [PATCH 034/249] test: increase --stack_size test-async-wrap-pop Currently, when building with --debug test-async-wrap-pop-id-during-load fails on macosx with the following error: $ out/Debug/node test/parallel/test-async-wrap-pop-id-during-load.js assert.js:86 throw new AssertionError(obj); ^ AssertionError [ERR_ASSERTION]: EXIT CODE: 1, STDERR: internal/bootstrap/loaders.js:275 const script = new ContextifyScript( ^ RangeError: Maximum call stack size exceeded at NativeModule.compile (internal/bootstrap/loaders.js:275:22) at NativeModule.require (internal/bootstrap/loaders.js:168:18) at assert.js:31:43 at NativeModule.compile (internal/bootstrap/loaders.js:299:7) at NativeModule.require (internal/bootstrap/loaders.js:168:18) at internal/process/main_thread_only.js:23:16 at NativeModule.compile (internal/bootstrap/loaders.js:299:7) at Function.NativeModule.require (internal/bootstrap/loaders.js:168:18) at startup (internal/bootstrap/node.js:58:38) at bootstrapNodeJSCore (internal/bootstrap/node.js:878:3) at Object. (/node/test/parallel/test-async-wrap-pop-id-during-load.js:21:8) at Module._compile (internal/modules/cjs/loader.js:707:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:718:10) at Module.load (internal/modules/cjs/loader.js:605:32) at tryModuleLoad (internal/modules/cjs/loader.js:544:12) at Function.Module._load (internal/modules/cjs/loader.js:536:3) at Function.Module.runMain (internal/modules/cjs/loader.js:760:12) at startup (internal/bootstrap/node.js:308:19) at bootstrapNodeJSCore (internal/bootstrap/node.js:878:3) This commit suggests increasing the stack_size to 80. Refs: https://github.com/nodejs/node/pull/20940 PR-URL: https://github.com/nodejs/node/pull/23996 Reviewed-By: James M Snell Reviewed-By: Rich Trott --- test/parallel/test-async-wrap-pop-id-during-load.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-async-wrap-pop-id-during-load.js b/test/parallel/test-async-wrap-pop-id-during-load.js index 31d2113eabc163..cff7e85fdffef4 100644 --- a/test/parallel/test-async-wrap-pop-id-during-load.js +++ b/test/parallel/test-async-wrap-pop-id-during-load.js @@ -16,7 +16,7 @@ const { spawnSync } = require('child_process'); const ret = spawnSync( process.execPath, - ['--stack_size=75', __filename, 'async'] + ['--stack_size=150', __filename, 'async'] ); assert.strictEqual(ret.status, 0, `EXIT CODE: ${ret.status}, STDERR:\n${ret.stderr}`); From fdba226d131ca2c153ded371a333809eda04f239 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 31 Oct 2018 07:48:59 +0100 Subject: [PATCH 035/249] src: fix compiler warning for debug build This commit updates the check of the offset argument passed to CallJSOnreadMethod to avoid doing a cast as this currently generates the following compiler warning when doing a debug build: ./src/stream_base.cc:295:3: warning: comparison of integers of different signs: 'int32_t' (aka 'int') and 'size_t' (aka 'unsigned long') [-Wsign-compare] CHECK_EQ(static_cast(offset), offset); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ PR-URL: https://github.com/nodejs/node/pull/23994 Reviewed-By: Anna Henningsen Reviewed-By: Matheus Marchini Reviewed-By: Luigi Pinca Reviewed-By: Ujjwal Sharma Reviewed-By: Joyee Cheung Reviewed-By: James M Snell --- src/stream_base.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stream_base.cc b/src/stream_base.cc index adb839c3e5d633..670b3cbd5091d1 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -292,7 +292,7 @@ void StreamBase::CallJSOnreadMethod(ssize_t nread, #ifdef DEBUG CHECK_EQ(static_cast(nread), nread); - CHECK_EQ(static_cast(offset), offset); + CHECK_LE(offset, INT32_MAX); if (ab.IsEmpty()) { CHECK_EQ(offset, 0); From 7ee0cea0283b6e18d81e509d5ed809647fb6f09c Mon Sep 17 00:00:00 2001 From: Benjamin Date: Sat, 3 Nov 2018 15:42:13 -0700 Subject: [PATCH 036/249] lib: make coverage work for Node.js PR-URL: https://github.com/nodejs/node/pull/23941 Reviewed-By: James M Snell Reviewed-By: Yang Guo --- lib/internal/bootstrap/loaders.js | 6 ++ lib/internal/bootstrap/node.js | 4 +- lib/internal/process/coverage.js | 90 +++++++++++++++-------- test/fixtures/v8-coverage/async-hooks.js | 11 +++ test/parallel/test-heapdump-inspector.js | 47 ++++++++---- test/parallel/test-v8-coverage.js | 14 ++++ test/sequential/test-inspector-enabled.js | 5 +- 7 files changed, 129 insertions(+), 48 deletions(-) create mode 100644 test/fixtures/v8-coverage/async-hooks.js diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index dff6ce661a4640..aceb15cc63fc69 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -362,6 +362,12 @@ NativeModule._cache[this.id] = this; }; + // coverage must be turned on early, so that we can collect + // it for Node.js' own internal libraries. + if (process.env.NODE_V8_COVERAGE) { + NativeModule.require('internal/process/coverage').setup(); + } + // This will be passed to the bootstrapNodeJSCore function in // bootstrap/node.js. return loaderExports; diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 1ba427a572e3f7..6b5f1f7f8e561c 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -103,9 +103,7 @@ NativeModule.require('internal/process/write-coverage').setup(); if (process.env.NODE_V8_COVERAGE) { - const { resolve } = NativeModule.require('path'); - process.env.NODE_V8_COVERAGE = resolve(process.env.NODE_V8_COVERAGE); - NativeModule.require('internal/process/coverage').setup(); + NativeModule.require('internal/process/coverage').setupExitHooks(); } if (process.config.variables.v8_enable_inspector) { diff --git a/lib/internal/process/coverage.js b/lib/internal/process/coverage.js index df45285baaee02..9c9b2b47119ea7 100644 --- a/lib/internal/process/coverage.js +++ b/lib/internal/process/coverage.js @@ -1,23 +1,19 @@ 'use strict'; -const path = require('path'); -const { mkdirSync, writeFileSync } = require('fs'); -const hasInspector = process.config.variables.v8_enable_inspector === 1; -let inspector = null; -if (hasInspector) inspector = require('inspector'); - -let session; +let coverageConnection = null; +let coverageDirectory; function writeCoverage() { - if (!session) { + if (!coverageConnection && coverageDirectory) { return; } + const { join } = require('path'); + const { mkdirSync, writeFileSync } = require('fs'); const { threadId } = require('internal/worker'); const filename = `coverage-${process.pid}-${Date.now()}-${threadId}.json`; try { - // TODO(bcoe): switch to mkdirp once #22302 is addressed. - mkdirSync(process.env.NODE_V8_COVERAGE); + mkdirSync(coverageDirectory, { recursive: true }); } catch (err) { if (err.code !== 'EEXIST') { console.error(err); @@ -25,41 +21,73 @@ function writeCoverage() { } } - const target = path.join(process.env.NODE_V8_COVERAGE, filename); - + const target = join(coverageDirectory, filename); try { - session.post('Profiler.takePreciseCoverage', (err, coverageInfo) => { - if (err) return console.error(err); - try { - writeFileSync(target, JSON.stringify(coverageInfo)); - } catch (err) { - console.error(err); - } - }); + disableAllAsyncHooks(); + let msg; + coverageConnection._coverageCallback = function(_msg) { + msg = _msg; + }; + coverageConnection.dispatch(JSON.stringify({ + id: 3, + method: 'Profiler.takePreciseCoverage' + })); + const coverageInfo = JSON.parse(msg).result; + writeFileSync(target, JSON.stringify(coverageInfo)); } catch (err) { console.error(err); } finally { - session.disconnect(); - session = null; + coverageConnection.disconnect(); + coverageConnection = null; } } +function disableAllAsyncHooks() { + const { getHookArrays } = require('internal/async_hooks'); + const [hooks_array] = getHookArrays(); + hooks_array.forEach((hook) => { hook.disable(); }); +} + exports.writeCoverage = writeCoverage; function setup() { - if (!hasInspector) { - console.warn('coverage currently only supported in main thread'); + const { Connection } = process.binding('inspector'); + if (!Connection) { + console.warn('inspector not enabled'); return; } - session = new inspector.Session(); - session.connect(); - session.post('Profiler.enable'); - session.post('Profiler.startPreciseCoverage', { callCount: true, - detailed: true }); + coverageConnection = new Connection((res) => { + if (coverageConnection._coverageCallback) { + coverageConnection._coverageCallback(res); + } + }); + coverageConnection.dispatch(JSON.stringify({ + id: 1, + method: 'Profiler.enable' + })); + coverageConnection.dispatch(JSON.stringify({ + id: 2, + method: 'Profiler.startPreciseCoverage', + params: { + callCount: true, + detailed: true + } + })); - const reallyReallyExit = process.reallyExit; + try { + const { resolve } = require('path'); + coverageDirectory = process.env.NODE_V8_COVERAGE = + resolve(process.env.NODE_V8_COVERAGE); + } catch (err) { + console.error(err); + } +} +exports.setup = setup; + +function setupExitHooks() { + const reallyReallyExit = process.reallyExit; process.reallyExit = function(code) { writeCoverage(); reallyReallyExit(code); @@ -68,4 +96,4 @@ function setup() { process.on('exit', writeCoverage); } -exports.setup = setup; +exports.setupExitHooks = setupExitHooks; diff --git a/test/fixtures/v8-coverage/async-hooks.js b/test/fixtures/v8-coverage/async-hooks.js new file mode 100644 index 00000000000000..855f41ed3b3449 --- /dev/null +++ b/test/fixtures/v8-coverage/async-hooks.js @@ -0,0 +1,11 @@ +const async_hooks = require('async_hooks'); +const common = require('../../common'); + +const hook = async_hooks.createHook({ + init: common.mustNotCall(), + before: common.mustNotCall(), + after: common.mustNotCall(), + destroy: common.mustNotCall() +}); + +hook.enable(); diff --git a/test/parallel/test-heapdump-inspector.js b/test/parallel/test-heapdump-inspector.js index 3d031d87eb1a99..963b85ac3a029a 100644 --- a/test/parallel/test-heapdump-inspector.js +++ b/test/parallel/test-heapdump-inspector.js @@ -7,17 +7,38 @@ common.skipIfInspectorDisabled(); const { validateSnapshotNodes } = require('../common/heap'); const inspector = require('inspector'); -const session = new inspector.Session(); -validateSnapshotNodes('Node / JSBindingsConnection', []); -session.connect(); -validateSnapshotNodes('Node / JSBindingsConnection', [ - { - children: [ - { node_name: 'Node / InspectorSession', edge_name: 'session' }, - { node_name: 'Connection', edge_name: 'wrapped' }, - (edge) => edge.name === 'callback' && - (edge.to.type === undefined || // embedded graph - edge.to.type === 'closure') // snapshot - ] +const snapshotNode = { + children: [ + { node_name: 'Node / InspectorSession', edge_name: 'session' } + ] +}; + +// starts with no JSBindingsConnection (or 1 if coverage enabled). +{ + const expected = []; + if (process.env.NODE_V8_COVERAGE) { + expected.push(snapshotNode); + } + validateSnapshotNodes('Node / JSBindingsConnection', expected); +} + +// JSBindingsConnection should be added. +{ + const session = new inspector.Session(); + session.connect(); + const expected = [ + { + children: [ + { node_name: 'Node / InspectorSession', edge_name: 'session' }, + { node_name: 'Connection', edge_name: 'wrapped' }, + (edge) => edge.name === 'callback' && + (edge.to.type === undefined || // embedded graph + edge.to.type === 'closure') // snapshot + ] + } + ]; + if (process.env.NODE_V8_COVERAGE) { + expected.push(snapshotNode); } -]); + validateSnapshotNodes('Node / JSBindingsConnection', expected); +} diff --git a/test/parallel/test-v8-coverage.js b/test/parallel/test-v8-coverage.js index 16a55b0fc4b8e8..191835fe0f5af9 100644 --- a/test/parallel/test-v8-coverage.js +++ b/test/parallel/test-v8-coverage.js @@ -108,6 +108,20 @@ function nextdir() { assert.strictEqual(fixtureCoverage, undefined); } +// disables async hooks before writing coverage. +{ + const coverageDirectory = path.join(tmpdir.path, nextdir()); + const output = spawnSync(process.execPath, [ + require.resolve('../fixtures/v8-coverage/async-hooks') + ], { env: { ...process.env, NODE_V8_COVERAGE: coverageDirectory } }); + assert.strictEqual(output.status, 0); + const fixtureCoverage = getFixtureCoverage('async-hooks.js', + coverageDirectory); + assert.ok(fixtureCoverage); + // first branch executed. + assert.strictEqual(fixtureCoverage.functions[1].ranges[0].count, 1); +} + // extracts the coverage object for a given fixture name. function getFixtureCoverage(fixtureFile, coverageDirectory) { const coverageFiles = fs.readdirSync(coverageDirectory); diff --git a/test/sequential/test-inspector-enabled.js b/test/sequential/test-inspector-enabled.js index a7a0832793283c..f14e7c17d817c5 100644 --- a/test/sequential/test-inspector-enabled.js +++ b/test/sequential/test-inspector-enabled.js @@ -20,7 +20,10 @@ assert( `; const args = ['--inspect', '-e', script]; -const child = spawn(process.execPath, args, { stdio: 'inherit' }); +const child = spawn(process.execPath, args, { + stdio: 'inherit', + env: { ...process.env, NODE_V8_COVERAGE: '' } +}); child.on('exit', (code, signal) => { process.exit(code || signal); }); From 424be28840c7ceb10a5f1f552114053087e734f2 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 1 Nov 2018 18:04:57 +0800 Subject: [PATCH 037/249] fs: handle result of access binding directly in fs.existsSync Instead of throwing errors in fs.accessSync and then catching it, handle the result from the binding directly in fs.existsSync. Note that the argument validation errors still needs to be caught until we properly deprecate the don't-thrown-on-invalid-arguments behavior. PR-URL: https://github.com/nodejs/node/pull/24015 Fixes: https://github.com/nodejs/node/issues/24008 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Refael Ackermann --- lib/fs.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 89c005375f450e..dba9049faec111 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -228,11 +228,14 @@ Object.defineProperty(exists, internalUtil.promisify.custom, { // TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior function existsSync(path) { try { - fs.accessSync(path, F_OK); - return true; + path = toPathIfFileURL(path); + validatePath(path); } catch (e) { return false; } + const ctx = { path }; + binding.access(pathModule.toNamespacedPath(path), F_OK, undefined, ctx); + return ctx.errno === undefined; } function readFileAfterOpen(err, fd) { From 874393bfd0691cfc86ec531de1990ed50a2a6e8f Mon Sep 17 00:00:00 2001 From: ZYSzys <17367077526@163.com> Date: Wed, 31 Oct 2018 18:30:35 +0800 Subject: [PATCH 038/249] lib: remove useless getLibuvNow in internal/timers PR-URL: https://github.com/nodejs/node/pull/23995 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Matheus Marchini Reviewed-By: Luigi Pinca Reviewed-By: Ujjwal Sharma --- lib/internal/timers.js | 3 +-- test/parallel/test-timers-now.js | 3 ++- test/parallel/test-timers-ordering.js | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/internal/timers.js b/lib/internal/timers.js index 5c96b38ee6e00d..3bfa1f03775fe1 100644 --- a/lib/internal/timers.js +++ b/lib/internal/timers.js @@ -32,8 +32,7 @@ module.exports = { kRefed, initAsyncResource, setUnrefTimeout, - validateTimerDuration, - getLibuvNow: internalBinding('timers').getLibuvNow, + validateTimerDuration }; var timers; diff --git a/test/parallel/test-timers-now.js b/test/parallel/test-timers-now.js index bd8faaa6c732cc..91b3f63496da2b 100644 --- a/test/parallel/test-timers-now.js +++ b/test/parallel/test-timers-now.js @@ -3,7 +3,8 @@ require('../common'); const assert = require('assert'); -const { getLibuvNow } = require('internal/timers'); +const { internalBinding } = require('internal/test/binding'); +const { getLibuvNow } = internalBinding('timers'); // Return value of getLibuvNow() should easily fit in a SMI after start-up. assert(getLibuvNow() < 0x3ffffff); diff --git a/test/parallel/test-timers-ordering.js b/test/parallel/test-timers-ordering.js index d9629e03190679..e163ea55bf2dd8 100644 --- a/test/parallel/test-timers-ordering.js +++ b/test/parallel/test-timers-ordering.js @@ -24,7 +24,8 @@ 'use strict'; require('../common'); const assert = require('assert'); -const { getLibuvNow } = require('internal/timers'); +const { internalBinding } = require('internal/test/binding'); +const { getLibuvNow } = internalBinding('timers'); const N = 30; From 72204d114f1a7b58f5fc430e64bb79c27391b0da Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 31 Oct 2018 15:41:32 +0100 Subject: [PATCH 039/249] n-api: add missing handle scopes Currently when building with --debug test/addons-napi/test_threadsafe_function will error: $ out/Debug/node test/addons-napi/test_threadsafe_function/test.js FATAL ERROR: v8::HandleScope::CreateHandle() Cannot create a handle without a HandleScope 1: 0x10004e287 node::DumpBacktrace(__sFILE*) [node/out/Debug/node] 2: 0x1000cd37b node::Abort() [/node/out/Debug/node] 3: 0x1000cd69f node::OnFatalError(char const*, char const*) [/node/out/Debug/node] 4: 0x1004df0b1 v8::Utils::ReportApiFailure(char const*, char const*) [/nodejs/node/out/Debug/node] 5: 0x100a8c0a9 v8::internal::HandleScope::Extend( v8::internal::Isolate*) [/node/out/Debug/node] 6: 0x1004e4229 v8::EmbedderDataFor(v8::Context*, int, bool, char const*) [/node/out/Debug/node] 7: 0x1004e43fa v8::Context::SlowGetAlignedPointerFromEmbedderData(int) [/node/out/Debug/node] 8: 0x10001c26b v8::Context::GetAlignedPointerFromEmbedderData(int) [/node/out/Debug/node] 9: 0x1000144ea node::Environment::GetCurrent(v8::Local) [/node/out/Debug/node] 10: 0x1000f49e2 napi_env__::node_env() const [/node/out/Debug/node] 11: 0x1000f9885 (anonymous namespace)::v8impl::ThreadSafeFunction:: CloseHandlesAndMaybeDelete(bool) [/node/out/Debug/node] 12: 0x1000fb34f (anonymous namespace)::v8impl::ThreadSafeFunction:: DispatchOne() [/node/out/Debug/node] 13: 0x1000fb129 (anonymous namespace)::v8impl::ThreadSafeFunction:: IdleCb(uv_idle_s*) [/node/out/Debug/node] 14: 0x1011a1b69 uv__run_idle [/node/out/Debug/node] 15: 0x101198179 uv_run [/node/out/Debug/node] 16: 0x1000dfca1 node::Start(...) [/node/out/Debug/node] 17: 0x1000dae50 node::Start(...) [/node/out/Debug/node] 18: 0x1000da56f node::Start(int, char**) [/node/out/Debug/node] 19: 0x10141112e main [/node/out/Debug/node] 20: 0x100001034 start [/node/out/Debug/node] Abort trap: 6 This commit adds two HandleScope's, one to CloseHandlesAndMaybeDelete and one to the lambda. SlowGetAlignedPointerFromEmbedderData will only be called for debug builds: https://github.com/v8/v8/blob/2ef0aa662fe907a1b36ac1abe7d77ad2bcd27733 /include/v8.h#L10440-L10447 PR-URL: https://github.com/nodejs/node/pull/24011 Reviewed-By: James M Snell Reviewed-By: Michael Dawson --- src/node_api.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/node_api.cc b/src/node_api.cc index c92175c75fea0a..1f7b1405539e7b 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -1084,6 +1084,7 @@ class ThreadSafeFunction : public node::AsyncResource { } void CloseHandlesAndMaybeDelete(bool set_closing = false) { + v8::HandleScope scope(env->isolate); if (set_closing) { node::Mutex::ScopedLock lock(this->mutex); is_closing = true; @@ -1101,6 +1102,7 @@ class ThreadSafeFunction : public node::AsyncResource { ThreadSafeFunction* ts_fn = node::ContainerOf(&ThreadSafeFunction::async, reinterpret_cast(handle)); + v8::HandleScope scope(ts_fn->env->isolate); ts_fn->env->node_env()->CloseHandle( reinterpret_cast(&ts_fn->idle), [](uv_handle_t* handle) -> void { From df1ca0fd828ca5ab81a854e3f4361e95afb5922f Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Wed, 31 Oct 2018 09:41:10 -0500 Subject: [PATCH 040/249] win: clarify Boxstarter behavior on install tools Clarify the behavior of what Boxstarter may do when it runs on a box to install all the necessary tools so that there are no surprises to the end user when the script is run. Currently there is no interface that warns the user that Boxstarter will reboot the machine possibly multiple times depending on how many dependencies need to be installed and doesn't mention a need to disable UAC. For folks who see what may look like a reboot loop, we feel it is necessary to make them aware that UAC will be disabled and they will need to take action to re-enable UAC manually if they interfere/stop the script from finishing. PR-URL: https://github.com/nodejs/node/pull/23987 Fixes: https://github.com/nodejs/Release/issues/369 Reviewed-By: John-David Dalton Reviewed-By: Refael Ackermann Reviewed-By: Richard Lau --- tools/msvs/install_tools/install_tools.bat | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/msvs/install_tools/install_tools.bat b/tools/msvs/install_tools/install_tools.bat index db10cf1f46049e..1585b5b7c96e04 100644 --- a/tools/msvs/install_tools/install_tools.bat +++ b/tools/msvs/install_tools/install_tools.bat @@ -47,7 +47,23 @@ echo script is at your own risk. Please read the Chocolatey's legal terms of use echo and the Boxstarter project license as well as how the community repository echo for Chocolatey.org is maintained. echo. -echo You can close this window to stop now. +pause + +cls +echo !!!!!WARNING!!!!! +echo ----------------- +echo Use of Boxstarter may reboot your computer automatically multiple times. +echo When performing a reboot, Boxstarter will need to disable User Account +echo Control (UAC) to allow the script to run immediately after the reboot. When +echo the scripts have completed, Boxstarter will re-enable UAC. If you prematurely +echo stop the process, UAC will need to be re-enabled manually. +echo. +echo Sometimes the scripts may install all necessary Windows Updates which +echo could cause a high number of reboots that appear to be a reboot loop when +echo in fact it is just a normal Windows Updates reboot cycle. +echo. +echo If this is not what you would like to occur, you can close this window +echo to stop now. pause "%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command Start-Process '%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe' -ArgumentList '-NoProfile -InputFormat None -ExecutionPolicy Bypass -Command iex ((New-Object System.Net.WebClient).DownloadString(''https://boxstarter.org/bootstrapper.ps1'')); get-boxstarter -Force; Install-BoxstarterPackage -PackageName ''%~dp0\install_tools.txt''; Read-Host ''Type ENTER to exit'' ' -Verb RunAs From 57a2b957deaee0886d85a47909facb5432218056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Reis?= Date: Wed, 31 Oct 2018 00:52:35 +0000 Subject: [PATCH 041/249] win: add prompt to tools installation script Fixes: https://github.com/nodejs/Release/issues/369 PR-URL: https://github.com/nodejs/node/pull/23987 Reviewed-By: John-David Dalton Reviewed-By: Refael Ackermann Reviewed-By: Richard Lau --- tools/msvs/install_tools/install_tools.bat | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tools/msvs/install_tools/install_tools.bat b/tools/msvs/install_tools/install_tools.bat index 1585b5b7c96e04..36456fa6f656a9 100644 --- a/tools/msvs/install_tools/install_tools.bat +++ b/tools/msvs/install_tools/install_tools.bat @@ -1,5 +1,7 @@ @echo off +setlocal + cls echo ==================================================== echo Tools for Node.js Native Modules Installation Script @@ -61,9 +63,14 @@ echo. echo Sometimes the scripts may install all necessary Windows Updates which echo could cause a high number of reboots that appear to be a reboot loop when echo in fact it is just a normal Windows Updates reboot cycle. +:acceptretry echo. -echo If this is not what you would like to occur, you can close this window -echo to stop now. -pause +echo Your computer may REBOOT SEVERAL TIMES WITHOUT FURTHER WARNING. +echo Please type YES followed by enter to confirm that you have saved all your +set /p "ACCEPT_PROMPT=work and closed all open programs: " +if /i not "%ACCEPT_PROMPT%"=="yes" ( + echo Please type YES to confirm, or close the window to exit. + goto acceptretry +) "%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command Start-Process '%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe' -ArgumentList '-NoProfile -InputFormat None -ExecutionPolicy Bypass -Command iex ((New-Object System.Net.WebClient).DownloadString(''https://boxstarter.org/bootstrapper.ps1'')); get-boxstarter -Force; Install-BoxstarterPackage -PackageName ''%~dp0\install_tools.txt''; Read-Host ''Type ENTER to exit'' ' -Verb RunAs From c7f471ab9769a4f8090aeb759bdb994bf273bc13 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 30 Oct 2018 16:17:33 -0700 Subject: [PATCH 042/249] http2: improve http2 code a bit Multiple general improvements to http2 internals for readability and efficiency PR-URL: https://github.com/nodejs/node/pull/23984 Reviewed-By: Anna Henningsen Reviewed-By: Trivikram Kamat Reviewed-By: Ujjwal Sharma Reviewed-By: Matteo Collina --- benchmark/http2/headers.js | 3 +- benchmark/http2/respond-with-fd.js | 6 +- benchmark/http2/simple.js | 6 +- lib/internal/http2/util.js | 44 ++-- src/node_http2.cc | 347 +++++++++++++++-------------- 5 files changed, 212 insertions(+), 194 deletions(-) diff --git a/benchmark/http2/headers.js b/benchmark/http2/headers.js index e2fad2ea02a0ee..f18a73b95e2421 100644 --- a/benchmark/http2/headers.js +++ b/benchmark/http2/headers.js @@ -39,8 +39,7 @@ function main({ n, nheaders }) { function doRequest(remaining) { const req = client.request(headersObject); - req.end(); - req.on('data', () => {}); + req.resume(); req.on('end', () => { if (remaining > 0) { doRequest(remaining - 1); diff --git a/benchmark/http2/respond-with-fd.js b/benchmark/http2/respond-with-fd.js index 3415a9c69f13ec..35856490f7e4a2 100644 --- a/benchmark/http2/respond-with-fd.js +++ b/benchmark/http2/respond-with-fd.js @@ -7,9 +7,9 @@ const fs = require('fs'); const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); const bench = common.createBenchmark(main, { - requests: [100, 1000, 10000, 100000], - streams: [100, 200, 1000], - clients: [1, 2], + requests: [100, 1000, 5000], + streams: [1, 10, 20, 40, 100, 200], + clients: [2], benchmarker: ['h2load'] }, { flags: ['--no-warnings'] }); diff --git a/benchmark/http2/simple.js b/benchmark/http2/simple.js index f4598b81560230..aab7c6b609b715 100644 --- a/benchmark/http2/simple.js +++ b/benchmark/http2/simple.js @@ -6,9 +6,9 @@ const fs = require('fs'); const file = path.join(path.resolve(__dirname, '../fixtures'), 'alice.html'); const bench = common.createBenchmark(main, { - requests: [100, 1000, 10000, 100000], - streams: [100, 200, 1000], - clients: [1, 2], + requests: [100, 1000, 5000], + streams: [1, 10, 20, 40, 100, 200], + clients: [2], benchmarker: ['h2load'] }, { flags: ['--no-warnings'] }); diff --git a/lib/internal/http2/util.js b/lib/internal/http2/util.js index 94dc1198ea1060..c8701af616f327 100644 --- a/lib/internal/http2/util.js +++ b/lib/internal/http2/util.js @@ -430,14 +430,20 @@ function mapToHeaders(map, let count = 0; const keys = Object.keys(map); const singles = new Set(); - for (var i = 0; i < keys.length; i++) { - let key = keys[i]; - let value = map[key]; + let i; + let isArray; + let key; + let value; + let isSingleValueHeader; + let err; + for (i = 0; i < keys.length; i++) { + key = keys[i]; + value = map[key]; if (value === undefined || key === '') continue; key = key.toLowerCase(); - const isSingleValueHeader = kSingleValueHeaders.has(key); - let isArray = Array.isArray(value); + isSingleValueHeader = kSingleValueHeaders.has(key); + isArray = Array.isArray(value); if (isArray) { switch (value.length) { case 0: @@ -459,26 +465,26 @@ function mapToHeaders(map, singles.add(key); } if (key[0] === ':') { - const err = assertValuePseudoHeader(key); + err = assertValuePseudoHeader(key); if (err !== undefined) return err; ret = `${key}\0${value}\0${ret}`; count++; - } else { - if (isIllegalConnectionSpecificHeader(key, value)) { - return new ERR_HTTP2_INVALID_CONNECTION_HEADERS(key); - } - if (isArray) { - for (var k = 0; k < value.length; k++) { - const val = String(value[k]); - ret += `${key}\0${val}\0`; - } - count += value.length; - } else { - ret += `${key}\0${value}\0`; - count++; + continue; + } + if (isIllegalConnectionSpecificHeader(key, value)) { + return new ERR_HTTP2_INVALID_CONNECTION_HEADERS(key); + } + if (isArray) { + for (var k = 0; k < value.length; k++) { + const val = String(value[k]); + ret += `${key}\0${val}\0`; } + count += value.length; + continue; } + ret += `${key}\0${value}\0`; + count++; } return [ret, count]; diff --git a/src/node_http2.cc b/src/node_http2.cc index a77f123d32a0bf..95f3f4a8f7c1d2 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -911,8 +911,10 @@ int Http2Session::OnBeginHeadersCallback(nghttp2_session* handle, Debug(session, "beginning headers for stream %d", id); Http2Stream* stream = session->FindStream(id); - if (stream == nullptr) { - if (!session->CanAddStream()) { + // The common case is that we're creating a new stream. The less likely + // case is that we're receiving a set of trailers + if (LIKELY(stream == nullptr)) { + if (UNLIKELY(!session->CanAddStream())) { // Too many concurrent streams being opened nghttp2_submit_rst_stream(**session, NGHTTP2_FLAG_NONE, id, NGHTTP2_ENHANCE_YOUR_CALM); @@ -940,7 +942,7 @@ int Http2Session::OnHeaderCallback(nghttp2_session* handle, // If stream is null at this point, either something odd has happened // or the stream was closed locally while header processing was occurring. // either way, do not proceed and close the stream. - if (stream == nullptr) + if (UNLIKELY(stream == nullptr)) return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; // If the stream has already been destroyed, ignore. @@ -955,7 +957,7 @@ int Http2Session::OnHeaderCallback(nghttp2_session* handle, // Called by nghttp2 when a complete HTTP2 frame has been received. There are -// only a handful of frame types tha we care about handling here. +// only a handful of frame types that we care about handling here. int Http2Session::OnFrameReceive(nghttp2_session* handle, const nghttp2_frame* frame, void* user_data) { @@ -1032,22 +1034,25 @@ int Http2Session::OnFrameNotSent(nghttp2_session* handle, Environment* env = session->env(); Debug(session, "frame type %d was not sent, code: %d", frame->hd.type, error_code); - // Do not report if the frame was not sent due to the session closing - if (error_code != NGHTTP2_ERR_SESSION_CLOSING && - error_code != NGHTTP2_ERR_STREAM_CLOSED && - error_code != NGHTTP2_ERR_STREAM_CLOSING) { - Isolate* isolate = env->isolate(); - HandleScope scope(isolate); - Local context = env->context(); - Context::Scope context_scope(context); - Local argv[3] = { - Integer::New(isolate, frame->hd.stream_id), - Integer::New(isolate, frame->hd.type), - Integer::New(isolate, error_code) - }; - session->MakeCallback(env->onframeerror_string(), arraysize(argv), argv); + // Do not report if the frame was not sent due to the session closing + if (error_code == NGHTTP2_ERR_SESSION_CLOSING || + error_code == NGHTTP2_ERR_STREAM_CLOSED || + error_code == NGHTTP2_ERR_STREAM_CLOSING) { + return 0; } + + Isolate* isolate = env->isolate(); + HandleScope scope(isolate); + Local context = env->context(); + Context::Scope context_scope(context); + + Local argv[3] = { + Integer::New(isolate, frame->hd.stream_id), + Integer::New(isolate, frame->hd.type), + Integer::New(isolate, error_code) + }; + session->MakeCallback(env->onframeerror_string(), arraysize(argv), argv); return 0; } @@ -1074,25 +1079,26 @@ int Http2Session::OnStreamClose(nghttp2_session* handle, Http2Stream* stream = session->FindStream(id); // Intentionally ignore the callback if the stream does not exist or has // already been destroyed - if (stream != nullptr && !stream->IsDestroyed()) { - stream->Close(code); - // It is possible for the stream close to occur before the stream is - // ever passed on to the javascript side. If that happens, skip straight - // to destroying the stream. We can check this by looking for the - // onstreamclose function. If it exists, then the stream has already - // been passed on to javascript. - Local fn = - stream->object()->Get(context, env->onstreamclose_string()) - .ToLocalChecked(); - if (fn->IsFunction()) { - Local argv[] = { - Integer::NewFromUnsigned(isolate, code) - }; - stream->MakeCallback(fn.As(), arraysize(argv), argv); - } else { - stream->Destroy(); - } + if (stream == nullptr || stream->IsDestroyed()) + return 0; + + stream->Close(code); + // It is possible for the stream close to occur before the stream is + // ever passed on to the javascript side. If that happens, skip straight + // to destroying the stream. We can check this by looking for the + // onstreamclose function. If it exists, then the stream has already + // been passed on to javascript. + Local fn = + stream->object()->Get(context, env->onstreamclose_string()) + .ToLocalChecked(); + + if (!fn->IsFunction()) { + stream->Destroy(); + return 0; } + + Local arg = Integer::NewFromUnsigned(isolate, code); + stream->MakeCallback(fn.As(), 1, &arg); return 0; } @@ -1125,53 +1131,56 @@ int Http2Session::OnDataChunkReceived(nghttp2_session* handle, "%d, flags: %d", id, len, flags); Environment* env = session->env(); HandleScope scope(env->isolate()); + // We should never actually get a 0-length chunk so this check is // only a precaution at this point. - if (len > 0) { - // Notify nghttp2 that we've consumed a chunk of data on the connection - // so that it can send a WINDOW_UPDATE frame. This is a critical part of - // the flow control process in http2 - CHECK_EQ(nghttp2_session_consume_connection(handle, len), 0); - Http2Stream* stream = session->FindStream(id); - // If the stream has been destroyed, ignore this chunk - if (stream->IsDestroyed()) - return 0; - - stream->statistics_.received_bytes += len; - - // Repeatedly ask the stream's owner for memory, and copy the read data - // into those buffers. - // The typical case is actually the exception here; Http2StreamListeners - // know about the HTTP2 session associated with this stream, so they know - // about the larger from-socket read buffer, so they do not require copying. - do { - uv_buf_t buf = stream->EmitAlloc(len); - ssize_t avail = len; - if (static_cast(buf.len) < avail) - avail = buf.len; - - // `buf.base == nullptr` is the default Http2StreamListener's way - // of saying that it wants a pointer to the raw original. - // Since it has access to the original socket buffer from which the data - // was read in the first place, it can use that to minimize ArrayBuffer - // allocations. - if (LIKELY(buf.base == nullptr)) - buf.base = reinterpret_cast(const_cast(data)); - else - memcpy(buf.base, data, avail); - data += avail; - len -= avail; - stream->EmitRead(avail, buf); - - // If the stream owner (e.g. the JS Http2Stream) wants more data, just - // tell nghttp2 that all data has been consumed. Otherwise, defer until - // more data is being requested. - if (stream->IsReading()) - nghttp2_session_consume_stream(handle, id, avail); - else - stream->inbound_consumed_data_while_paused_ += avail; - } while (len != 0); - } + if (len == 0) + return 0; + + // Notify nghttp2 that we've consumed a chunk of data on the connection + // so that it can send a WINDOW_UPDATE frame. This is a critical part of + // the flow control process in http2 + CHECK_EQ(nghttp2_session_consume_connection(handle, len), 0); + Http2Stream* stream = session->FindStream(id); + // If the stream has been destroyed, ignore this chunk + if (stream->IsDestroyed()) + return 0; + + stream->statistics_.received_bytes += len; + + // Repeatedly ask the stream's owner for memory, and copy the read data + // into those buffers. + // The typical case is actually the exception here; Http2StreamListeners + // know about the HTTP2 session associated with this stream, so they know + // about the larger from-socket read buffer, so they do not require copying. + do { + uv_buf_t buf = stream->EmitAlloc(len); + ssize_t avail = len; + if (static_cast(buf.len) < avail) + avail = buf.len; + + // `buf.base == nullptr` is the default Http2StreamListener's way + // of saying that it wants a pointer to the raw original. + // Since it has access to the original socket buffer from which the data + // was read in the first place, it can use that to minimize ArrayBuffer + // allocations. + if (LIKELY(buf.base == nullptr)) + buf.base = reinterpret_cast(const_cast(data)); + else + memcpy(buf.base, data, avail); + data += avail; + len -= avail; + stream->EmitRead(avail, buf); + + // If the stream owner (e.g. the JS Http2Stream) wants more data, just + // tell nghttp2 that all data has been consumed. Otherwise, defer until + // more data is being requested. + if (stream->IsReading()) + nghttp2_session_consume_stream(handle, id, avail); + else + stream->inbound_consumed_data_while_paused_ += avail; + } while (len != 0); + return 0; } @@ -1430,7 +1439,7 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) { nghttp2_extension ext = frame->ext; nghttp2_ext_origin* origin = static_cast(ext.payload); - Local holder = Array::New(isolate); + Local holder = Array::New(isolate); Local fn = env()->push_values_to_array_function(); Local argv[NODE_PUSH_VAL_TO_ARRAY_MAX]; @@ -1449,9 +1458,7 @@ void Http2Session::HandleOriginFrame(const nghttp2_frame* frame) { fn->Call(context, holder, j, argv).ToLocalChecked(); } - Local args[1] = { holder }; - - MakeCallback(env()->onorigin_string(), arraysize(args), args); + MakeCallback(env()->onorigin_string(), 1, &holder); } // Called by OnFrameReceived when a complete PING frame has been received. @@ -1464,9 +1471,8 @@ void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK; if (ack) { Http2Ping* ping = PopPing(); - if (ping != nullptr) { - ping->Done(true, frame->ping.opaque_data); - } else { + + if (ping == nullptr) { // PING Ack is unsolicited. Treat as a connection error. The HTTP/2 // spec does not require this, but there is no legitimate reason to // receive an unsolicited PING ack on a connection. Either the peer @@ -1474,46 +1480,51 @@ void Http2Session::HandlePingFrame(const nghttp2_frame* frame) { // nonsense. arg = Integer::New(isolate, NGHTTP2_ERR_PROTO); MakeCallback(env()->error_string(), 1, &arg); + return; } - } else { - // Notify the session that a ping occurred - arg = Buffer::Copy(env(), - reinterpret_cast(frame->ping.opaque_data), - 8).ToLocalChecked(); - MakeCallback(env()->onping_string(), 1, &arg); + + ping->Done(true, frame->ping.opaque_data); + return; } + + // Notify the session that a ping occurred + arg = Buffer::Copy(env(), + reinterpret_cast(frame->ping.opaque_data), + 8).ToLocalChecked(); + MakeCallback(env()->onping_string(), 1, &arg); } // Called by OnFrameReceived when a complete SETTINGS frame has been received. void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) { bool ack = frame->hd.flags & NGHTTP2_FLAG_ACK; - if (ack) { - // If this is an acknowledgement, we should have an Http2Settings - // object for it. - Http2Settings* settings = PopSettings(); - if (settings != nullptr) { - settings->Done(true); - } else { - // SETTINGS Ack is unsolicited. Treat as a connection error. The HTTP/2 - // spec does not require this, but there is no legitimate reason to - // receive an unsolicited SETTINGS ack on a connection. Either the peer - // is buggy or malicious, and we're not going to tolerate such - // nonsense. - // Note that nghttp2 currently prevents this from happening for SETTINGS - // frames, so this block is purely defensive just in case that behavior - // changes. Specifically, unlike unsolicited PING acks, unsolicited - // SETTINGS acks should *never* make it this far. - Isolate* isolate = env()->isolate(); - HandleScope scope(isolate); - Local context = env()->context(); - Context::Scope context_scope(context); - Local arg = Integer::New(isolate, NGHTTP2_ERR_PROTO); - MakeCallback(env()->error_string(), 1, &arg); - } - } else { - // Otherwise, notify the session about a new settings + if (!ack) { + // This is not a SETTINGS acknowledgement, notify and return MakeCallback(env()->onsettings_string(), 0, nullptr); + return; } + + // If this is an acknowledgement, we should have an Http2Settings + // object for it. + Http2Settings* settings = PopSettings(); + if (settings != nullptr) { + settings->Done(true); + return; + } + // SETTINGS Ack is unsolicited. Treat as a connection error. The HTTP/2 + // spec does not require this, but there is no legitimate reason to + // receive an unsolicited SETTINGS ack on a connection. Either the peer + // is buggy or malicious, and we're not going to tolerate such + // nonsense. + // Note that nghttp2 currently prevents this from happening for SETTINGS + // frames, so this block is purely defensive just in case that behavior + // changes. Specifically, unlike unsolicited PING acks, unsolicited + // SETTINGS acks should *never* make it this far. + Isolate* isolate = env()->isolate(); + HandleScope scope(isolate); + Local context = env()->context(); + Context::Scope context_scope(context); + Local arg = Integer::New(isolate, NGHTTP2_ERR_PROTO); + MakeCallback(env()->error_string(), 1, &arg); } // Callback used when data has been written to the stream. @@ -1535,7 +1546,10 @@ void Http2Session::OnStreamAfterWrite(WriteWrap* w, int status) { // queue), but only if a write has not already been scheduled. void Http2Session::MaybeScheduleWrite() { CHECK_EQ(flags_ & SESSION_STATE_WRITE_SCHEDULED, 0); - if (session_ != nullptr && nghttp2_session_want_write(session_)) { + if (UNLIKELY(session_ == nullptr)) + return; + + if (nghttp2_session_want_write(session_)) { HandleScope handle_scope(env()->isolate()); Debug(this, "scheduling write"); flags_ |= SESSION_STATE_WRITE_SCHEDULED; @@ -1594,7 +1608,7 @@ void Http2Session::ClearOutgoing(int status) { for (int32_t stream_id : current_pending_rst_streams) { Http2Stream* stream = FindStream(stream_id); - if (stream != nullptr) + if (LIKELY(stream != nullptr)) stream->FlushRstStream(); } } @@ -1769,7 +1783,7 @@ Http2Stream* Http2Session::SubmitRequest( Http2Stream::Provider::Stream prov(options); *ret = nghttp2_submit_request(session_, prispec, nva, len, *prov, nullptr); CHECK_NE(*ret, NGHTTP2_ERR_NOMEM); - if (*ret > 0) + if (LIKELY(*ret > 0)) stream = new Http2Stream(this, *ret, NGHTTP2_HCAT_HEADERS, options); return stream; } @@ -1784,59 +1798,58 @@ void Http2Session::OnStreamRead(ssize_t nread, const uv_buf_t& buf) { IncrementCurrentSessionMemory(buf.len); CHECK(stream_buf_ab_.IsEmpty()); + OnScopeLeave on_scope_leave([&]() { + // Once finished handling this write, reset the stream buffer. + // The memory has either been free()d or was handed over to V8. + DecrementCurrentSessionMemory(buf.len); + stream_buf_ab_ = Local(); + stream_buf_ = uv_buf_init(nullptr, 0); + }); + + // Only pass data on if nread > 0 if (nread <= 0) { free(buf.base); if (nread < 0) { PassReadErrorToPreviousListener(nread); } - } else { - // Only pass data on if nread > 0 - - // Makre sure that there was no read previously active. - CHECK_NULL(stream_buf_.base); - CHECK_EQ(stream_buf_.len, 0); - - // Remember the current buffer, so that OnDataChunkReceived knows the - // offset of a DATA frame's data into the socket read buffer. - stream_buf_ = uv_buf_init(buf.base, nread); - - // Verify that currently: There is memory allocated into which - // the data has been read, and that memory buffer is at least as large - // as the amount of data we have read, but we have not yet made an - // ArrayBuffer out of it. - CHECK_LE(static_cast(nread), stream_buf_.len); - - Isolate* isolate = env()->isolate(); - - // Create an array buffer for the read data. DATA frames will be emitted - // as slices of this array buffer to avoid having to copy memory. - stream_buf_ab_ = - ArrayBuffer::New(isolate, - buf.base, - nread, - v8::ArrayBufferCreationMode::kInternalized); - - statistics_.data_received += nread; - ssize_t ret = Write(&stream_buf_, 1); - - if (ret < 0) { - Debug(this, "fatal error receiving data: %d", ret); - - Local argv[] = { - Integer::New(isolate, ret), - }; - MakeCallback(env()->error_string(), arraysize(argv), argv); - } else { - MaybeStopReading(); - } + return; } - // Since we are finished handling this write, reset the stream buffer. - // The memory has either been free()d or was handed over to V8. - DecrementCurrentSessionMemory(buf.len); + // Make sure that there was no read previously active. + CHECK_NULL(stream_buf_.base); + CHECK_EQ(stream_buf_.len, 0); + + // Remember the current buffer, so that OnDataChunkReceived knows the + // offset of a DATA frame's data into the socket read buffer. + stream_buf_ = uv_buf_init(buf.base, nread); + + // Verify that currently: There is memory allocated into which + // the data has been read, and that memory buffer is at least as large + // as the amount of data we have read, but we have not yet made an + // ArrayBuffer out of it. + CHECK_LE(static_cast(nread), stream_buf_.len); + + Isolate* isolate = env()->isolate(); - stream_buf_ab_ = Local(); - stream_buf_ = uv_buf_init(nullptr, 0); + // Create an array buffer for the read data. DATA frames will be emitted + // as slices of this array buffer to avoid having to copy memory. + stream_buf_ab_ = + ArrayBuffer::New(isolate, + buf.base, + nread, + v8::ArrayBufferCreationMode::kInternalized); + + statistics_.data_received += nread; + ssize_t ret = Write(&stream_buf_, 1); + + if (UNLIKELY(ret < 0)) { + Debug(this, "fatal error receiving data: %d", ret); + Local arg = Integer::New(isolate, ret); + MakeCallback(env()->error_string(), 1, &arg); + return; + } + + MaybeStopReading(); } bool Http2Session::HasWritesOnSocketForStream(Http2Stream* stream) { From e27f43201c02dc73074bb6c1c5cf7e9ef57e8374 Mon Sep 17 00:00:00 2001 From: Weijia Wang Date: Tue, 30 Oct 2018 16:33:00 +0800 Subject: [PATCH 043/249] repl: use promise#finally PR-URL: https://github.com/nodejs/node/pull/23971 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat --- lib/repl.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 2ecb5abaa4005c..75750ca1cd6295 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -376,18 +376,8 @@ function REPLServer(prompt, } promise.then((result) => { - // Remove prioritized SIGINT listener if it was not called. - // TODO(TimothyGu): Use Promise.prototype.finally when it becomes - // available. - prioritizedSigintQueue.delete(sigintListener); - finishExecution(undefined, result); - unpause(); }, (err) => { - // Remove prioritized SIGINT listener if it was not called. - prioritizedSigintQueue.delete(sigintListener); - - unpause(); if (err && process.domain) { debug('not recoverable, send to domain'); process.domain.emit('error', err); @@ -395,6 +385,10 @@ function REPLServer(prompt, return; } finishExecution(err); + }).finally(() => { + // Remove prioritized SIGINT listener if it was not called. + prioritizedSigintQueue.delete(sigintListener); + unpause(); }); } } From e4cd255a8583fe1b4044673708e7ea0c88e82b4c Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 28 Oct 2018 15:59:20 +0100 Subject: [PATCH 044/249] buffer: throw exception when creating from non-Node.js Context Throw an exception instead of crashing when attempting to create `Buffer` objects from a Context that is not associated with a Node.js `Environment`. Possible alternatives for the future might be just returning a plain `Uint8Array`, or working on providing `Buffer` for all `Context`s. PR-URL: https://github.com/nodejs/node/pull/23938 Reviewed-By: James M Snell Reviewed-By: Daniel Bevenius --- doc/api/errors.md | 13 +++++++++++ src/node_buffer.cc | 22 +++++++++++++++---- src/node_errors.h | 3 +++ test/addons/non-node-context/binding.cc | 21 ++++++++++++------ .../non-node-context/test-make-buffer.js | 22 +++++++++++++++++++ 5 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 test/addons/non-node-context/test-make-buffer.js diff --git a/doc/api/errors.md b/doc/api/errors.md index bdabc48a7ddd72..aecb5282e79808 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -613,6 +613,19 @@ An attempt was made to register something that is not a function as an The type of an asynchronous resource was invalid. Note that users are also able to define their own types if using the public embedder API. + +### ERR_BUFFER_CONTEXT_NOT_AVAILABLE + +An attempt was made to create a Node.js `Buffer` instance from addon or embedder +code, while in a JS engine Context that is not associated with a Node.js +instance. The data passed to the `Buffer` method will have been released +by the time the method returns. + +When encountering this error, a possible alternative to creating a `Buffer` +instance is to create a normal `Uint8Array`, which only differs in the +prototype of the resulting object. `Uint8Array`s are generally accepted in all +Node.js core APIs where `Buffer`s are; they are available in all Contexts. + ### ERR_BUFFER_OUT_OF_BOUNDS diff --git a/src/node_buffer.cc b/src/node_buffer.cc index d4f7c751634b4d..2a2fb45e7abf15 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -271,7 +271,10 @@ MaybeLocal New(Isolate* isolate, size_t length) { EscapableHandleScope handle_scope(isolate); Local obj; Environment* env = Environment::GetCurrent(isolate); - CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here. + if (env == nullptr) { + THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate); + return MaybeLocal(); + } if (Buffer::New(env, length).ToLocal(&obj)) return handle_scope.Escape(obj); return Local(); @@ -314,7 +317,10 @@ MaybeLocal New(Environment* env, size_t length) { MaybeLocal Copy(Isolate* isolate, const char* data, size_t length) { EscapableHandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); - CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here. + if (env == nullptr) { + THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate); + return MaybeLocal(); + } Local obj; if (Buffer::Copy(env, data, length).ToLocal(&obj)) return handle_scope.Escape(obj); @@ -364,7 +370,11 @@ MaybeLocal New(Isolate* isolate, void* hint) { EscapableHandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); - CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here. + if (env == nullptr) { + callback(data, hint); + THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate); + return MaybeLocal(); + } Local obj; if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj)) return handle_scope.Escape(obj); @@ -403,7 +413,11 @@ MaybeLocal New(Environment* env, MaybeLocal New(Isolate* isolate, char* data, size_t length) { EscapableHandleScope handle_scope(isolate); Environment* env = Environment::GetCurrent(isolate); - CHECK_NOT_NULL(env); // TODO(addaleax): Handle nullptr here. + if (env == nullptr) { + free(data); + THROW_ERR_BUFFER_CONTEXT_NOT_AVAILABLE(isolate); + return MaybeLocal(); + } Local obj; if (Buffer::New(env, data, length).ToLocal(&obj)) return handle_scope.Escape(obj); diff --git a/src/node_errors.h b/src/node_errors.h index a958eccf8af4b9..a435695693ba18 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -21,6 +21,7 @@ namespace node { // a `Local` containing the TypeError with proper code and message #define ERRORS_WITH_CODE(V) \ + V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, Error) \ V(ERR_BUFFER_OUT_OF_BOUNDS, RangeError) \ V(ERR_BUFFER_TOO_LARGE, Error) \ V(ERR_CANNOT_TRANSFER_OBJECT, TypeError) \ @@ -64,6 +65,8 @@ namespace node { // Errors with predefined static messages #define PREDEFINED_ERROR_MESSAGES(V) \ + V(ERR_BUFFER_CONTEXT_NOT_AVAILABLE, \ + "Buffer is not available for the current Context") \ V(ERR_CANNOT_TRANSFER_OBJECT, "Cannot transfer object of unsupported type")\ V(ERR_CLOSED_MESSAGE_PORT, "Cannot send data on closed MessagePort") \ V(ERR_CONSTRUCT_CALL_REQUIRED, "Cannot call constructor without `new`") \ diff --git a/test/addons/non-node-context/binding.cc b/test/addons/non-node-context/binding.cc index 324f5c5a1ef16f..776786cef5180f 100644 --- a/test/addons/non-node-context/binding.cc +++ b/test/addons/non-node-context/binding.cc @@ -1,4 +1,5 @@ #include +#include #include namespace { @@ -15,6 +16,17 @@ using v8::Script; using v8::String; using v8::Value; +inline void MakeBufferInNewContext( + const v8::FunctionCallbackInfo& args) { + Isolate* isolate = args.GetIsolate(); + Local context = Context::New(isolate); + Context::Scope context_scope(context); + + // This should throw an exception, rather than actually do anything. + MaybeLocal buf = node::Buffer::Copy(isolate, "foo", 3); + assert(buf.IsEmpty()); +} + inline void RunInNewContext( const v8::FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); @@ -41,13 +53,8 @@ inline void RunInNewContext( inline void Initialize(Local exports, Local module, Local context) { - Isolate* isolate = context->GetIsolate(); - Local key = String::NewFromUtf8( - isolate, "runInNewContext", NewStringType::kNormal).ToLocalChecked(); - Local value = FunctionTemplate::New(isolate, RunInNewContext) - ->GetFunction(context) - .ToLocalChecked(); - assert(exports->Set(context, key, value).IsJust()); + NODE_SET_METHOD(exports, "runInNewContext", RunInNewContext); + NODE_SET_METHOD(exports, "makeBufferInNewContext", MakeBufferInNewContext); } } // anonymous namespace diff --git a/test/addons/non-node-context/test-make-buffer.js b/test/addons/non-node-context/test-make-buffer.js new file mode 100644 index 00000000000000..9b17fa4ee930ae --- /dev/null +++ b/test/addons/non-node-context/test-make-buffer.js @@ -0,0 +1,22 @@ +'use strict'; + +const common = require('../../common'); +const assert = require('assert'); +const { + makeBufferInNewContext +} = require(`./build/${common.buildType}/binding`); + +// Because the `Buffer` function and its protoype property only (currently) +// exist in a Node.js instance’s main context, trying to create buffers from +// another context throws an exception. + +try { + makeBufferInNewContext(); +} catch (exception) { + assert.strictEqual(exception.constructor.name, 'Error'); + assert(!(exception.constructor instanceof Error)); + + assert.strictEqual(exception.code, 'ERR_BUFFER_CONTEXT_NOT_AVAILABLE'); + assert.strictEqual(exception.message, + 'Buffer is not available for the current Context'); +} From e8078f269351393bb6c1d21202c0d6bfcad8e8a4 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 1 Nov 2018 20:41:10 -0700 Subject: [PATCH 045/249] doc: edit man page for superfluous "node" usage Rather than ponder "node" vs. "Node.js", remove the descriptor so it's just "command-line options" rather than "node command-line options" or "Node.js command-line options". PR-URL: https://github.com/nodejs/node/pull/24029 Reviewed-By: Vse Mozhet Byt Reviewed-By: Richard Lau Reviewed-By: Gus Caplan Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- doc/node.1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/node.1 b/doc/node.1 index 397b40ed71e3f4..b8144f4ebb5f6c 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -66,7 +66,7 @@ Alias for stdin, analogous to the use of - in other command-line utilities. The executed script is read from stdin, and remaining arguments are passed to the script. . .It Fl - -Indicate the end of node options. +Indicate the end of command-line options. Pass the rest of the arguments to the script. .Pp If no script filename or eval/print script is supplied prior to this, then @@ -246,7 +246,7 @@ Evaluate as JavaScript. . .It Fl h , Fl -help -Print Node.js command line options. +Print command-line options. The output of this option is less detailed than this document. . .It Fl i , Fl -interactive From fa84164de4e5f3d411306673bb9ca898ad4d3277 Mon Sep 17 00:00:00 2001 From: warnerp18 Date: Thu, 1 Nov 2018 21:24:54 -0700 Subject: [PATCH 046/249] doc: add SECURITY.md to readme.md This adds a SECURITY.md file and links to the security document per the request of @https://github.com/Trott at a recent SF Node meetup. PR-URL: https://github.com/nodejs/node/pull/24031 Reviewed-By: Rich Trott Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca --- README.md | 39 ++------------------------------------- SECURITY.md | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 SECURITY.md diff --git a/README.md b/README.md index 671e5321450c7e..a4a93612c1036d 100644 --- a/README.md +++ b/README.md @@ -159,43 +159,8 @@ source and a list of supported platforms. ## Security -If you find a security vulnerability in Node.js, please report it to -security@nodejs.org. Please withhold public disclosure until after the security -team has addressed the vulnerability. - -The security team will acknowledge your email within 24 hours. You will receive -a more detailed response within 48 hours. - -There are no hard and fast rules to determine if a bug is worth reporting as a -security issue. Here are some examples of past issues and what the Security -Response Team thinks of them. When in doubt, please do send us a report -nonetheless. - - -### Public disclosure preferred - -- [#14519](https://github.com/nodejs/node/issues/14519): _Internal domain - function can be used to cause segfaults_. Requires the ability to execute - arbitrary JavaScript code. That is already the highest level of privilege - possible. - -### Private disclosure preferred - -- [CVE-2016-7099](https://nodejs.org/en/blog/vulnerability/september-2016-security-releases/): - _Fix invalid wildcard certificate validation check_. This was a high-severity - defect. It caused Node.js TLS clients to accept invalid wildcard certificates. - -- [#5507](https://github.com/nodejs/node/pull/5507): _Fix a defect that makes - the CacheBleed Attack possible_. Many, though not all, OpenSSL vulnerabilities - in the TLS/SSL protocols also affect Node.js. - -- [CVE-2016-2216](https://nodejs.org/en/blog/vulnerability/february-2016-security-releases/): - _Fix defects in HTTP header parsing for requests and responses that can allow - response splitting_. This was a remotely-exploitable defect in the Node.js - HTTP implementation. - -When in doubt, please do send us a report. - +For information on reporting security vulnerabilities in Node.js, see +[SECURITY.md](./SECURITY.md). ## Current Project Team Members diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000000..5f1e3e2cc7d563 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,37 @@ +# Security + +If you find a security vulnerability in Node.js, please report it to +security@nodejs.org. Please withhold public disclosure until after the security +team has addressed the vulnerability. + +The security team will acknowledge your email within 24 hours. You will receive +a more detailed response within 48 hours. + +There are no hard and fast rules to determine if a bug is worth reporting as a +security issue. Here are some examples of past issues and what the Security +Response Team thinks of them. When in doubt, please do send us a report +nonetheless. + +## Public disclosure preferred + +- [#14519](https://github.com/nodejs/node/issues/14519): _Internal domain + function can be used to cause segfaults_. Requires the ability to execute + arbitrary JavaScript code. That is already the highest level of privilege + possible. + +## Private disclosure preferred + +- [CVE-2016-7099](https://nodejs.org/en/blog/vulnerability/september-2016-security-releases/): + _Fix invalid wildcard certificate validation check_. This was a high-severity + defect. It caused Node.js TLS clients to accept invalid wildcard certificates. + +- [#5507](https://github.com/nodejs/node/pull/5507): _Fix a defect that makes + the CacheBleed Attack possible_. Many, though not all, OpenSSL vulnerabilities + in the TLS/SSL protocols also affect Node.js. + +- [CVE-2016-2216](https://nodejs.org/en/blog/vulnerability/february-2016-security-releases/): + _Fix defects in HTTP header parsing for requests and responses that can allow + response splitting_. This was a remotely-exploitable defect in the Node.js + HTTP implementation. + +When in doubt, please do send us a report. From 94f73942ed25126ec925e356c6fea54d5b626532 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 3 Nov 2018 19:51:54 +0100 Subject: [PATCH 047/249] doc: fix socket.connecting description In particular, this value is `true` and not `false` between calling `connect()` and the operation finishing. PR-URL: https://github.com/nodejs/node/pull/24066 Reviewed-By: Joyee Cheung Reviewed-By: Luigi Pinca Reviewed-By: Rich Trott --- doc/api/net.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/net.md b/doc/api/net.md index a8cd321dca968d..1b495da81c3f56 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -658,9 +658,9 @@ called with `{port: port, host: host}` as `options`. added: v6.1.0 --> -If `true` - +If `true`, [`socket.connect(options[, connectListener])`][`socket.connect(options)`] -was called and haven't yet finished. Will be set to `false` before emitting +was called and has not yet finished. Will be set to `true` before emitting `'connect'` event and/or calling [`socket.connect(options[, connectListener])`][`socket.connect(options)`]'s callback. From 1541c7f40196b1a33745095d54dca47608340240 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Thu, 1 Nov 2018 23:55:19 -0400 Subject: [PATCH 048/249] tools: add script to lint first PR commit message Decouple first commit in pull request linting from Travis by using the GitHub API to work out the first commit. The shell script obtains the pull request number in one of the following ways: 1) supplied on the command line (use this to test against any PR) 2) derived from the HEAD commit via the GitHub API PR-URL: https://github.com/nodejs/node/pull/24030 Reviewed-By: Refael Ackermann Reviewed-By: Rich Trott --- .travis.yml | 2 +- tools/lint-pr-commit-message.sh | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tools/lint-pr-commit-message.sh diff --git a/.travis.yml b/.travis.yml index 21ec6dab70f994..dce15b7ab16851 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ matrix: script: - make lint # Lint the first commit in the PR. - - \[ -z "$TRAVIS_COMMIT_RANGE" \] || (echo -e '\nLinting the commit message according to the guidelines at https://goo.gl/p2fr5Q\n' && git log $TRAVIS_COMMIT_RANGE --pretty=format:'%h' --no-merges | tail -1 | xargs npx -q core-validate-commit --no-validate-metadata) + - \[ "${TRAVIS_PULL_REQUEST}" != "false" \] && PR_ID=${TRAVIS_PULL_REQUEST}; bash tools/lint-pr-commit-message.sh ${PR_ID} - name: "Test Suite" addons: apt: diff --git a/tools/lint-pr-commit-message.sh b/tools/lint-pr-commit-message.sh new file mode 100644 index 00000000000000..1998026a16ae39 --- /dev/null +++ b/tools/lint-pr-commit-message.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +# Shell script to lint the message of the first commit in a pull request. +# +# Depends on curl, git, node, npm and npx being in $PATH. +# +# The pull request is either: +# 1) supplied as an argument to this shell script +# 2) derived from the HEAD commit via the GitHub API + +GH_API_URL="https://api.github.com" +PR_ID=$1; +if [ -z "${PR_ID}" ]; then + # Attempt to work out the PR number based on current HEAD + if HEAD_COMMIT="$( git rev-parse HEAD )"; then + if SEARCH_RESULTS="$( curl -s ${GH_API_URL}/search/issues?q=sha:${HEAD_COMMIT}+type:pr+repo:nodejs/node )"; then + if FOUND_PR="$( node -p 'JSON.parse(process.argv[1]).items[0].number' "${SEARCH_RESULTS}" 2> /dev/null )"; then + PR_ID=${FOUND_PR} + fi + fi + fi +fi +if [ -z "${PR_ID}" ]; then + echo "Unable to determine the pull request number to check. Please specify, " + echo " e.g. $0 " + exit 1 +fi +# Retrieve the first commit of the pull request via GitHub API +# TODO: If we teach core-validate-commit to ignore "fixup!" and "squash!" +# commits and lint messages for all commits in the pull request +# we could simplify the following to: +# npx -q core-validate-commit --no-validate-metadata ${GH_API_URL}/repos/nodejs/node/pulls/${PR_ID}/commits +if PR_COMMITS="$( curl -s ${GH_API_URL}/repos/nodejs/node/pulls/${PR_ID}/commits )"; then + if FIRST_COMMIT="$( node -p 'JSON.parse(process.argv[1])[0].url' "${PR_COMMITS}" 2> /dev/null )"; then + echo "Linting the first commit message for pull request ${PR_ID}" + echo "according to the guidelines at https://goo.gl/p2fr5Q." + # Print the commit message to make it more obvious what is being checked. + echo "Commit message for ${FIRST_COMMIT##*/} is:" + node -p 'JSON.parse(process.argv[1])[0].commit.message' "${PR_COMMITS}" 2> /dev/null + npx -q core-validate-commit --no-validate-metadata "${FIRST_COMMIT}" + else + echo "Unable to determine the first commit for pull request ${PR_ID}." + exit 1 + fi +fi From 1d6d384c0292dfd1d264982608f578ec5f3350f9 Mon Sep 17 00:00:00 2001 From: mritunjaygoutam12 Date: Sat, 3 Nov 2018 03:42:26 +0530 Subject: [PATCH 049/249] doc: correct link to test coverage command PR-URL: https://github.com/nodejs/node/pull/24049 Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca --- doc/guides/writing-tests.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md index 2059a709ff8a95..4d0c0307bbd765 100644 --- a/doc/guides/writing-tests.md +++ b/doc/guides/writing-tests.md @@ -414,7 +414,7 @@ will depend on what is being tested if this is required or not. ### Test Coverage To generate a test coverage report, see the -[Test Coverage section of the Pull Requests guide][]. +[Test Coverage section of the Building guide][]. [ASCII]: http://man7.org/linux/man-pages/man7/ascii.7.html [Google Test]: https://github.com/google/googletest @@ -423,5 +423,5 @@ To generate a test coverage report, see the [all maintained branches]: https://github.com/nodejs/lts [node.green]: http://node.green/ [test fixture]: https://github.com/google/googletest/blob/master/googletest/docs/Primer.md#test-fixtures-using-the-same-data-configuration-for-multiple-tests -[Test Coverage section of the Pull Requests guide]: https://github.com/nodejs/node/blob/master/doc/guides/contributing/pull-requests.md#test-coverage +[Test Coverage section of the Building guide]: https://github.com/nodejs/node/blob/master/BUILDING.md#running-coverage [directory structure overview]: https://github.com/nodejs/node/blob/master/test/README.md#test-directories From 667ce42447e9f2a970962608865b50c4a91c5c47 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 4 Nov 2018 00:18:49 -0700 Subject: [PATCH 050/249] doc: add missing comma in net documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/24074 Reviewed-By: Luigi Pinca Reviewed-By: Michaël Zasso Reviewed-By: James M Snell Reviewed-By: Vse Mozhet Byt --- doc/api/net.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/net.md b/doc/api/net.md index 1b495da81c3f56..07c88cc88520af 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -167,7 +167,7 @@ The number of concurrent connections on the server. This becomes `null` when sending a socket to a child with [`child_process.fork()`][]. To poll forks and get current number of active -connections use asynchronous [`server.getConnections()`][] instead. +connections, use asynchronous [`server.getConnections()`][] instead. ### server.getConnections(callback) +* {number} + +This property shows the number of characters currently buffered to be written. +See [`net.Socket.bufferSize`][] for details. + #### http2stream.close(code[, callback]) diff --git a/tools/lint-md.js b/tools/lint-md.js index 3c22cd8704ffc2..cbb658dd418932 100644 --- a/tools/lint-md.js +++ b/tools/lint-md.js @@ -30293,88 +30293,61 @@ function stringify$7(options) { var remark = unified_1().use(remarkParse).use(remarkStringify).freeze(); -const _args = [["remark@8.0.0","D:\\code\\prws\\tools\\node-lint-md-cli-rollup"]]; -const _from = "remark@8.0.0"; -const _id = "remark@8.0.0"; -const _inBundle = false; -const _integrity = "sha512-K0PTsaZvJlXTl9DN6qYlvjTkqSZBFELhROZMrblm2rB+085flN84nz4g/BscKRMqDvhzlK1oQ/xnWQumdeNZYw=="; -const _location = "/remark"; -const _phantomChildren = {}; -const _requested = {"type":"version","registry":true,"raw":"remark@8.0.0","name":"remark","escapedName":"remark","rawSpec":"8.0.0","saveSpec":null,"fetchSpec":"8.0.0"}; -const _requiredBy = ["/"]; -const _resolved = "https://registry.npmjs.org/remark/-/remark-8.0.0.tgz"; -const _spec = "8.0.0"; -const _where = "D:\\code\\prws\\tools\\node-lint-md-cli-rollup"; -const author = {"name":"Titus Wormer","email":"tituswormer@gmail.com","url":"http://wooorm.com"}; -const bugs = {"url":"https://github.com/wooorm/remark/issues"}; -const contributors = [{"name":"Titus Wormer","email":"tituswormer@gmail.com","url":"http://wooorm.com"}]; -const dependencies = {"remark-parse":"^4.0.0","remark-stringify":"^4.0.0","unified":"^6.0.0"}; +const name = "remark"; +const version$1 = "8.0.0"; const description = "Markdown processor powered by plugins"; -const files = ["index.js"]; -const homepage = "http://remark.js.org"; -const keywords = ["markdown","abstract","syntax","tree","ast","parse","stringify","process"]; const license = "MIT"; -const name = "remark"; -const repository = {"type":"git","url":"https://github.com/wooorm/remark/tree/master/packages/remark"}; +const keywords = ["markdown","abstract","syntax","tree","ast","parse","stringify","process"]; +const dependencies = {"remark-parse":"^4.0.0","remark-stringify":"^4.0.0","unified":"^6.0.0"}; +const homepage = "http://remark.js.org"; +const repository = "https://github.com/wooorm/remark/tree/master/packages/remark"; +const bugs = "https://github.com/wooorm/remark/issues"; +const author = "Titus Wormer (http://wooorm.com)"; +const contributors = ["Titus Wormer (http://wooorm.com)"]; +const files = ["index.js"]; const scripts = {}; -const version$1 = "8.0.0"; const xo = false; +const _resolved = "https://registry.npmjs.org/remark/-/remark-8.0.0.tgz"; +const _integrity = "sha512-K0PTsaZvJlXTl9DN6qYlvjTkqSZBFELhROZMrblm2rB+085flN84nz4g/BscKRMqDvhzlK1oQ/xnWQumdeNZYw=="; +const _from = "remark@8.0.0"; var _package = { - _args: _args, - _from: _from, - _id: _id, - _inBundle: _inBundle, - _integrity: _integrity, - _location: _location, - _phantomChildren: _phantomChildren, - _requested: _requested, - _requiredBy: _requiredBy, - _resolved: _resolved, - _spec: _spec, - _where: _where, - author: author, - bugs: bugs, - contributors: contributors, - dependencies: dependencies, + name: name, + version: version$1, description: description, - files: files, - homepage: homepage, - keywords: keywords, license: license, - name: name, + keywords: keywords, + dependencies: dependencies, + homepage: homepage, repository: repository, + bugs: bugs, + author: author, + contributors: contributors, + files: files, scripts: scripts, - version: version$1, - xo: xo + xo: xo, + _resolved: _resolved, + _integrity: _integrity, + _from: _from }; var _package$1 = Object.freeze({ - _args: _args, - _from: _from, - _id: _id, - _inBundle: _inBundle, - _integrity: _integrity, - _location: _location, - _phantomChildren: _phantomChildren, - _requested: _requested, - _requiredBy: _requiredBy, - _resolved: _resolved, - _spec: _spec, - _where: _where, - author: author, - bugs: bugs, - contributors: contributors, - dependencies: dependencies, + name: name, + version: version$1, description: description, - files: files, - homepage: homepage, - keywords: keywords, license: license, - name: name, + keywords: keywords, + dependencies: dependencies, + homepage: homepage, repository: repository, + bugs: bugs, + author: author, + contributors: contributors, + files: files, scripts: scripts, - version: version$1, xo: xo, + _resolved: _resolved, + _integrity: _integrity, + _from: _from, default: _package }); @@ -30382,7 +30355,7 @@ const name$1 = "node-lint-md-cli-rollup"; const description$1 = "remark packaged for node markdown linting"; const version$2 = "1.0.0"; const devDependencies = {"rollup":"^0.55.5","rollup-plugin-commonjs":"^8.0.2","rollup-plugin-json":"^2.3.1","rollup-plugin-node-resolve":"^3.4.0"}; -const dependencies$1 = {"markdown-extensions":"^1.1.0","remark":"^8.0.0","remark-lint":"^6.0.2","remark-preset-lint-node":"^1.0.3","unified-args":"^6.0.0","unified-engine":"^5.1.0"}; +const dependencies$1 = {"markdown-extensions":"^1.1.0","remark":"^8.0.0","remark-lint":"^6.0.2","remark-preset-lint-node":"^1.1.0","unified-args":"^6.0.0","unified-engine":"^5.1.0"}; const scripts$1 = {"build":"rollup -c","build-node":"npm run build && cp dist/* .."}; var _package$2 = { name: name$1, @@ -32479,7 +32452,84 @@ function noInlinePadding(tree, file) { } } +var remarkLintMaximumLineLength = unifiedLintRule('remark-lint:maximum-line-length', maximumLineLength); + var start$6 = unistUtilPosition.start; +var end$4 = unistUtilPosition.end; + +function maximumLineLength(tree, file, pref) { + var style = typeof pref === 'number' && !isNaN(pref) ? pref : 80; + var content = String(file); + var lines = content.split(/\r?\n/); + var length = lines.length; + var index = -1; + var lineLength; + + unistUtilVisit(tree, ['heading', 'table', 'code', 'definition'], ignore); + unistUtilVisit(tree, ['link', 'image', 'inlineCode'], inline); + + /* Iterate over every line, and warn for violating lines. */ + while (++index < length) { + lineLength = lines[index].length; + + if (lineLength > style) { + file.message('Line must be at most ' + style + ' characters', { + line: index + 1, + column: lineLength + 1 + }); + } + } + + /* Finally, whitelist some inline spans, but only if they occur at or after + * the wrap. However, when they do, and there’s white-space after it, they + * are not whitelisted. */ + function inline(node, pos, parent) { + var next = parent.children[pos + 1]; + var initial; + var final; + + /* istanbul ignore if - Nothing to whitelist when generated. */ + if (unistUtilGenerated(node)) { + return + } + + initial = start$6(node); + final = end$4(node); + + /* No whitelisting when starting after the border, or ending before it. */ + if (initial.column > style || final.column < style) { + return + } + + /* No whitelisting when there’s white-space after + * the link. */ + if ( + next && + start$6(next).line === initial.line && + (!next.value || /^(.+?[ \t].+?)/.test(next.value)) + ) { + return + } + + whitelist(initial.line - 1, final.line); + } + + function ignore(node) { + /* istanbul ignore else - Hard to test, as we only run this case on `position: true` */ + if (!unistUtilGenerated(node)) { + whitelist(start$6(node).line - 1, end$4(node).line); + } + } + + /* Whitelist from `initial` to `final`, zero-based. */ + function whitelist(initial, final) { + while (initial < final) { + lines[initial++] = ''; + } + } +} + +var start$7 = unistUtilPosition.start; @@ -32502,7 +32552,7 @@ function noMultipleToplevelHeadings(tree, file, pref) { node ); } else { - duplicate = unistUtilStringifyPosition(start$6(node)); + duplicate = unistUtilStringifyPosition(start$7(node)); } } } @@ -32664,8 +32714,8 @@ var rule$1 = unifiedLintRule; var remarkLintRuleStyle = rule$1('remark-lint:rule-style', ruleStyle); -var start$7 = unistUtilPosition.start; -var end$4 = unistUtilPosition.end; +var start$8 = unistUtilPosition.start; +var end$5 = unistUtilPosition.end; function ruleStyle(tree, file, pref) { var contents = String(file); @@ -32681,8 +32731,8 @@ function ruleStyle(tree, file, pref) { unistUtilVisit(tree, 'thematicBreak', visitor); function visitor(node) { - var initial = start$7(node).offset; - var final = end$4(node).offset; + var initial = start$8(node).offset; + var final = end$5(node).offset; var rule; if (!unistUtilGenerated(node)) { @@ -32701,8 +32751,8 @@ function ruleStyle(tree, file, pref) { var remarkLintTablePipes = unifiedLintRule('remark-lint:table-pipes', tablePipes); -var start$8 = unistUtilPosition.start; -var end$5 = unistUtilPosition.end; +var start$9 = unistUtilPosition.start; +var end$6 = unistUtilPosition.end; var reasonStart = 'Missing initial pipe in table fence'; var reasonEnd = 'Missing final pipe in table fence'; @@ -32730,15 +32780,15 @@ function tablePipes(tree, file) { cells = row.children; head = cells[0]; tail = cells[cells.length - 1]; - initial = contents.slice(start$8(row).offset, start$8(head).offset); - final = contents.slice(end$5(tail).offset, end$5(row).offset); + initial = contents.slice(start$9(row).offset, start$9(head).offset); + final = contents.slice(end$6(tail).offset, end$6(row).offset); if (initial.indexOf('|') === -1) { - file.message(reasonStart, start$8(row)); + file.message(reasonStart, start$9(row)); } if (final.indexOf('|') === -1) { - file.message(reasonEnd, end$5(row)); + file.message(reasonEnd, end$6(row)); } } } @@ -32800,8 +32850,8 @@ var remarkLintCheckboxCharacterStyle = unifiedLintRule( checkboxCharacterStyle ); -var start$9 = unistUtilPosition.start; -var end$6 = unistUtilPosition.end; +var start$10 = unistUtilPosition.start; +var end$7 = unistUtilPosition.end; var checked = {x: true, X: true}; var unchecked = {' ': true, '\t': true}; @@ -32846,8 +32896,8 @@ function checkboxCharacterStyle(tree, file, pref) { } type = types[node.checked]; - initial = start$9(node).offset; - final = (node.children.length ? start$9(node.children[0]) : end$6(node)).offset; + initial = start$10(node).offset; + final = (node.children.length ? start$10(node.children[0]) : end$7(node)).offset; /* For a checkbox to be parsed, it must be followed by a white space. */ value = contents @@ -32881,8 +32931,8 @@ function checkboxCharacterStyle(tree, file, pref) { var remarkLintCodeBlockStyle = unifiedLintRule('remark-lint:code-block-style', codeBlockStyle); -var start$10 = unistUtilPosition.start; -var end$7 = unistUtilPosition.end; +var start$11 = unistUtilPosition.start; +var end$8 = unistUtilPosition.end; var styles = {null: true, fenced: true, indented: true}; @@ -32915,8 +32965,8 @@ function codeBlockStyle(tree, file, pref) { /* Get the style of `node`. */ function check(node) { - var initial = start$10(node).offset; - var final = end$7(node).offset; + var initial = start$11(node).offset; + var final = end$8(node).offset; if (unistUtilGenerated(node)) { return null @@ -33111,8 +33161,8 @@ function strongMarker(tree, file, pref) { var remarkLintTableCellPadding = unifiedLintRule('remark-lint:table-cell-padding', tableCellPadding); -var start$11 = unistUtilPosition.start; -var end$8 = unistUtilPosition.end; +var start$12 = unistUtilPosition.start; +var end$9 = unistUtilPosition.end; var styles$1 = {null: true, padded: true, compact: true}; @@ -33160,8 +33210,8 @@ function tableCellPadding(tree, file, pref) { next = cells[column + 1]; fence = contents.slice( - cell ? end$8(cell).offset : start$11(row).offset, - next ? start$11(next).offset : end$8(row).offset + cell ? end$9(cell).offset : start$12(row).offset, + next ? start$12(next).offset : end$9(row).offset ); pos = fence.indexOf('|'); @@ -33238,7 +33288,7 @@ function tableCellPadding(tree, file, pref) { } function size(node) { - return end$8(node).offset - start$11(node).offset + return end$9(node).offset - start$12(node).offset } var plugins$1 = [ @@ -33258,6 +33308,7 @@ var plugins$1 = [ remarkLintNoHeadingContentIndent, remarkLintNoHeadingIndent, remarkLintNoInlinePadding, + remarkLintMaximumLineLength, remarkLintNoMultipleToplevelHeadings, remarkLintNoShellDollars, remarkLintNoShortcutReferenceImage, diff --git a/tools/node-lint-md-cli-rollup/package-lock.json b/tools/node-lint-md-cli-rollup/package-lock.json index 49fcc015cd6829..2d37506884a12b 100644 --- a/tools/node-lint-md-cli-rollup/package-lock.json +++ b/tools/node-lint-md-cli-rollup/package-lock.json @@ -2108,6 +2108,17 @@ "unist-util-visit": "^1.1.1" } }, + "remark-lint-maximum-line-length": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remark-lint-maximum-line-length/-/remark-lint-maximum-line-length-1.1.0.tgz", + "integrity": "sha512-L+jI6+DReoxHyAWRIxABjX8hPDgxB8B5Lzp0/nDYjWbjl7I4vTsdEvejpmP1K8LVvZ7Ew0XcVHd1zt+p2O8tDg==", + "requires": { + "unified-lint-rule": "^1.0.0", + "unist-util-generated": "^1.1.0", + "unist-util-position": "^3.0.0", + "unist-util-visit": "^1.1.1" + } + }, "remark-lint-no-auto-link-without-protocol": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/remark-lint-no-auto-link-without-protocol/-/remark-lint-no-auto-link-without-protocol-1.0.2.tgz", @@ -2352,9 +2363,9 @@ } }, "remark-preset-lint-node": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-1.0.3.tgz", - "integrity": "sha512-Ztmm7tcdWWmz/tpCU+bBz9QDRfjrTsa4PUSUWXwPBjQA07asGmw9qUzNTFc1iHXpXVs9xEz1IbVXpWwEJ+9uvA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remark-preset-lint-node/-/remark-preset-lint-node-1.1.0.tgz", + "integrity": "sha512-wT37p0rYGgSy92XNjd7S5WZmtzRLq5iYT9mhVo/p3dVG9oF5NjOjFNUFu/6JBYgGBmZllftWvhrUpKNg+QXqug==", "requires": { "remark-lint": "^6.0.0", "remark-lint-blockquote-indentation": "^1.0.0", @@ -2370,6 +2381,7 @@ "remark-lint-first-heading-level": "^1.0.0", "remark-lint-hard-break-spaces": "^1.0.1", "remark-lint-heading-style": "^1.0.0", + "remark-lint-maximum-line-length": "^1.1.0", "remark-lint-no-auto-link-without-protocol": "^1.0.0", "remark-lint-no-blockquote-without-caret": "^1.0.0", "remark-lint-no-duplicate-definitions": "^1.0.0", @@ -3173,9 +3185,9 @@ } }, "unist-util-generated": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.2.tgz", - "integrity": "sha512-1HcwiEO62dr0XWGT+abVK4f0aAm8Ik8N08c5nAYVmuSxfvpA9rCcNyX/le8xXj1pJK5nBrGlZefeWB6bN8Pstw==" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.3.tgz", + "integrity": "sha512-qlPeDqnQnd84KIqwphzOR+l02cxjDzvEYEBl84EjmKRrX4eUmjyAo8xJv1SCDhJqNjyHRnBMZWNKAiBtXE6hBg==" }, "unist-util-inspect": { "version": "4.1.3", @@ -3191,9 +3203,9 @@ "integrity": "sha512-YkXBK/H9raAmG7KXck+UUpnKiNmUdB+aBGrknfQ4EreE1banuzrKABx3jP6Z5Z3fMSPMQQmeXBlKpCbMwBkxVw==" }, "unist-util-position": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.1.tgz", - "integrity": "sha512-05QfJDPI7PE1BIUtAxeSV+cDx21xP7+tUZgSval5CA7tr0pHBwybF7OnEa1dOFqg6BfYH/qiMUnWwWj+Frhlww==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.0.2.tgz", + "integrity": "sha512-npmFu92l/+b1Ao6uGP4I1WFz9hsKv7qleZ4aliw6x0RVu6A9A3tAf57NMpFfzQ02jxRtJZuRn+C8xWT7GWnH0g==" }, "unist-util-remove-position": { "version": "1.1.2", diff --git a/tools/node-lint-md-cli-rollup/package.json b/tools/node-lint-md-cli-rollup/package.json index e2b105f91bcf4f..b3d491717d4d2f 100644 --- a/tools/node-lint-md-cli-rollup/package.json +++ b/tools/node-lint-md-cli-rollup/package.json @@ -12,7 +12,7 @@ "markdown-extensions": "^1.1.0", "remark": "^8.0.0", "remark-lint": "^6.0.2", - "remark-preset-lint-node": "^1.0.3", + "remark-preset-lint-node": "^1.1.0", "unified-args": "^6.0.0", "unified-engine": "^5.1.0" }, From 9437aaad26370065327efaa1b6a28e4b310ce256 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 3 Nov 2018 10:41:10 -0400 Subject: [PATCH 092/249] src: fix Get() usage in async_wrap.cc PR-URL: https://github.com/nodejs/node/pull/24060 Reviewed-By: Daniel Bevenius Reviewed-By: Anna Henningsen Reviewed-By: Joyee Cheung --- src/async_wrap.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 021bfbdf54c48e..d23e59f69e721c 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -359,8 +359,13 @@ void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo& info) { std::unique_ptr p{info.GetParameter()}; Local prop_bag = PersistentToLocal(info.GetIsolate(), p->propBag); + Local val; + + if (!prop_bag->Get(p->env->context(), p->env->destroyed_string()) + .ToLocal(&val)) { + return; + } - Local val = prop_bag->Get(p->env->destroyed_string()); if (val->IsFalse()) { AsyncWrap::EmitDestroy(p->env, p->asyncId); } From 2a938824982848b0a075fefba6b6e888477fb3a8 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 3 Nov 2018 11:24:50 -0400 Subject: [PATCH 093/249] src: fix Get() usage in tls_wrap.cc PR-URL: https://github.com/nodejs/node/pull/24060 Reviewed-By: Daniel Bevenius Reviewed-By: Anna Henningsen Reviewed-By: Joyee Cheung --- src/tls_wrap.cc | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 6bc152b2e24fca..1d982db28e2558 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -213,17 +213,22 @@ void TLSWrap::SSLInfoCallback(const SSL* ssl_, int where, int ret) { Local object = c->object(); if (where & SSL_CB_HANDSHAKE_START) { - Local callback = object->Get(env->onhandshakestart_string()); - if (callback->IsFunction()) { + Local callback; + + if (object->Get(env->context(), env->onhandshakestart_string()) + .ToLocal(&callback) && callback->IsFunction()) { Local argv[] = { env->GetNow() }; c->MakeCallback(callback.As(), arraysize(argv), argv); } } if (where & SSL_CB_HANDSHAKE_DONE) { + Local callback; + c->established_ = true; - Local callback = object->Get(env->onhandshakedone_string()); - if (callback->IsFunction()) { + + if (object->Get(env->context(), env->onhandshakedone_string()) + .ToLocal(&callback) && callback->IsFunction()) { c->MakeCallback(callback.As(), 0, nullptr); } } @@ -814,7 +819,10 @@ int TLSWrap::SelectSNIContextCallback(SSL* s, int* ad, void* arg) { // Call the SNI callback and use its return value as context Local object = p->object(); - Local ctx = object->Get(env->sni_context_string()); + Local ctx; + + if (!object->Get(env->context(), env->sni_context_string()).ToLocal(&ctx)) + return SSL_TLSEXT_ERR_NOACK; // Not an object, probably undefined or null if (!ctx->IsObject()) From bef1c3b748fc1a9b0401a00741e25d31d861d57c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 3 Nov 2018 11:41:17 -0400 Subject: [PATCH 094/249] src: fix Set() usage in node.h PR-URL: https://github.com/nodejs/node/pull/24060 Reviewed-By: Daniel Bevenius Reviewed-By: Anna Henningsen Reviewed-By: Joyee Cheung --- src/node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node.h b/src/node.h index 5bbaa11def5c86..fbf9128be42429 100644 --- a/src/node.h +++ b/src/node.h @@ -369,7 +369,7 @@ inline void NODE_SET_METHOD(v8::Local recv, v8::Local fn_name = v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized).ToLocalChecked(); fn->SetName(fn_name); - recv->Set(fn_name, fn); + recv->Set(context, fn_name, fn).FromJust(); } #define NODE_SET_METHOD node::NODE_SET_METHOD From 1cda9b39883d825aadf0c011be869e34d8fe2300 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 3 Nov 2018 11:52:37 -0400 Subject: [PATCH 095/249] src: fix Set() usage in env-inl.h PR-URL: https://github.com/nodejs/node/pull/24060 Reviewed-By: Daniel Bevenius Reviewed-By: Anna Henningsen Reviewed-By: Joyee Cheung --- src/env-inl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/env-inl.h b/src/env-inl.h index da8ca222b3361f..30fed57b71fbed 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -740,7 +740,7 @@ inline void Environment::SetMethod(v8::Local that, const v8::NewStringType type = v8::NewStringType::kInternalized; v8::Local name_string = v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); - that->Set(name_string, function); + that->Set(context, name_string, function).FromJust(); function->SetName(name_string); // NODE_SET_METHOD() compatibility. } @@ -760,7 +760,7 @@ inline void Environment::SetMethodNoSideEffect(v8::Local that, const v8::NewStringType type = v8::NewStringType::kInternalized; v8::Local name_string = v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked(); - that->Set(name_string, function); + that->Set(context, name_string, function).FromJust(); function->SetName(name_string); // NODE_SET_METHOD() compatibility. } From 7cc3b9337f0d4b03b0c3d6815dc712a031e177cd Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 7 Nov 2018 12:36:57 -0500 Subject: [PATCH 096/249] doc: fix linting errors PR-URL: https://github.com/nodejs/node/pull/24229 Reviewed-By: Rich Trott Reviewed-By: Refael Ackermann --- doc/api/errors.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index 575f77861fa0f2..82c4e790e6b84b 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -260,7 +260,10 @@ not capture any frames. * {string} The `error.code` property is a string label that identifies the kind of error. -`error.code` is the most stable way to identify an error. It will only change between major versions of Node.js. In contrast, `error.message` strings may change between any versions of Node.js. See [Node.js Error Codes][] for details about specific codes. +`error.code` is the most stable way to identify an error. It will only change +between major versions of Node.js. In contrast, `error.message` strings may +change between any versions of Node.js. See [Node.js Error Codes][] for details +about specific codes. ### error.message @@ -489,7 +492,8 @@ system error. * {string|number} -The `error.errno` property is a number or a string. If it is a number, it is a negative value which corresponds to the error code defined in +The `error.errno` property is a number or a string. If it is a number, it is a +negative value which corresponds to the error code defined in [`libuv Error handling`]. See the libuv `errno.h` header file (`deps/uv/include/uv/errno.h` in the Node.js source tree) for details. In case of a string, it is the same as `error.code`. From f669817a5a20321a49d54a6ec85f7ebd0e5b6b12 Mon Sep 17 00:00:00 2001 From: chux0519 Date: Sun, 4 Nov 2018 00:04:57 -0400 Subject: [PATCH 097/249] crypto: add support for chacha20-poly1305 for AEAD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit openSSL supports AEAD_CHACHA20_POLY1305(rfc7539) since 1.1. PR-URL: https://github.com/nodejs/node/pull/24081 Fixes: https://github.com/nodejs/node/issues/24080 Refs: https://tools.ietf.org/html/rfc7539 Reviewed-By: Ben Noordhuis Reviewed-By: Sam Roberts Reviewed-By: Tobias Nießen --- doc/api/crypto.md | 6 +++ src/node_crypto.cc | 55 ++++++++++++---------- test/fixtures/aead-vectors.js | 37 +++++++++++++++ test/parallel/test-crypto-authenticated.js | 3 +- 4 files changed, 75 insertions(+), 26 deletions(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index d12eb6d1360d38..81706157e62cac 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1382,6 +1382,9 @@ Adversaries][] for details. "; + case Node.DOCUMENT_NODE: + return "Document node with " + val.childNodes.length + (val.childNodes.length == 1 ? " child" : " children"); + case Node.DOCUMENT_TYPE_NODE: + return "DocumentType node"; + case Node.DOCUMENT_FRAGMENT_NODE: + return "DocumentFragment node with " + val.childNodes.length + (val.childNodes.length == 1 ? " child" : " children"); + default: + return "Node object of unknown type"; + } + } + + /* falls through */ + default: + try { + return typeof val + ' "' + truncate(String(val), 1000) + '"'; + } catch(e) { + return ("[stringifying object threw " + String(e) + + " with type " + String(typeof e) + "]"); + } + } + } + expose(format_value, "format_value"); + + /* + * Assertions + */ + + function assert_true(actual, description) + { + assert(actual === true, "assert_true", description, + "expected true got ${actual}", {actual:actual}); + } + expose(assert_true, "assert_true"); + + function assert_false(actual, description) + { + assert(actual === false, "assert_false", description, + "expected false got ${actual}", {actual:actual}); + } + expose(assert_false, "assert_false"); + + function same_value(x, y) { + if (y !== y) { + //NaN case + return x !== x; + } + if (x === 0 && y === 0) { + //Distinguish +0 and -0 + return 1/x === 1/y; + } + return x === y; + } + + function assert_equals(actual, expected, description) + { + /* + * Test if two primitives are equal or two objects + * are the same object + */ + if (typeof actual != typeof expected) { + assert(false, "assert_equals", description, + "expected (" + typeof expected + ") ${expected} but got (" + typeof actual + ") ${actual}", + {expected:expected, actual:actual}); + return; + } + assert(same_value(actual, expected), "assert_equals", description, + "expected ${expected} but got ${actual}", + {expected:expected, actual:actual}); + } + expose(assert_equals, "assert_equals"); + + function assert_not_equals(actual, expected, description) + { + /* + * Test if two primitives are unequal or two objects + * are different objects + */ + assert(!same_value(actual, expected), "assert_not_equals", description, + "got disallowed value ${actual}", + {actual:actual}); + } + expose(assert_not_equals, "assert_not_equals"); + + function assert_in_array(actual, expected, description) + { + assert(expected.indexOf(actual) != -1, "assert_in_array", description, + "value ${actual} not in array ${expected}", + {actual:actual, expected:expected}); + } + expose(assert_in_array, "assert_in_array"); + + function assert_object_equals(actual, expected, description) + { + assert(typeof actual === "object" && actual !== null, "assert_object_equals", description, + "value is ${actual}, expected object", + {actual: actual}); + //This needs to be improved a great deal + function check_equal(actual, expected, stack) + { + stack.push(actual); + + var p; + for (p in actual) { + assert(expected.hasOwnProperty(p), "assert_object_equals", description, + "unexpected property ${p}", {p:p}); + + if (typeof actual[p] === "object" && actual[p] !== null) { + if (stack.indexOf(actual[p]) === -1) { + check_equal(actual[p], expected[p], stack); + } + } else { + assert(same_value(actual[p], expected[p]), "assert_object_equals", description, + "property ${p} expected ${expected} got ${actual}", + {p:p, expected:expected, actual:actual}); + } + } + for (p in expected) { + assert(actual.hasOwnProperty(p), + "assert_object_equals", description, + "expected property ${p} missing", {p:p}); + } + stack.pop(); + } + check_equal(actual, expected, []); + } + expose(assert_object_equals, "assert_object_equals"); + + function assert_array_equals(actual, expected, description) + { + assert(typeof actual === "object" && actual !== null && "length" in actual, + "assert_array_equals", description, + "value is ${actual}, expected array", + {actual:actual}); + assert(actual.length === expected.length, + "assert_array_equals", description, + "lengths differ, expected ${expected} got ${actual}", + {expected:expected.length, actual:actual.length}); + + for (var i = 0; i < actual.length; i++) { + assert(actual.hasOwnProperty(i) === expected.hasOwnProperty(i), + "assert_array_equals", description, + "property ${i}, property expected to be ${expected} but was ${actual}", + {i:i, expected:expected.hasOwnProperty(i) ? "present" : "missing", + actual:actual.hasOwnProperty(i) ? "present" : "missing"}); + assert(same_value(expected[i], actual[i]), + "assert_array_equals", description, + "property ${i}, expected ${expected} but got ${actual}", + {i:i, expected:expected[i], actual:actual[i]}); + } + } + expose(assert_array_equals, "assert_array_equals"); + + function assert_array_approx_equals(actual, expected, epsilon, description) + { + /* + * Test if two primitive arrays are equal within +/- epsilon + */ + assert(actual.length === expected.length, + "assert_array_approx_equals", description, + "lengths differ, expected ${expected} got ${actual}", + {expected:expected.length, actual:actual.length}); + + for (var i = 0; i < actual.length; i++) { + assert(actual.hasOwnProperty(i) === expected.hasOwnProperty(i), + "assert_array_approx_equals", description, + "property ${i}, property expected to be ${expected} but was ${actual}", + {i:i, expected:expected.hasOwnProperty(i) ? "present" : "missing", + actual:actual.hasOwnProperty(i) ? "present" : "missing"}); + assert(typeof actual[i] === "number", + "assert_array_approx_equals", description, + "property ${i}, expected a number but got a ${type_actual}", + {i:i, type_actual:typeof actual[i]}); + assert(Math.abs(actual[i] - expected[i]) <= epsilon, + "assert_array_approx_equals", description, + "property ${i}, expected ${expected} +/- ${epsilon}, expected ${expected} but got ${actual}", + {i:i, expected:expected[i], actual:actual[i]}); + } + } + expose(assert_array_approx_equals, "assert_array_approx_equals"); + + function assert_approx_equals(actual, expected, epsilon, description) + { + /* + * Test if two primitive numbers are equal within +/- epsilon + */ + assert(typeof actual === "number", + "assert_approx_equals", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(Math.abs(actual - expected) <= epsilon, + "assert_approx_equals", description, + "expected ${expected} +/- ${epsilon} but got ${actual}", + {expected:expected, actual:actual, epsilon:epsilon}); + } + expose(assert_approx_equals, "assert_approx_equals"); + + function assert_less_than(actual, expected, description) + { + /* + * Test if a primitive number is less than another + */ + assert(typeof actual === "number", + "assert_less_than", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(actual < expected, + "assert_less_than", description, + "expected a number less than ${expected} but got ${actual}", + {expected:expected, actual:actual}); + } + expose(assert_less_than, "assert_less_than"); + + function assert_greater_than(actual, expected, description) + { + /* + * Test if a primitive number is greater than another + */ + assert(typeof actual === "number", + "assert_greater_than", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(actual > expected, + "assert_greater_than", description, + "expected a number greater than ${expected} but got ${actual}", + {expected:expected, actual:actual}); + } + expose(assert_greater_than, "assert_greater_than"); + + function assert_between_exclusive(actual, lower, upper, description) + { + /* + * Test if a primitive number is between two others + */ + assert(typeof actual === "number", + "assert_between_exclusive", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(actual > lower && actual < upper, + "assert_between_exclusive", description, + "expected a number greater than ${lower} " + + "and less than ${upper} but got ${actual}", + {lower:lower, upper:upper, actual:actual}); + } + expose(assert_between_exclusive, "assert_between_exclusive"); + + function assert_less_than_equal(actual, expected, description) + { + /* + * Test if a primitive number is less than or equal to another + */ + assert(typeof actual === "number", + "assert_less_than_equal", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(actual <= expected, + "assert_less_than_equal", description, + "expected a number less than or equal to ${expected} but got ${actual}", + {expected:expected, actual:actual}); + } + expose(assert_less_than_equal, "assert_less_than_equal"); + + function assert_greater_than_equal(actual, expected, description) + { + /* + * Test if a primitive number is greater than or equal to another + */ + assert(typeof actual === "number", + "assert_greater_than_equal", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(actual >= expected, + "assert_greater_than_equal", description, + "expected a number greater than or equal to ${expected} but got ${actual}", + {expected:expected, actual:actual}); + } + expose(assert_greater_than_equal, "assert_greater_than_equal"); + + function assert_between_inclusive(actual, lower, upper, description) + { + /* + * Test if a primitive number is between to two others or equal to either of them + */ + assert(typeof actual === "number", + "assert_between_inclusive", description, + "expected a number but got a ${type_actual}", + {type_actual:typeof actual}); + + assert(actual >= lower && actual <= upper, + "assert_between_inclusive", description, + "expected a number greater than or equal to ${lower} " + + "and less than or equal to ${upper} but got ${actual}", + {lower:lower, upper:upper, actual:actual}); + } + expose(assert_between_inclusive, "assert_between_inclusive"); + + function assert_regexp_match(actual, expected, description) { + /* + * Test if a string (actual) matches a regexp (expected) + */ + assert(expected.test(actual), + "assert_regexp_match", description, + "expected ${expected} but got ${actual}", + {expected:expected, actual:actual}); + } + expose(assert_regexp_match, "assert_regexp_match"); + + function assert_class_string(object, class_string, description) { + assert_equals({}.toString.call(object), "[object " + class_string + "]", + description); + } + expose(assert_class_string, "assert_class_string"); + + + function assert_own_property(object, property_name, description) { + assert(object.hasOwnProperty(property_name), + "assert_own_property", description, + "expected property ${p} missing", {p:property_name}); + } + expose(assert_own_property, "assert_own_property"); + + function assert_not_own_property(object, property_name, description) { + assert(!object.hasOwnProperty(property_name), + "assert_not_own_property", description, + "unexpected property ${p} is found on object", {p:property_name}); + } + expose(assert_not_own_property, "assert_not_own_property"); + + function _assert_inherits(name) { + return function (object, property_name, description) + { + assert(typeof object === "object" || typeof object === "function", + name, description, + "provided value is not an object"); + + assert("hasOwnProperty" in object, + name, description, + "provided value is an object but has no hasOwnProperty method"); + + assert(!object.hasOwnProperty(property_name), + name, description, + "property ${p} found on object expected in prototype chain", + {p:property_name}); + + assert(property_name in object, + name, description, + "property ${p} not found in prototype chain", + {p:property_name}); + }; + } + expose(_assert_inherits("assert_inherits"), "assert_inherits"); + expose(_assert_inherits("assert_idl_attribute"), "assert_idl_attribute"); + + function assert_readonly(object, property_name, description) + { + var initial_value = object[property_name]; + try { + //Note that this can have side effects in the case where + //the property has PutForwards + object[property_name] = initial_value + "a"; //XXX use some other value here? + assert(same_value(object[property_name], initial_value), + "assert_readonly", description, + "changing property ${p} succeeded", + {p:property_name}); + } finally { + object[property_name] = initial_value; + } + } + expose(assert_readonly, "assert_readonly"); + + /** + * Assert an Exception with the expected code is thrown. + * + * @param {object|number|string} code The expected exception code. + * @param {Function} func Function which should throw. + * @param {string} description Error description for the case that the error is not thrown. + */ + function assert_throws(code, func, description) + { + try { + func.call(this); + assert(false, "assert_throws", description, + "${func} did not throw", {func:func}); + } catch (e) { + if (e instanceof AssertionError) { + throw e; + } + + assert(typeof e === "object", + "assert_throws", description, + "${func} threw ${e} with type ${type}, not an object", + {func:func, e:e, type:typeof e}); + + assert(e !== null, + "assert_throws", description, + "${func} threw null, not an object", + {func:func}); + + if (code === null) { + throw new AssertionError('Test bug: need to pass exception to assert_throws()'); + } + if (typeof code === "object") { + assert("name" in e && e.name == code.name, + "assert_throws", description, + "${func} threw ${actual} (${actual_name}) expected ${expected} (${expected_name})", + {func:func, actual:e, actual_name:e.name, + expected:code, + expected_name:code.name}); + return; + } + + var code_name_map = { + INDEX_SIZE_ERR: 'IndexSizeError', + HIERARCHY_REQUEST_ERR: 'HierarchyRequestError', + WRONG_DOCUMENT_ERR: 'WrongDocumentError', + INVALID_CHARACTER_ERR: 'InvalidCharacterError', + NO_MODIFICATION_ALLOWED_ERR: 'NoModificationAllowedError', + NOT_FOUND_ERR: 'NotFoundError', + NOT_SUPPORTED_ERR: 'NotSupportedError', + INUSE_ATTRIBUTE_ERR: 'InUseAttributeError', + INVALID_STATE_ERR: 'InvalidStateError', + SYNTAX_ERR: 'SyntaxError', + INVALID_MODIFICATION_ERR: 'InvalidModificationError', + NAMESPACE_ERR: 'NamespaceError', + INVALID_ACCESS_ERR: 'InvalidAccessError', + TYPE_MISMATCH_ERR: 'TypeMismatchError', + SECURITY_ERR: 'SecurityError', + NETWORK_ERR: 'NetworkError', + ABORT_ERR: 'AbortError', + URL_MISMATCH_ERR: 'URLMismatchError', + QUOTA_EXCEEDED_ERR: 'QuotaExceededError', + TIMEOUT_ERR: 'TimeoutError', + INVALID_NODE_TYPE_ERR: 'InvalidNodeTypeError', + DATA_CLONE_ERR: 'DataCloneError' + }; + + var name = code in code_name_map ? code_name_map[code] : code; + + var name_code_map = { + IndexSizeError: 1, + HierarchyRequestError: 3, + WrongDocumentError: 4, + InvalidCharacterError: 5, + NoModificationAllowedError: 7, + NotFoundError: 8, + NotSupportedError: 9, + InUseAttributeError: 10, + InvalidStateError: 11, + SyntaxError: 12, + InvalidModificationError: 13, + NamespaceError: 14, + InvalidAccessError: 15, + TypeMismatchError: 17, + SecurityError: 18, + NetworkError: 19, + AbortError: 20, + URLMismatchError: 21, + QuotaExceededError: 22, + TimeoutError: 23, + InvalidNodeTypeError: 24, + DataCloneError: 25, + + EncodingError: 0, + NotReadableError: 0, + UnknownError: 0, + ConstraintError: 0, + DataError: 0, + TransactionInactiveError: 0, + ReadOnlyError: 0, + VersionError: 0, + OperationError: 0, + NotAllowedError: 0 + }; + + if (!(name in name_code_map)) { + throw new AssertionError('Test bug: unrecognized DOMException code "' + code + '" passed to assert_throws()'); + } + + var required_props = { code: name_code_map[name] }; + + if (required_props.code === 0 || + ("name" in e && + e.name !== e.name.toUpperCase() && + e.name !== "DOMException")) { + // New style exception: also test the name property. + required_props.name = name; + } + + //We'd like to test that e instanceof the appropriate interface, + //but we can't, because we don't know what window it was created + //in. It might be an instanceof the appropriate interface on some + //unknown other window. TODO: Work around this somehow? + + for (var prop in required_props) { + assert(prop in e && e[prop] == required_props[prop], + "assert_throws", description, + "${func} threw ${e} that is not a DOMException " + code + ": property ${prop} is equal to ${actual}, expected ${expected}", + {func:func, e:e, prop:prop, actual:e[prop], expected:required_props[prop]}); + } + } + } + expose(assert_throws, "assert_throws"); + + function assert_unreached(description) { + assert(false, "assert_unreached", description, + "Reached unreachable code"); + } + expose(assert_unreached, "assert_unreached"); + + function assert_any(assert_func, actual, expected_array) + { + var args = [].slice.call(arguments, 3); + var errors = []; + var passed = false; + forEach(expected_array, + function(expected) + { + try { + assert_func.apply(this, [actual, expected].concat(args)); + passed = true; + } catch (e) { + errors.push(e.message); + } + }); + if (!passed) { + throw new AssertionError(errors.join("\n\n")); + } + } + expose(assert_any, "assert_any"); + + function Test(name, properties) + { + if (tests.file_is_test && tests.tests.length) { + throw new Error("Tried to create a test with file_is_test"); + } + this.name = name; + + this.phase = tests.is_aborted ? + this.phases.COMPLETE : this.phases.INITIAL; + + this.status = this.NOTRUN; + this.timeout_id = null; + this.index = null; + + this.properties = properties; + var timeout = properties.timeout ? properties.timeout : settings.test_timeout; + if (timeout !== null) { + this.timeout_length = timeout * tests.timeout_multiplier; + } else { + this.timeout_length = null; + } + + this.message = null; + this.stack = null; + + this.steps = []; + this._is_promise_test = false; + + this.cleanup_callbacks = []; + this._user_defined_cleanup_count = 0; + this._done_callbacks = []; + + tests.push(this); + } + + Test.statuses = { + PASS:0, + FAIL:1, + TIMEOUT:2, + NOTRUN:3 + }; + + Test.prototype = merge({}, Test.statuses); + + Test.prototype.phases = { + INITIAL:0, + STARTED:1, + HAS_RESULT:2, + CLEANING:3, + COMPLETE:4 + }; + + Test.prototype.structured_clone = function() + { + if (!this._structured_clone) { + var msg = this.message; + msg = msg ? String(msg) : msg; + this._structured_clone = merge({ + name:String(this.name), + properties:merge({}, this.properties), + phases:merge({}, this.phases) + }, Test.statuses); + } + this._structured_clone.status = this.status; + this._structured_clone.message = this.message; + this._structured_clone.stack = this.stack; + this._structured_clone.index = this.index; + this._structured_clone.phase = this.phase; + return this._structured_clone; + }; + + Test.prototype.step = function(func, this_obj) + { + if (this.phase > this.phases.STARTED) { + return; + } + this.phase = this.phases.STARTED; + //If we don't get a result before the harness times out that will be a test timeout + this.set_status(this.TIMEOUT, "Test timed out"); + + tests.started = true; + tests.notify_test_state(this); + + if (this.timeout_id === null) { + this.set_timeout(); + } + + this.steps.push(func); + + if (arguments.length === 1) { + this_obj = this; + } + + try { + return func.apply(this_obj, Array.prototype.slice.call(arguments, 2)); + } catch (e) { + if (this.phase >= this.phases.HAS_RESULT) { + return; + } + var message = String((typeof e === "object" && e !== null) ? e.message : e); + var stack = e.stack ? e.stack : null; + + this.set_status(this.FAIL, message, stack); + this.phase = this.phases.HAS_RESULT; + this.done(); + } + }; + + Test.prototype.step_func = function(func, this_obj) + { + var test_this = this; + + if (arguments.length === 1) { + this_obj = test_this; + } + + return function() + { + return test_this.step.apply(test_this, [func, this_obj].concat( + Array.prototype.slice.call(arguments))); + }; + }; + + Test.prototype.step_func_done = function(func, this_obj) + { + var test_this = this; + + if (arguments.length === 1) { + this_obj = test_this; + } + + return function() + { + if (func) { + test_this.step.apply(test_this, [func, this_obj].concat( + Array.prototype.slice.call(arguments))); + } + test_this.done(); + }; + }; + + Test.prototype.unreached_func = function(description) + { + return this.step_func(function() { + assert_unreached(description); + }); + }; + + Test.prototype.step_timeout = function(f, timeout) { + var test_this = this; + var args = Array.prototype.slice.call(arguments, 2); + return setTimeout(this.step_func(function() { + return f.apply(test_this, args); + }), timeout * tests.timeout_multiplier); + } + + /* + * Private method for registering cleanup functions. `testharness.js` + * internals should use this method instead of the public `add_cleanup` + * method in order to hide implementation details from the harness status + * message in the case errors. + */ + Test.prototype._add_cleanup = function(callback) { + this.cleanup_callbacks.push(callback); + }; + + /* + * Schedule a function to be run after the test result is known, regardless + * of passing or failing state. The behavior of this function will not + * influence the result of the test, but if an exception is thrown, the + * test harness will report an error. + */ + Test.prototype.add_cleanup = function(callback) { + this._user_defined_cleanup_count += 1; + this._add_cleanup(callback); + }; + + Test.prototype.set_timeout = function() + { + if (this.timeout_length !== null) { + var this_obj = this; + this.timeout_id = setTimeout(function() + { + this_obj.timeout(); + }, this.timeout_length); + } + }; + + Test.prototype.set_status = function(status, message, stack) + { + this.status = status; + this.message = message; + this.stack = stack ? stack : null; + }; + + Test.prototype.timeout = function() + { + this.timeout_id = null; + this.set_status(this.TIMEOUT, "Test timed out"); + this.phase = this.phases.HAS_RESULT; + this.done(); + }; + + Test.prototype.force_timeout = Test.prototype.timeout; + + /** + * Update the test status, initiate "cleanup" functions, and signal test + * completion. + */ + Test.prototype.done = function() + { + if (this.phase >= this.phases.CLEANING) { + return; + } + + if (this.phase <= this.phases.STARTED) { + this.set_status(this.PASS, null); + } + + if (global_scope.clearTimeout) { + clearTimeout(this.timeout_id); + } + + this.cleanup(); + }; + + function add_test_done_callback(test, callback) + { + if (test.phase === test.phases.COMPLETE) { + callback(); + return; + } + + test._done_callbacks.push(callback); + } + + /* + * Invoke all specified cleanup functions. If one or more produce an error, + * the context is in an unpredictable state, so all further testing should + * be cancelled. + */ + Test.prototype.cleanup = function() { + var error_count = 0; + var bad_value_count = 0; + function on_error() { + error_count += 1; + // Abort tests immediately so that tests declared within subsequent + // cleanup functions are not run. + tests.abort(); + } + var this_obj = this; + var results = []; + + this.phase = this.phases.CLEANING; + + forEach(this.cleanup_callbacks, + function(cleanup_callback) { + var result; + + try { + result = cleanup_callback(); + } catch (e) { + on_error(); + return; + } + + if (!is_valid_cleanup_result(this_obj, result)) { + bad_value_count += 1; + // Abort tests immediately so that tests declared + // within subsequent cleanup functions are not run. + tests.abort(); + } + + results.push(result); + }); + + if (!this._is_promise_test) { + cleanup_done(this_obj, error_count, bad_value_count); + } else { + all_async(results, + function(result, done) { + if (result && typeof result.then === "function") { + result + .then(null, on_error) + .then(done); + } else { + done(); + } + }, + function() { + cleanup_done(this_obj, error_count, bad_value_count); + }); + } + }; + + /** + * Determine if the return value of a cleanup function is valid for a given + * test. Any test may return the value `undefined`. Tests created with + * `promise_test` may alternatively return "thenable" object values. + */ + function is_valid_cleanup_result(test, result) { + if (result === undefined) { + return true; + } + + if (test._is_promise_test) { + return result && typeof result.then === "function"; + } + + return false; + } + + function cleanup_done(test, error_count, bad_value_count) { + if (error_count || bad_value_count) { + var total = test._user_defined_cleanup_count; + + tests.status.status = tests.status.ERROR; + tests.status.message = "Test named '" + test.name + + "' specified " + total + + " 'cleanup' function" + (total > 1 ? "s" : ""); + + if (error_count) { + tests.status.message += ", and " + error_count + " failed"; + } + + if (bad_value_count) { + var type = test._is_promise_test ? + "non-thenable" : "non-undefined"; + tests.status.message += ", and " + bad_value_count + + " returned a " + type + " value"; + } + + tests.status.message += "."; + + tests.status.stack = null; + } + + test.phase = test.phases.COMPLETE; + tests.result(test); + forEach(test._done_callbacks, + function(callback) { + callback(); + }); + test._done_callbacks.length = 0; + } + + /* + * A RemoteTest object mirrors a Test object on a remote worker. The + * associated RemoteWorker updates the RemoteTest object in response to + * received events. In turn, the RemoteTest object replicates these events + * on the local document. This allows listeners (test result reporting + * etc..) to transparently handle local and remote events. + */ + function RemoteTest(clone) { + var this_obj = this; + Object.keys(clone).forEach( + function(key) { + this_obj[key] = clone[key]; + }); + this.index = null; + this.phase = this.phases.INITIAL; + this.update_state_from(clone); + this._done_callbacks = []; + tests.push(this); + } + + RemoteTest.prototype.structured_clone = function() { + var clone = {}; + Object.keys(this).forEach( + (function(key) { + var value = this[key]; + // `RemoteTest` instances are responsible for managing + // their own "done" callback functions, so those functions + // are not relevant in other execution contexts. Because of + // this (and because Function values cannot be serialized + // for cross-realm transmittance), the property should not + // be considered when cloning instances. + if (key === '_done_callbacks' ) { + return; + } + + if (typeof value === "object" && value !== null) { + clone[key] = merge({}, value); + } else { + clone[key] = value; + } + }).bind(this)); + clone.phases = merge({}, this.phases); + return clone; + }; + + /** + * `RemoteTest` instances are objects which represent tests running in + * another realm. They do not define "cleanup" functions (if necessary, + * such functions are defined on the associated `Test` instance within the + * external realm). However, `RemoteTests` may have "done" callbacks (e.g. + * as attached by the `Tests` instance responsible for tracking the overall + * test status in the parent realm). The `cleanup` method delegates to + * `done` in order to ensure that such callbacks are invoked following the + * completion of the `RemoteTest`. + */ + RemoteTest.prototype.cleanup = function() { + this.done(); + }; + RemoteTest.prototype.phases = Test.prototype.phases; + RemoteTest.prototype.update_state_from = function(clone) { + this.status = clone.status; + this.message = clone.message; + this.stack = clone.stack; + if (this.phase === this.phases.INITIAL) { + this.phase = this.phases.STARTED; + } + }; + RemoteTest.prototype.done = function() { + this.phase = this.phases.COMPLETE; + + forEach(this._done_callbacks, + function(callback) { + callback(); + }); + } + + /* + * A RemoteContext listens for test events from a remote test context, such + * as another window or a worker. These events are then used to construct + * and maintain RemoteTest objects that mirror the tests running in the + * remote context. + * + * An optional third parameter can be used as a predicate to filter incoming + * MessageEvents. + */ + function RemoteContext(remote, message_target, message_filter) { + this.running = true; + this.tests = new Array(); + + var this_obj = this; + // If remote context is cross origin assigning to onerror is not + // possible, so silently catch those errors. + try { + remote.onerror = function(error) { this_obj.remote_error(error); }; + } catch (e) { + // Ignore. + } + + // Keeping a reference to the remote object and the message handler until + // remote_done() is seen prevents the remote object and its message channel + // from going away before all the messages are dispatched. + this.remote = remote; + this.message_target = message_target; + this.message_handler = function(message) { + var passesFilter = !message_filter || message_filter(message); + // The reference to the `running` property in the following + // condition is unnecessary because that value is only set to + // `false` after the `message_handler` function has been + // unsubscribed. + // TODO: Simplify the condition by removing the reference. + if (this_obj.running && message.data && passesFilter && + (message.data.type in this_obj.message_handlers)) { + this_obj.message_handlers[message.data.type].call(this_obj, message.data); + } + }; + + if (self.Promise) { + this.done = new Promise(function(resolve) { + this_obj.doneResolve = resolve; + }); + } + + this.message_target.addEventListener("message", this.message_handler); + } + + RemoteContext.prototype.remote_error = function(error) { + var message = error.message || String(error); + var filename = (error.filename ? " " + error.filename: ""); + // FIXME: Display remote error states separately from main document + // error state. + tests.set_status(tests.status.ERROR, + "Error in remote" + filename + ": " + message, + error.stack); + + if (error.preventDefault) { + error.preventDefault(); + } + }; + + RemoteContext.prototype.test_state = function(data) { + var remote_test = this.tests[data.test.index]; + if (!remote_test) { + remote_test = new RemoteTest(data.test); + this.tests[data.test.index] = remote_test; + } + remote_test.update_state_from(data.test); + tests.notify_test_state(remote_test); + }; + + RemoteContext.prototype.test_done = function(data) { + var remote_test = this.tests[data.test.index]; + remote_test.update_state_from(data.test); + remote_test.done(); + tests.result(remote_test); + }; + + RemoteContext.prototype.remote_done = function(data) { + if (tests.status.status === null && + data.status.status !== data.status.OK) { + tests.set_status(data.status.status, data.status.message, data.status.sack); + } + + this.message_target.removeEventListener("message", this.message_handler); + this.running = false; + + // If remote context is cross origin assigning to onerror is not + // possible, so silently catch those errors. + try { + this.remote.onerror = null; + } catch (e) { + // Ignore. + } + + this.remote = null; + this.message_target = null; + if (this.doneResolve) { + this.doneResolve(); + } + + if (tests.all_done()) { + tests.complete(); + } + }; + + RemoteContext.prototype.message_handlers = { + test_state: RemoteContext.prototype.test_state, + result: RemoteContext.prototype.test_done, + complete: RemoteContext.prototype.remote_done + }; + + /* + * Harness + */ + + function TestsStatus() + { + this.status = null; + this.message = null; + this.stack = null; + } + + TestsStatus.statuses = { + OK:0, + ERROR:1, + TIMEOUT:2 + }; + + TestsStatus.prototype = merge({}, TestsStatus.statuses); + + TestsStatus.prototype.structured_clone = function() + { + if (!this._structured_clone) { + var msg = this.message; + msg = msg ? String(msg) : msg; + this._structured_clone = merge({ + status:this.status, + message:msg, + stack:this.stack + }, TestsStatus.statuses); + } + return this._structured_clone; + }; + + function Tests() + { + this.tests = []; + this.num_pending = 0; + + this.phases = { + INITIAL:0, + SETUP:1, + HAVE_TESTS:2, + HAVE_RESULTS:3, + COMPLETE:4 + }; + this.phase = this.phases.INITIAL; + + this.properties = {}; + + this.wait_for_finish = false; + this.processing_callbacks = false; + + this.allow_uncaught_exception = false; + + this.file_is_test = false; + + this.timeout_multiplier = 1; + this.timeout_length = test_environment.test_timeout(); + this.timeout_id = null; + + this.start_callbacks = []; + this.test_state_callbacks = []; + this.test_done_callbacks = []; + this.all_done_callbacks = []; + + this.pending_remotes = []; + + this.status = new TestsStatus(); + + var this_obj = this; + + test_environment.add_on_loaded_callback(function() { + if (this_obj.all_done()) { + this_obj.complete(); + } + }); + + this.set_timeout(); + } + + Tests.prototype.setup = function(func, properties) + { + if (this.phase >= this.phases.HAVE_RESULTS) { + return; + } + + if (this.phase < this.phases.SETUP) { + this.phase = this.phases.SETUP; + } + + this.properties = properties; + + for (var p in properties) { + if (properties.hasOwnProperty(p)) { + var value = properties[p]; + if (p == "allow_uncaught_exception") { + this.allow_uncaught_exception = value; + } else if (p == "explicit_done" && value) { + this.wait_for_finish = true; + } else if (p == "explicit_timeout" && value) { + this.timeout_length = null; + if (this.timeout_id) + { + clearTimeout(this.timeout_id); + } + } else if (p == "timeout_multiplier") { + this.timeout_multiplier = value; + } + } + } + + if (func) { + try { + func(); + } catch (e) { + this.status.status = this.status.ERROR; + this.status.message = String(e); + this.status.stack = e.stack ? e.stack : null; + } + } + this.set_timeout(); + }; + + Tests.prototype.set_file_is_test = function() { + if (this.tests.length > 0) { + throw new Error("Tried to set file as test after creating a test"); + } + this.wait_for_finish = true; + this.file_is_test = true; + // Create the test, which will add it to the list of tests + async_test(); + }; + + Tests.prototype.set_status = function(status, message, stack) + { + this.status.status = status; + this.status.message = message; + this.status.stack = stack ? stack : null; + }; + + Tests.prototype.set_timeout = function() { + if (global_scope.clearTimeout) { + var this_obj = this; + clearTimeout(this.timeout_id); + if (this.timeout_length !== null) { + this.timeout_id = setTimeout(function() { + this_obj.timeout(); + }, this.timeout_length); + } + } + }; + + Tests.prototype.timeout = function() { + var test_in_cleanup = null; + + if (this.status.status === null) { + forEach(this.tests, + function(test) { + // No more than one test is expected to be in the + // "CLEANUP" phase at any time + if (test.phase === test.phases.CLEANING) { + test_in_cleanup = test; + } + + test.phase = test.phases.COMPLETE; + }); + + // Timeouts that occur while a test is in the "cleanup" phase + // indicate that some global state was not properly reverted. This + // invalidates the overall test execution, so the timeout should be + // reported as an error and cancel the execution of any remaining + // tests. + if (test_in_cleanup) { + this.status.status = this.status.ERROR; + this.status.message = "Timeout while running cleanup for " + + "test named \"" + test_in_cleanup.name + "\"."; + tests.status.stack = null; + } else { + this.status.status = this.status.TIMEOUT; + } + } + + this.complete(); + }; + + Tests.prototype.end_wait = function() + { + this.wait_for_finish = false; + if (this.all_done()) { + this.complete(); + } + }; + + Tests.prototype.push = function(test) + { + if (this.phase < this.phases.HAVE_TESTS) { + this.start(); + } + this.num_pending++; + test.index = this.tests.push(test); + this.notify_test_state(test); + }; + + Tests.prototype.notify_test_state = function(test) { + var this_obj = this; + forEach(this.test_state_callbacks, + function(callback) { + callback(test, this_obj); + }); + }; + + Tests.prototype.all_done = function() { + return this.tests.length > 0 && test_environment.all_loaded && + (this.num_pending === 0 || this.is_aborted) && !this.wait_for_finish && + !this.processing_callbacks && + !this.pending_remotes.some(function(w) { return w.running; }); + }; + + Tests.prototype.start = function() { + this.phase = this.phases.HAVE_TESTS; + this.notify_start(); + }; + + Tests.prototype.notify_start = function() { + var this_obj = this; + forEach (this.start_callbacks, + function(callback) + { + callback(this_obj.properties); + }); + }; + + Tests.prototype.result = function(test) + { + // If the harness has already transitioned beyond the `HAVE_RESULTS` + // phase, subsequent tests should not cause it to revert. + if (this.phase <= this.phases.HAVE_RESULTS) { + this.phase = this.phases.HAVE_RESULTS; + } + this.num_pending--; + this.notify_result(test); + }; + + Tests.prototype.notify_result = function(test) { + var this_obj = this; + this.processing_callbacks = true; + forEach(this.test_done_callbacks, + function(callback) + { + callback(test, this_obj); + }); + this.processing_callbacks = false; + if (this_obj.all_done()) { + this_obj.complete(); + } + }; + + Tests.prototype.complete = function() { + if (this.phase === this.phases.COMPLETE) { + return; + } + var this_obj = this; + var all_complete = function() { + this_obj.phase = this_obj.phases.COMPLETE; + this_obj.notify_complete(); + }; + var incomplete = filter(this.tests, + function(test) { + return test.phase < test.phases.COMPLETE; + }); + + /** + * To preserve legacy behavior, overall test completion must be + * signaled synchronously. + */ + if (incomplete.length === 0) { + all_complete(); + return; + } + + all_async(incomplete, + function(test, testDone) + { + if (test.phase === test.phases.INITIAL) { + test.phase = test.phases.COMPLETE; + testDone(); + } else { + add_test_done_callback(test, testDone); + test.cleanup(); + } + }, + all_complete); + }; + + /** + * Update the harness status to reflect an unrecoverable harness error that + * should cancel all further testing. Update all previously-defined tests + * which have not yet started to indicate that they will not be executed. + */ + Tests.prototype.abort = function() { + this.status.status = this.status.ERROR; + this.is_aborted = true; + + forEach(this.tests, + function(test) { + if (test.phase === test.phases.INITIAL) { + test.phase = test.phases.COMPLETE; + } + }); + }; + + /* + * Determine if any tests share the same `name` property. Return an array + * containing the names of any such duplicates. + */ + Tests.prototype.find_duplicates = function() { + var names = Object.create(null); + var duplicates = []; + + forEach (this.tests, + function(test) + { + if (test.name in names && duplicates.indexOf(test.name) === -1) { + duplicates.push(test.name); + } + names[test.name] = true; + }); + + return duplicates; + }; + + Tests.prototype.notify_complete = function() { + var this_obj = this; + var duplicates; + + if (this.status.status === null) { + duplicates = this.find_duplicates(); + + // Test names are presumed to be unique within test files--this + // allows consumers to use them for identification purposes. + // Duplicated names violate this expectation and should therefore + // be reported as an error. + if (duplicates.length) { + this.status.status = this.status.ERROR; + this.status.message = + duplicates.length + ' duplicate test name' + + (duplicates.length > 1 ? 's' : '') + ': "' + + duplicates.join('", "') + '"'; + } else { + this.status.status = this.status.OK; + } + } + + forEach (this.all_done_callbacks, + function(callback) + { + callback(this_obj.tests, this_obj.status); + }); + }; + + /* + * Constructs a RemoteContext that tracks tests from a specific worker. + */ + Tests.prototype.create_remote_worker = function(worker) { + var message_port; + + if (is_service_worker(worker)) { + if (window.MessageChannel) { + // The ServiceWorker's implicit MessagePort is currently not + // reliably accessible from the ServiceWorkerGlobalScope due to + // Blink setting MessageEvent.source to null for messages sent + // via ServiceWorker.postMessage(). Until that's resolved, + // create an explicit MessageChannel and pass one end to the + // worker. + var message_channel = new MessageChannel(); + message_port = message_channel.port1; + message_port.start(); + worker.postMessage({type: "connect"}, [message_channel.port2]); + } else { + // If MessageChannel is not available, then try the + // ServiceWorker.postMessage() approach using MessageEvent.source + // on the other end. + message_port = navigator.serviceWorker; + worker.postMessage({type: "connect"}); + } + } else if (is_shared_worker(worker)) { + message_port = worker.port; + message_port.start(); + } else { + message_port = worker; + } + + return new RemoteContext(worker, message_port); + }; + + /* + * Constructs a RemoteContext that tracks tests from a specific window. + */ + Tests.prototype.create_remote_window = function(remote) { + remote.postMessage({type: "getmessages"}, "*"); + return new RemoteContext( + remote, + window, + function(msg) { + return msg.source === remote; + } + ); + }; + + Tests.prototype.fetch_tests_from_worker = function(worker) { + if (this.phase >= this.phases.COMPLETE) { + return; + } + + var remoteContext = this.create_remote_worker(worker); + this.pending_remotes.push(remoteContext); + return remoteContext.done; + }; + + function fetch_tests_from_worker(port) { + return tests.fetch_tests_from_worker(port); + } + expose(fetch_tests_from_worker, 'fetch_tests_from_worker'); + + Tests.prototype.fetch_tests_from_window = function(remote) { + if (this.phase >= this.phases.COMPLETE) { + return; + } + + this.pending_remotes.push(this.create_remote_window(remote)); + }; + + function fetch_tests_from_window(window) { + tests.fetch_tests_from_window(window); + } + expose(fetch_tests_from_window, 'fetch_tests_from_window'); + + function timeout() { + if (tests.timeout_length === null) { + tests.timeout(); + } + } + expose(timeout, 'timeout'); + + function add_start_callback(callback) { + tests.start_callbacks.push(callback); + } + + function add_test_state_callback(callback) { + tests.test_state_callbacks.push(callback); + } + + function add_result_callback(callback) { + tests.test_done_callbacks.push(callback); + } + + function add_completion_callback(callback) { + tests.all_done_callbacks.push(callback); + } + + expose(add_start_callback, 'add_start_callback'); + expose(add_test_state_callback, 'add_test_state_callback'); + expose(add_result_callback, 'add_result_callback'); + expose(add_completion_callback, 'add_completion_callback'); + + function remove(array, item) { + var index = array.indexOf(item); + if (index > -1) { + array.splice(index, 1); + } + } + + function remove_start_callback(callback) { + remove(tests.start_callbacks, callback); + } + + function remove_test_state_callback(callback) { + remove(tests.test_state_callbacks, callback); + } + + function remove_result_callback(callback) { + remove(tests.test_done_callbacks, callback); + } + + function remove_completion_callback(callback) { + remove(tests.all_done_callbacks, callback); + } + + /* + * Output listener + */ + + function Output() { + this.output_document = document; + this.output_node = null; + this.enabled = settings.output; + this.phase = this.INITIAL; + } + + Output.prototype.INITIAL = 0; + Output.prototype.STARTED = 1; + Output.prototype.HAVE_RESULTS = 2; + Output.prototype.COMPLETE = 3; + + Output.prototype.setup = function(properties) { + if (this.phase > this.INITIAL) { + return; + } + + //If output is disabled in testharnessreport.js the test shouldn't be + //able to override that + this.enabled = this.enabled && (properties.hasOwnProperty("output") ? + properties.output : settings.output); + }; + + Output.prototype.init = function(properties) { + if (this.phase >= this.STARTED) { + return; + } + if (properties.output_document) { + this.output_document = properties.output_document; + } else { + this.output_document = document; + } + this.phase = this.STARTED; + }; + + Output.prototype.resolve_log = function() { + var output_document; + if (typeof this.output_document === "function") { + output_document = this.output_document.apply(undefined); + } else { + output_document = this.output_document; + } + if (!output_document) { + return; + } + var node = output_document.getElementById("log"); + if (!node) { + if (!document.readyState == "loading") { + return; + } + node = output_document.createElementNS("http://www.w3.org/1999/xhtml", "div"); + node.id = "log"; + if (output_document.body) { + output_document.body.appendChild(node); + } else { + var root = output_document.documentElement; + var is_html = (root && + root.namespaceURI == "http://www.w3.org/1999/xhtml" && + root.localName == "html"); + var is_svg = (output_document.defaultView && + "SVGSVGElement" in output_document.defaultView && + root instanceof output_document.defaultView.SVGSVGElement); + if (is_svg) { + var foreignObject = output_document.createElementNS("http://www.w3.org/2000/svg", "foreignObject"); + foreignObject.setAttribute("width", "100%"); + foreignObject.setAttribute("height", "100%"); + root.appendChild(foreignObject); + foreignObject.appendChild(node); + } else if (is_html) { + root.appendChild(output_document.createElementNS("http://www.w3.org/1999/xhtml", "body")) + .appendChild(node); + } else { + root.appendChild(node); + } + } + } + this.output_document = output_document; + this.output_node = node; + }; + + Output.prototype.show_status = function() { + if (this.phase < this.STARTED) { + this.init(); + } + if (!this.enabled) { + return; + } + if (this.phase < this.HAVE_RESULTS) { + this.resolve_log(); + this.phase = this.HAVE_RESULTS; + } + var done_count = tests.tests.length - tests.num_pending; + if (this.output_node) { + if (done_count < 100 || + (done_count < 1000 && done_count % 100 === 0) || + done_count % 1000 === 0) { + this.output_node.textContent = "Running, " + + done_count + " complete, " + + tests.num_pending + " remain"; + } + } + }; + + Output.prototype.show_results = function (tests, harness_status) { + if (this.phase >= this.COMPLETE) { + return; + } + if (!this.enabled) { + return; + } + if (!this.output_node) { + this.resolve_log(); + } + this.phase = this.COMPLETE; + + var log = this.output_node; + if (!log) { + return; + } + var output_document = this.output_document; + + while (log.lastChild) { + log.removeChild(log.lastChild); + } + + var stylesheet = output_document.createElementNS(xhtml_ns, "style"); + stylesheet.textContent = stylesheetContent; + var heads = output_document.getElementsByTagName("head"); + if (heads.length) { + heads[0].appendChild(stylesheet); + } + + var status_text_harness = {}; + status_text_harness[harness_status.OK] = "OK"; + status_text_harness[harness_status.ERROR] = "Error"; + status_text_harness[harness_status.TIMEOUT] = "Timeout"; + + var status_text = {}; + status_text[Test.prototype.PASS] = "Pass"; + status_text[Test.prototype.FAIL] = "Fail"; + status_text[Test.prototype.TIMEOUT] = "Timeout"; + status_text[Test.prototype.NOTRUN] = "Not Run"; + + var status_number = {}; + forEach(tests, + function(test) { + var status = status_text[test.status]; + if (status_number.hasOwnProperty(status)) { + status_number[status] += 1; + } else { + status_number[status] = 1; + } + }); + + function status_class(status) + { + return status.replace(/\s/g, '').toLowerCase(); + } + + var summary_template = ["section", {"id":"summary"}, + ["h2", {}, "Summary"], + function() + { + + var status = status_text_harness[harness_status.status]; + var rv = [["section", {}, + ["p", {}, + "Harness status: ", + ["span", {"class":status_class(status)}, + status + ], + ] + ]]; + + if (harness_status.status === harness_status.ERROR) { + rv[0].push(["pre", {}, harness_status.message]); + if (harness_status.stack) { + rv[0].push(["pre", {}, harness_status.stack]); + } + } + return rv; + }, + ["p", {}, "Found ${num_tests} tests"], + function() { + var rv = [["div", {}]]; + var i = 0; + while (status_text.hasOwnProperty(i)) { + if (status_number.hasOwnProperty(status_text[i])) { + var status = status_text[i]; + rv[0].push(["div", {"class":status_class(status)}, + ["label", {}, + ["input", {type:"checkbox", checked:"checked"}], + status_number[status] + " " + status]]); + } + i++; + } + return rv; + }, + ]; + + log.appendChild(render(summary_template, {num_tests:tests.length}, output_document)); + + forEach(output_document.querySelectorAll("section#summary label"), + function(element) + { + on_event(element, "click", + function(e) + { + if (output_document.getElementById("results") === null) { + e.preventDefault(); + return; + } + var result_class = element.parentNode.getAttribute("class"); + var style_element = output_document.querySelector("style#hide-" + result_class); + var input_element = element.querySelector("input"); + if (!style_element && !input_element.checked) { + style_element = output_document.createElementNS(xhtml_ns, "style"); + style_element.id = "hide-" + result_class; + style_element.textContent = "table#results > tbody > tr."+result_class+"{display:none}"; + output_document.body.appendChild(style_element); + } else if (style_element && input_element.checked) { + style_element.parentNode.removeChild(style_element); + } + }); + }); + + // This use of innerHTML plus manual escaping is not recommended in + // general, but is necessary here for performance. Using textContent + // on each individual " + + (assertions ? "" : "") + + "" + + ""; + for (var i = 0; i < tests.length; i++) { + html += '"; + } + html += "
11Current adds tens of seconds of execution time for + // large test suites (tens of thousands of tests). + function escape_html(s) + { + return s.replace(/\&/g, "&") + .replace(/" + + "
ResultTest NameAssertionMessage
' + + escape_html(status_text[tests[i].status]) + + "" + + escape_html(tests[i].name) + + "" + + (assertions ? escape_html(get_assertion(tests[i])) + "" : "") + + escape_html(tests[i].message ? tests[i].message : " ") + + (tests[i].stack ? "
" +
+                 escape_html(tests[i].stack) +
+                 "
": "") + + "
"; + try { + log.lastChild.innerHTML = html; + } catch (e) { + log.appendChild(document.createElementNS(xhtml_ns, "p")) + .textContent = "Setting innerHTML for the log threw an exception."; + log.appendChild(document.createElementNS(xhtml_ns, "pre")) + .textContent = html; + } + }; + + /* + * Template code + * + * A template is just a JavaScript structure. An element is represented as: + * + * [tag_name, {attr_name:attr_value}, child1, child2] + * + * the children can either be strings (which act like text nodes), other templates or + * functions (see below) + * + * A text node is represented as + * + * ["{text}", value] + * + * String values have a simple substitution syntax; ${foo} represents a variable foo. + * + * It is possible to embed logic in templates by using a function in a place where a + * node would usually go. The function must either return part of a template or null. + * + * In cases where a set of nodes are required as output rather than a single node + * with children it is possible to just use a list + * [node1, node2, node3] + * + * Usage: + * + * render(template, substitutions) - take a template and an object mapping + * variable names to parameters and return either a DOM node or a list of DOM nodes + * + * substitute(template, substitutions) - take a template and variable mapping object, + * make the variable substitutions and return the substituted template + * + */ + + function is_single_node(template) + { + return typeof template[0] === "string"; + } + + function substitute(template, substitutions) + { + if (typeof template === "function") { + var replacement = template(substitutions); + if (!replacement) { + return null; + } + + return substitute(replacement, substitutions); + } + + if (is_single_node(template)) { + return substitute_single(template, substitutions); + } + + return filter(map(template, function(x) { + return substitute(x, substitutions); + }), function(x) {return x !== null;}); + } + + function substitute_single(template, substitutions) + { + var substitution_re = /\$\{([^ }]*)\}/g; + + function do_substitution(input) { + var components = input.split(substitution_re); + var rv = []; + for (var i = 0; i < components.length; i += 2) { + rv.push(components[i]); + if (components[i + 1]) { + rv.push(String(substitutions[components[i + 1]])); + } + } + return rv; + } + + function substitute_attrs(attrs, rv) + { + rv[1] = {}; + for (var name in template[1]) { + if (attrs.hasOwnProperty(name)) { + var new_name = do_substitution(name).join(""); + var new_value = do_substitution(attrs[name]).join(""); + rv[1][new_name] = new_value; + } + } + } + + function substitute_children(children, rv) + { + for (var i = 0; i < children.length; i++) { + if (children[i] instanceof Object) { + var replacement = substitute(children[i], substitutions); + if (replacement !== null) { + if (is_single_node(replacement)) { + rv.push(replacement); + } else { + extend(rv, replacement); + } + } + } else { + extend(rv, do_substitution(String(children[i]))); + } + } + return rv; + } + + var rv = []; + rv.push(do_substitution(String(template[0])).join("")); + + if (template[0] === "{text}") { + substitute_children(template.slice(1), rv); + } else { + substitute_attrs(template[1], rv); + substitute_children(template.slice(2), rv); + } + + return rv; + } + + function make_dom_single(template, doc) + { + var output_document = doc || document; + var element; + if (template[0] === "{text}") { + element = output_document.createTextNode(""); + for (var i = 1; i < template.length; i++) { + element.data += template[i]; + } + } else { + element = output_document.createElementNS(xhtml_ns, template[0]); + for (var name in template[1]) { + if (template[1].hasOwnProperty(name)) { + element.setAttribute(name, template[1][name]); + } + } + for (var i = 2; i < template.length; i++) { + if (template[i] instanceof Object) { + var sub_element = make_dom(template[i]); + element.appendChild(sub_element); + } else { + var text_node = output_document.createTextNode(template[i]); + element.appendChild(text_node); + } + } + } + + return element; + } + + function make_dom(template, substitutions, output_document) + { + if (is_single_node(template)) { + return make_dom_single(template, output_document); + } + + return map(template, function(x) { + return make_dom_single(x, output_document); + }); + } + + function render(template, substitutions, output_document) + { + return make_dom(substitute(template, substitutions), output_document); + } + + /* + * Utility functions + */ + function assert(expected_true, function_name, description, error, substitutions) + { + if (tests.tests.length === 0) { + tests.set_file_is_test(); + } + if (expected_true !== true) { + var msg = make_message(function_name, description, + error, substitutions); + throw new AssertionError(msg); + } + } + + function AssertionError(message) + { + this.message = message; + this.stack = this.get_stack(); + } + expose(AssertionError, "AssertionError"); + + AssertionError.prototype = Object.create(Error.prototype); + + AssertionError.prototype.get_stack = function() { + var stack = new Error().stack; + // IE11 does not initialize 'Error.stack' until the object is thrown. + if (!stack) { + try { + throw new Error(); + } catch (e) { + stack = e.stack; + } + } + + // 'Error.stack' is not supported in all browsers/versions + if (!stack) { + return "(Stack trace unavailable)"; + } + + var lines = stack.split("\n"); + + // Create a pattern to match stack frames originating within testharness.js. These include the + // script URL, followed by the line/col (e.g., '/resources/testharness.js:120:21'). + // Escape the URL per http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript + // in case it contains RegExp characters. + var script_url = get_script_url(); + var re_text = script_url ? script_url.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&') : "\\btestharness.js"; + var re = new RegExp(re_text + ":\\d+:\\d+"); + + // Some browsers include a preamble that specifies the type of the error object. Skip this by + // advancing until we find the first stack frame originating from testharness.js. + var i = 0; + while (!re.test(lines[i]) && i < lines.length) { + i++; + } + + // Then skip the top frames originating from testharness.js to begin the stack at the test code. + while (re.test(lines[i]) && i < lines.length) { + i++; + } + + // Paranoid check that we didn't skip all frames. If so, return the original stack unmodified. + if (i >= lines.length) { + return stack; + } + + return lines.slice(i).join("\n"); + } + + function make_message(function_name, description, error, substitutions) + { + for (var p in substitutions) { + if (substitutions.hasOwnProperty(p)) { + substitutions[p] = format_value(substitutions[p]); + } + } + var node_form = substitute(["{text}", "${function_name}: ${description}" + error], + merge({function_name:function_name, + description:(description?description + " ":"")}, + substitutions)); + return node_form.slice(1).join(""); + } + + function filter(array, callable, thisObj) { + var rv = []; + for (var i = 0; i < array.length; i++) { + if (array.hasOwnProperty(i)) { + var pass = callable.call(thisObj, array[i], i, array); + if (pass) { + rv.push(array[i]); + } + } + } + return rv; + } + + function map(array, callable, thisObj) + { + var rv = []; + rv.length = array.length; + for (var i = 0; i < array.length; i++) { + if (array.hasOwnProperty(i)) { + rv[i] = callable.call(thisObj, array[i], i, array); + } + } + return rv; + } + + function extend(array, items) + { + Array.prototype.push.apply(array, items); + } + + function forEach(array, callback, thisObj) + { + for (var i = 0; i < array.length; i++) { + if (array.hasOwnProperty(i)) { + callback.call(thisObj, array[i], i, array); + } + } + } + + /** + * Immediately invoke a "iteratee" function with a series of values in + * parallel and invoke a final "done" function when all of the "iteratee" + * invocations have signaled completion. + * + * If all callbacks complete synchronously (or if no callbacks are + * specified), the `done_callback` will be invoked synchronously. It is the + * responsibility of the caller to ensure asynchronicity in cases where + * that is desired. + * + * @param {array} value Zero or more values to use in the invocation of + * `iter_callback` + * @param {function} iter_callback A function that will be invoked once for + * each of the provided `values`. Two + * arguments will be available in each + * invocation: the value from `values` and + * a function that must be invoked to + * signal completion + * @param {function} done_callback A function that will be invoked after + * all operations initiated by the + * `iter_callback` function have signaled + * completion + */ + function all_async(values, iter_callback, done_callback) + { + var remaining = values.length; + + if (remaining === 0) { + done_callback(); + } + + forEach(values, + function(element) { + var invoked = false; + var elDone = function() { + if (invoked) { + return; + } + + invoked = true; + remaining -= 1; + + if (remaining === 0) { + done_callback(); + } + }; + + iter_callback(element, elDone); + }); + } + + function merge(a,b) + { + var rv = {}; + var p; + for (p in a) { + rv[p] = a[p]; + } + for (p in b) { + rv[p] = b[p]; + } + return rv; + } + + function expose(object, name) + { + var components = name.split("."); + var target = global_scope; + for (var i = 0; i < components.length - 1; i++) { + if (!(components[i] in target)) { + target[components[i]] = {}; + } + target = target[components[i]]; + } + target[components[components.length - 1]] = object; + } + + function is_same_origin(w) { + try { + 'random_prop' in w; + return true; + } catch (e) { + return false; + } + } + + /** Returns the 'src' URL of the first +``` + +## Documentation + +The API to WebIDL2 is trivial: you parse a string of WebIDL and it returns a syntax tree. + +### Parsing + +In Node, that happens with: + +```JS +var WebIDL2 = require("webidl2"); +var tree = WebIDL2.parse("string of WebIDL"); +``` + +In the browser: +```HTML + + +``` + +### Errors + +When there is a syntax error in the WebIDL, it throws an exception object with the following +properties: + +* `message`: the error message +* `line`: the line at which the error occurred. +* `input`: a short peek at the text at the point where the error happened +* `tokens`: the five tokens at the point of error, as understood by the tokeniser + (this is the same content as `input`, but seen from the tokeniser's point of view) + +The exception also has a `toString()` method that hopefully should produce a decent +error message. + +### AST (Abstract Syntax Tree) + +The `parse()` method returns a tree object representing the parse tree of the IDL. +Comment and white space are not represented in the AST. + +The root of this object is always an array of definitions (where definitions are +any of interfaces, dictionaries, callbacks, etc. — anything that can occur at the root +of the IDL). + +### IDL Type + +This structure is used in many other places (operation return types, argument types, etc.). +It captures a WebIDL type with a number of options. Types look like this and are typically +attached to a field called `idlType`: + +```JS +{ + "type": "attribute-type", + "generic": null, + "idlType": "unsigned short", + "nullable": false, + "union": false, + "extAttrs": [...] +} +``` + +Where the fields are as follows: + +* `type`: String indicating where this type is used. Can be `null` if not applicable. +* `generic`: String indicating the generic type (e.g. "Promise", "sequence"). `null` + otherwise. +* `idlType`: Can be different things depending on context. In most cases, this will just + be a string with the type name. But the reason this field isn't called "typeName" is + because it can take more complex values. If the type is a union, then this contains an + array of the types it unites. If it is a generic type, it contains the IDL type + description for the type in the sequence, the eventual value of the promise, etc. +* `nullable`: Boolean indicating whether this is nullable or not. +* `union`: Boolean indicating whether this is a union type or not. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Interface + +Interfaces look like this: + +```JS +{ + "type": "interface", + "name": "Animal", + "partial": false, + "members": [...], + "inheritance": null, + "extAttrs": [...] +}, { + "type": "interface", + "name": "Human", + "partial": false, + "members": [...], + "inheritance": "Animal", + "extAttrs": [...] +} +``` + +The fields are as follows: + +* `type`: Always "interface". +* `name`: The name of the interface. +* `partial`: A boolean indicating whether it's a partial interface. +* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none. +* `inheritance`: A string giving the name of an interface this one inherits from, `null` otherwise. + **NOTE**: In v1 this was an array, but multiple inheritance is no longer supported so this didn't make + sense. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Interface mixins + +Interfaces mixins look like this: + +```JS +{ + "type": "interface mixin", + "name": "Animal", + "partial": false, + "members": [...], + "extAttrs": [...] +}, { + "type": "interface mixin", + "name": "Human", + "partial": false, + "members": [...], + "extAttrs": [...] +} +``` + +The fields are as follows: + +* `type`: Always "interface mixin". +* `name`: The name of the interface mixin. +* `partial`: A boolean indicating whether it's a partial interface mixin. +* `members`: An array of interface members (attributes, operations, etc.). Empty if there are none. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Namespace + +Namespaces look like this: + +```JS +{ + "type": "namespace", + "name": "Console", + "partial": false, + "members": [...], + "extAttrs": [...] +} +``` + +The fields are as follows: + +* `type`: Always "namespace". +* `name`: The name of the namespace. +* `partial`: A boolean indicating whether it's a partial namespace. +* `members`: An array of namespace members (attributes and operations). Empty if there are none. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Callback Interfaces + +These are captured by the same structure as [Interfaces](#interface) except that +their `type` field is "callback interface". + +### Callback + +A callback looks like this: + +```JS +{ + "type": "callback", + "name": "AsyncOperationCallback", + "idlType": { + "type": "return-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "void", + "extAttrs": [] + }, + "arguments": [...], + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "callback". +* `name`: The name of the callback. +* `idlType`: An [IDL Type](#idl-type) describing what the callback returns. +* `arguments`: A list of [arguments](#arguments), as in function paramters. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Dictionary + +A dictionary looks like this: + +```JS +{ + "type": "dictionary", + "name": "PaintOptions", + "partial": false, + "members": [{ + "type": "field", + "name": "fillPattern", + "required": false, + "idlType": { + "type": "dictionary-type", + "sequence": false, + "generic": null, + "nullable": true, + "union": false, + "idlType": "DOMString", + "extAttrs": [...] + }, + "extAttrs": [], + "default": { + "type": "string", + "value": "black" + } + }], + "inheritance": null, + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "dictionary". +* `name`: The dictionary name. +* `partial`: Boolean indicating whether it's a partial dictionary. +* `members`: An array of members (see below). +* `inheritance`: A string indicating which dictionary is being inherited from, `null` otherwise. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +All the members are fields as follows: + +* `type`: Always "field". +* `name`: The name of the field. +* `required`: Boolean indicating whether this is a [required](https://heycam.github.io/webidl/#required-dictionary-member) field. +* `idlType`: An [IDL Type](#idl-type) describing what field's type. +* `extAttrs`: A list of [extended attributes](#extended-attributes). +* `default`: A [default value](#default-and-const-values), absent if there is none. + +### Enum + +An enum looks like this: + +```JS +{ + "type": "enum", + "name": "MealType", + "values": [ + { "type": "string", "value": "rice" }, + { "type": "string", "value": "noodles" }, + { "type": "string", "value": "other" } + ], + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "enum". +* `name`: The enum's name. +* `values`: An array of values. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Typedef + +A typedef looks like this: + +```JS +{ + "type": "typedef", + "idlType": { + "type": "typedef-type", + "sequence": true, + "generic": "sequence", + "nullable": false, + "union": false, + "idlType": { + "type": "typedef-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "Point", + "extAttrs": [...] + }, + "extAttrs": [...] + }, + "name": "PointSequence", + "extAttrs": [] +} +``` + + +The fields are as follows: + +* `type`: Always "typedef". +* `name`: The typedef's name. +* `idlType`: An [IDL Type](#idl-type) describing what typedef's type. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Implements + +An implements definition looks like this: + +```JS +{ + "type": "implements", + "target": "Node", + "implements": "EventTarget", + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "implements". +* `target`: The interface that implements another. +* `implements`: The interface that is being implemented by the target. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Includes + +An includes definition looks like this: + +```JS +{ + "type": "includes", + "target": "Node", + "includes": "EventTarget", + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "includes". +* `target`: The interface that includes an interface mixin. +* `includes`: The interface mixin that is being included by the target. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Operation Member + +An operation looks like this: +```JS +{ + "type": "operation", + "getter": false, + "setter": false, + "deleter": false, + "static": false, + "stringifier": false, + "idlType": { + "type": "return-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "void", + "extAttrs": [] + }, + "name": "intersection", + "arguments": [{ + "optional": false, + "variadic": true, + "extAttrs": [], + "idlType": { + "type": "argument-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "long", + "extAttrs": [...] + }, + "name": "ints" + }], + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "operation". +* `getter`: True if a getter operation. +* `setter`: True if a setter operation. +* `deleter`: True if a deleter operation. +* `static`: True if a static operation. +* `stringifier`: True if a stringifier operation. +* `idlType`: An [IDL Type](#idl-type) of what the operation returns. If a stringifier, may be absent. +* `name`: The name of the operation. If a stringifier, may be `null`. +* `arguments`: An array of [arguments](#arguments) for the operation. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Attribute Member + +An attribute member looks like this: + +```JS +{ + "type": "attribute", + "static": false, + "stringifier": false, + "inherit": false, + "readonly": false, + "idlType": { + "type": "attribute-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "RegExp", + "extAttrs": [...] + }, + "name": "regexp", + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "attribute". +* `name`: The attribute's name. +* `static`: True if it's a static attribute. +* `stringifier`: True if it's a stringifier attribute. +* `inherit`: True if it's an inherit attribute. +* `readonly`: True if it's a read-only attribute. +* `idlType`: An [IDL Type](#idl-type) for the attribute. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Constant Member + +A constant member looks like this: + +```JS +{ + "type": "const", + "nullable": false, + "idlType": { + "type": "const-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "boolean" + "extAttrs": [] + }, + "name": "DEBUG", + "value": { + "type": "boolean", + "value": false + }, + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always "const". +* `nullable`: Whether its type is nullable. +* `idlType`: An [IDL Type](#idl-type) of the constant that represents a simple type, the type name. +* `name`: The name of the constant. +* `value`: The constant value as described by [Const Values](#default-and-const-values) +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Arguments + +The arguments (e.g. for an operation) look like this: + +```JS +{ + "arguments": [{ + "optional": false, + "variadic": true, + "extAttrs": [], + "idlType": { + "type": "argument-type", + "sequence": false, + "generic": null, + "nullable": false, + "union": false, + "idlType": "long", + "extAttrs": [...] + }, + "name": "ints" + }] +} +``` + +The fields are as follows: + +* `optional`: True if the argument is optional. +* `variadic`: True if the argument is variadic. +* `idlType`: An [IDL Type](#idl-type) describing the type of the argument. +* `name`: The argument's name. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + +### Extended Attributes + +Extended attributes are arrays of items that look like this: + +```JS +{ + "extAttrs": [{ + "name": "TreatNullAs", + "arguments": null, + "type": "extended-attribute", + "rhs": { + "type": "identifier", + "value": "EmptyString" + } + }] +} +``` + +The fields are as follows: + +* `name`: The extended attribute's name. +* `arguments`: If the extended attribute takes arguments (e.g. `[Foo()]`) or if + its right-hand side does (e.g. `[NamedConstructor=Name(DOMString blah)]`) they + are listed here. Note that an empty arguments list will produce an empty array, + whereas the lack thereof will yield a `null`. If there is an `rhs` field then + they are the right-hand side's arguments, otherwise they apply to the extended + attribute directly. +* `type`: Always `"extended-attribute"`. +* `rhs`: If there is a right-hand side, this will capture its `type` (which can be + "identifier" or "identifier-list") and its `value`. + +### Default and Const Values + +Dictionary fields and operation arguments can take default values, and constants take +values, all of which have the following fields: + +* `type`: One of string, number, boolean, null, Infinity, NaN, or sequence. + +For string, number, boolean, and sequence: + +* `value`: The value of the given type, as a string. For sequence, the only possible value is `[]`. + +For Infinity: + +* `negative`: Boolean indicating whether this is negative Infinity or not. + +### `iterable<>`, `legacyiterable<>`, `maplike<>`, `setlike<>` declarations + +These appear as members of interfaces that look like this: + +```JS +{ + "type": "maplike", // or "legacyiterable" / "iterable" / "setlike" + "idlType": /* One or two types */ , + "readonly": false, // only for maplike and setlike + "extAttrs": [] +} +``` + +The fields are as follows: + +* `type`: Always one of "iterable", "legacyiterable", "maplike" or "setlike". +* `idlType`: An array with one or more [IDL Types](#idl-type) representing the declared type arguments. +* `readonly`: Whether the maplike or setlike is declared as read only. +* `extAttrs`: A list of [extended attributes](#extended-attributes). + + +## Testing + +### Running + +The test runs with mocha and expect.js. Normally, running mocha in the root directory +should be enough once you're set up. + +### Coverage + +Current test coverage, as documented in `coverage.html`, is 95%. You can run your own +coverage analysis with: + +```Bash +jscoverage lib lib-cov +``` + +That will create the lib-cov directory with instrumented code; the test suite knows +to use that if needed. You can then run the tests with: + +```Bash +JSCOV=1 mocha --reporter html-cov > coverage.html +``` + +Note that I've been getting weirdly overescaped results from the html-cov reporter, +so you might wish to try this instead: + +```Bash +JSCOV=1 mocha --reporter html-cov | sed "s/<//g" | sed "s/"/\"/g" > coverage.html +``` +### Browser tests + +In order to test in the browser, get inside `test/web` and run `make-web-tests.js`. This +will generate a `browser-tests.html` file that you can open in a browser. As of this +writing tests pass in the latest Firefox, Chrome, Opera, and Safari. Testing on IE +and older versions will happen progressively. diff --git a/test/fixtures/wpt/resources/webidl2/checker/index.html b/test/fixtures/wpt/resources/webidl2/checker/index.html new file mode 100644 index 00000000000000..9897d8572f22a0 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/checker/index.html @@ -0,0 +1,55 @@ + + + +WebIDL 2 Checker + + + + + + +

WebIDL Checker

+

This is an online checker for WebIDL built on the webidl2.js project.

+

Enter your WebIDL to check below:

+ +
+ +

Validation results:

+ +

Parser output:

+ +
+Pretty Print + + diff --git a/test/fixtures/wpt/resources/webidl2/coverage.html b/test/fixtures/wpt/resources/webidl2/coverage.html new file mode 100644 index 00000000000000..46e7ed324ec2c8 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/coverage.html @@ -0,0 +1,341 @@ +Coverage +

Coverage

95%
572
548
24

webidl2.js

95%
572
548
24
LineHitsSource
1
2
31(function () {
41 var tokenise = function (str) {
547 var tokens = []
6 , re = {
7 "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/
8 , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/
9 , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/
10 , "string": /^"[^"]*"/
11 , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/
12 , "other": /^[^\t\n\r 0-9A-Z_a-z]/
13 }
14 , types = []
15 ;
16329 for (var k in re) types.push(k);
1747 while (str.length > 0) {
182914 var matched = false;
192914 for (var i = 0, n = types.length; i < n; i++) {
2013325 var type = types[i];
2113325 str = str.replace(re[type], function (tok) {
222914 tokens.push({ type: type, value: tok });
232914 matched = true;
242914 return "";
25 });
2616239 if (matched) break;
27 }
285828 if (matched) continue;
290 throw new Error("Token stream not progressing");
30 }
3147 return tokens;
32 };
33
341 var parse = function (tokens) {
3547 var line = 1;
3647 tokens = tokens.slice();
37
3847 var FLOAT = "float"
39 , INT = "integer"
40 , ID = "identifier"
41 , STR = "string"
42 , OTHER = "other"
43 ;
44
4547 var WebIDLParseError = function (str, line, input, tokens) {
460 this.message = str;
470 this.line = line;
480 this.input = input;
490 this.tokens = tokens;
50 };
5147 WebIDLParseError.prototype.toString = function () {
520 return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" +
53 JSON.stringify(this.tokens, null, 4);
54 };
55
5647 var error = function (str) {
570 var tok = "", numTokens = 0, maxTokens = 5;
580 while (numTokens < maxTokens && tokens.length > numTokens) {
590 tok += tokens[numTokens].value;
600 numTokens++;
61 }
620 throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5));
63 };
64
6547 var last_token = null;
66
6747 var consume = function (type, value) {
688778 if (!tokens.length || tokens[0].type !== type) return;
695470 if (typeof value === "undefined" || tokens[0].value === value) {
701738 last_token = tokens.shift();
711738 return last_token;
72 }
73 };
74
7547 var ws = function () {
766961 if (!tokens.length) return;
77 // console.log("tokens.length", tokens.length, tokens[0]);
786115 if (tokens[0].type === "whitespace") {
791172 var t = tokens.shift();
802294 t.value.replace(/\n/g, function (m) { line++; return m; });
811172 return t;
82 }
83 };
84
8547 var all_ws = function () {
865366 var t = { type: "whitespace", value: "" };
875366 while (true) {
886538 var w = ws();
8911904 if (!w) break;
901172 t.value += w.value;
91 }
926538 if (t.value.length > 0) return t;
93 };
94
9547 var integer_type = function () {
96273 var ret = "";
97273 all_ws();
98312 if (consume(ID, "unsigned")) ret = "unsigned ";
99273 all_ws();
100287 if (consume(ID, "short")) return ret + "short";
101259 if (consume(ID, "long")) {
10241 ret += "long";
10341 all_ws();
10443 if (consume(ID, "long")) return ret + " long";
10539 return ret;
106 }
107218 if (ret) error("Failed to parse integer type");
108 };
109
11047 var float_type = function () {
111218 var ret = "";
112218 all_ws();
113222 if (consume(ID, "unrestricted")) ret = "unrestricted ";
114218 all_ws();
115257 if (consume(ID, "float")) return ret + "float";
116182 if (consume(ID, "double")) return ret + "double";
117176 if (ret) error("Failed to parse float type");
118 };
119
12047 var primitive_type = function () {
121273 var num_type = integer_type() || float_type();
122370 if (num_type) return num_type;
123176 all_ws();
124186 if (consume(ID, "boolean")) return "boolean";
125167 if (consume(ID, "byte")) return "byte";
126168 if (consume(ID, "octet")) return "octet";
127 };
128
12947 var const_value = function () {
13017 if (consume(ID, "true")) return true;
13119 if (consume(ID, "false")) return false;
13217 if (consume(ID, "null")) return null;
13314 if (consume(ID, "Infinity")) return Infinity;
13413 if (consume(ID, "NaN")) return NaN;
13511 var ret = consume(FLOAT) || consume(INT);
13619 if (ret) return 1 * ret.value;
1373 var tok = consume(OTHER, "-");
1383 if (tok) {
1392 if (consume(ID, "Infinity")) return -Infinity;
1400 else tokens.unshift(tok);
141 }
142 };
143
14447 var type_suffix = function (obj) {
145249 while (true) {
146263 all_ws();
147263 if (consume(OTHER, "?")) {
14811 if (obj.nullable) error("Can't nullable more than once");
14911 obj.nullable = true;
150 }
151252 else if (consume(OTHER, "[")) {
1523 all_ws();
1533 consume(OTHER, "]") || error("Unterminated array type");
1545 if (!obj.array) obj.array = 1;
1551 else obj.array++;
156 }
157249 else return;
158 }
159 };
160
16147 var single_type = function () {
162261 var prim = primitive_type()
163 , ret = { sequence: false, nullable: false, array: false, union: false }
164 ;
165261 if (prim) {
16699 ret.idlType = prim;
167 }
168162 else if (consume(ID, "sequence")) {
1694 all_ws();
1704 if (!consume(OTHER, "<")) {
1710 ret.idlType = "sequence";
172 }
173 else {
1744 ret.sequence = true;
1754 ret.idlType = type() || error("Error parsing sequence type");
1764 all_ws();
1774 if (!consume(OTHER, ">")) error("Unterminated sequence");
1784 all_ws();
1795 if (consume(OTHER, "?")) ret.nullable = true;
1804 return ret;
181 }
182 }
183 else {
184158 var name = consume(ID);
185169 if (!name) return;
186147 ret.idlType = name.value;
187 }
188246 type_suffix(ret);
189246 if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable");
190246 return ret;
191 };
192
19347 var union_type = function () {
19411 all_ws();
19519 if (!consume(OTHER, "(")) return;
1963 var ret = { sequence: false, nullable: false, array: false, union: true, idlType: [] };
1973 var fst = type() || error("Union type with no content");
1983 ret.idlType.push(fst);
1993 while (true) {
2007 all_ws();
20110 if (!consume(ID, "or")) break;
2024 var typ = type() || error("No type after 'or' in union type");
2034 ret.idlType.push(typ);
204 }
2053 if (!consume(OTHER, ")")) error("Unterminated union type");
2063 type_suffix(ret);
2073 return ret;
208 };
209
21047 var type = function () {
211261 return single_type() || union_type();
212 };
213
21447 var argument = function () {
21579 var ret = { optional: false, variadic: false };
21679 ret.extAttrs = extended_attrs();
21779 all_ws();
21879 if (consume(ID, "optional")) {
2192 ret.optional = true;
2202 all_ws();
221 }
22279 ret.type = type();
22387 if (!ret.type) return;
22471 if (!ret.optional) {
22569 all_ws();
22669 if (tokens.length >= 3 &&
227 tokens[0].type === "other" && tokens[0].value === "." &&
228 tokens[1].type === "other" && tokens[1].value === "." &&
229 tokens[2].type === "other" && tokens[2].value === "."
230 ) {
2314 tokens.shift();
2324 tokens.shift();
2334 tokens.shift();
2344 ret.variadic = true;
235 }
236 }
23771 all_ws();
23871 var name = consume(ID) || error("No name in argument");
23971 ret.name = name.value;
24071 if (ret.optional) {
2412 all_ws();
2422 ret["default"] = default_();
243 }
24471 return ret;
245 };
246
24747 var argument_list = function () {
24859 var arg = argument(), ret = [];
24967 if (!arg) return ret;
25051 ret.push(arg);
25151 while (true) {
25271 all_ws();
253122 if (!consume(OTHER, ",")) return ret;
25420 all_ws();
25520 var nxt = argument() || error("Trailing comma in arguments list");
25620 ret.push(nxt);
257 }
258 };
259
26047 var simple_extended_attr = function () {
26117 all_ws();
26217 var name = consume(ID);
26317 if (!name) return;
26417 var ret = {
265 name: name.value
266 , "arguments": null
267 };
26817 all_ws();
26917 var eq = consume(OTHER, "=");
27017 if (eq) {
2715 all_ws();
2725 ret.rhs = consume(ID);
2735 if (!ret.rhs) return error("No right hand side to extended attribute assignment");
274 }
27517 all_ws();
27617 if (consume(OTHER, "(")) {
2772 ret["arguments"] = argument_list();
2782 all_ws();
2792 consume(OTHER, ")") || error("Unclosed argument in extended attribute");
280 }
28117 return ret;
282 };
283
284 // Note: we parse something simpler than the official syntax. It's all that ever
285 // seems to be used
28647 var extended_attrs = function () {
287415 var eas = [];
288415 all_ws();
289815 if (!consume(OTHER, "[")) return eas;
29015 eas[0] = simple_extended_attr() || error("Extended attribute with not content");
29115 all_ws();
29215 while (consume(OTHER, ",")) {
2932 all_ws();
2942 eas.push(simple_extended_attr() || error("Trailing comma in extended attribute"));
2952 all_ws();
296 }
29715 consume(OTHER, "]") || error("No end of extended attribute");
29815 return eas;
299 };
300
30147 var default_ = function () {
30211 all_ws();
30311 if (consume(OTHER, "=")) {
3045 all_ws();
3055 var def = const_value();
3065 if (typeof def !== "undefined") {
3073 return def;
308 }
309 else {
3102 var str = consume(STR) || error("No value for default");
3112 return str;
312 }
313 }
314 };
315
31647 var const_ = function () {
317180 all_ws();
318348 if (!consume(ID, "const")) return;
31912 var ret = { type: "const", nullable: false };
32012 all_ws();
32112 var typ = primitive_type();
32212 if (!typ) {
3230 typ = consume(ID) || error("No type for const");
3240 typ = typ.value;
325 }
32612 ret.idlType = typ;
32712 all_ws();
32812 if (consume(OTHER, "?")) {
3291 ret.nullable = true;
3301 all_ws();
331 }
33212 var name = consume(ID) || error("No name for const");
33312 ret.name = name.value;
33412 all_ws();
33512 consume(OTHER, "=") || error("No value assignment for const");
33612 all_ws();
33712 var cnt = const_value();
33824 if (typeof cnt !== "undefined") ret.value = cnt;
3390 else error("No value for const");
34012 all_ws();
34112 consume(OTHER, ";") || error("Unterminated const");
34212 return ret;
343 };
344
34547 var inheritance = function () {
34689 all_ws();
34789 if (consume(OTHER, ":")) {
3489 all_ws();
3499 var inh = consume(ID) || error ("No type in inheritance");
3509 return inh.value;
351 }
352 };
353
35447 var operation_rest = function (ret) {
35556 all_ws();
35657 if (!ret) ret = {};
35756 var name = consume(ID);
35856 ret.name = name ? name.value : null;
35956 all_ws();
36056 consume(OTHER, "(") || error("Invalid operation");
36156 ret["arguments"] = argument_list();
36256 all_ws();
36356 consume(OTHER, ")") || error("Unterminated operation");
36456 all_ws();
36556 consume(OTHER, ";") || error("Unterminated operation");
36656 return ret;
367 };
368
36947 var callback = function () {
370144 all_ws();
371144 var ret;
372286 if (!consume(ID, "callback")) return;
3732 all_ws();
3742 var tok = consume(ID, "interface");
3752 if (tok) {
3761 tokens.unshift(tok);
3771 ret = interface_();
3781 ret.type = "callback interface";
3791 return ret;
380 }
3811 var name = consume(ID) || error("No name for callback");
3821 ret = { type: "callback", name: name.value };
3831 all_ws();
3841 consume(OTHER, "=") || error("No assignment in callback");
3851 all_ws();
3861 ret.idlType = return_type();
3871 all_ws();
3881 consume(OTHER, "(") || error("No arguments in callback");
3891 ret["arguments"] = argument_list();
3901 all_ws();
3911 consume(OTHER, ")") || error("Unterminated callback");
3921 all_ws();
3931 consume(OTHER, ";") || error("Unterminated callback");
3941 return ret;
395 };
396
39747 var attribute = function () {
398154 all_ws();
399154 var grabbed = []
400 , ret = {
401 type: "attribute"
402 , "static": false
403 , stringifier: false
404 , inherit: false
405 , readonly: false
406 };
407154 if (consume(ID, "static")) {
4082 ret["static"] = true;
4092 grabbed.push(last_token);
410 }
411152 else if (consume(ID, "stringifier")) {
4124 ret.stringifier = true;
4134 grabbed.push(last_token);
414 }
415154 var w = all_ws();
416159 if (w) grabbed.push(w);
417154 if (consume(ID, "inherit")) {
4181 if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit");
4191 ret.inherit = true;
4201 grabbed.push(last_token);
4211 var w = all_ws();
4222 if (w) grabbed.push(w);
423 }
424154 if (consume(ID, "readonly")) {
42532 ret.readonly = true;
42632 grabbed.push(last_token);
42732 var w = all_ws();
42864 if (w) grabbed.push(w);
429 }
430154 if (!consume(ID, "attribute")) {
43160 tokens = grabbed.concat(tokens);
43260 return;
433 }
43494 all_ws();
43594 ret.idlType = type() || error("No type in attribute");
43694 if (ret.idlType.sequence) error("Attributes cannot accept sequence types");
43794 all_ws();
43894 var name = consume(ID) || error("No name in attribute");
43994 ret.name = name.value;
44094 all_ws();
44194 consume(OTHER, ";") || error("Unterminated attribute");
44294 return ret;
443 };
444
44547 var return_type = function () {
44661 var typ = type();
44761 if (!typ) {
4480 if (consume(ID, "void")) {
4490 return "void";
450 }
4510 else error("No return type");
452 }
45361 return typ;
454 };
455
45647 var operation = function () {
45760 all_ws();
45860 var ret = {
459 type: "operation"
460 , getter: false
461 , setter: false
462 , creator: false
463 , deleter: false
464 , legacycaller: false
465 , "static": false
466 , stringifier: false
467 };
46860 while (true) {
46978 all_ws();
47087 if (consume(ID, "getter")) ret.getter = true;
47174 else if (consume(ID, "setter")) ret.setter = true;
47265 else if (consume(ID, "creator")) ret.creator = true;
47365 else if (consume(ID, "deleter")) ret.deleter = true;
47462 else if (consume(ID, "legacycaller")) ret.legacycaller = true;
47560 else break;
476 }
47760 if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
47817 all_ws();
47917 ret.idlType = return_type();
48017 operation_rest(ret);
48117 return ret;
482 }
48343 if (consume(ID, "static")) {
4841 ret["static"] = true;
4851 ret.idlType = return_type();
4861 operation_rest(ret);
4871 return ret;
488 }
48942 else if (consume(ID, "stringifier")) {
4903 ret.stringifier = true;
4913 all_ws();
4924 if (consume(OTHER, ";")) return ret;
4932 ret.idlType = return_type();
4942 operation_rest(ret);
4952 return ret;
496 }
49739 ret.idlType = return_type();
49839 all_ws();
49939 if (consume(ID, "iterator")) {
5004 all_ws();
5014 ret.type = "iterator";
5024 if (consume(ID, "object")) {
5031 ret.iteratorObject = "object";
504 }
5053 else if (consume(OTHER, "=")) {
5062 all_ws();
5072 var name = consume(ID) || error("No right hand side in iterator");
5082 ret.iteratorObject = name.value;
509 }
5104 all_ws();
5114 consume(OTHER, ";") || error("Unterminated iterator");
5124 return ret;
513 }
514 else {
51535 operation_rest(ret);
51635 return ret;
517 }
518 };
519
52047 var identifiers = function (arr) {
5215 while (true) {
52211 all_ws();
52311 if (consume(OTHER, ",")) {
5246 all_ws();
5256 var name = consume(ID) || error("Trailing comma in identifiers list");
5266 arr.push(name.value);
527 }
5285 else break;
529 }
530 };
531
53247 var serialiser = function () {
533164 all_ws();
534318 if (!consume(ID, "serializer")) return;
53510 var ret = { type: "serializer" };
53610 all_ws();
53710 if (consume(OTHER, "=")) {
5388 all_ws();
5398 if (consume(OTHER, "{")) {
5405 ret.patternMap = true;
5415 all_ws();
5425 var id = consume(ID);
5435 if (id && id.value === "getter") {
5441 ret.names = ["getter"];
545 }
5464 else if (id && id.value === "inherit") {
5472 ret.names = ["inherit"];
5482 identifiers(ret.names);
549 }
5502 else if (id) {
5512 ret.names = [id.value];
5522 identifiers(ret.names);
553 }
554 else {
5550 ret.names = [];
556 }
5575 all_ws();
5585 consume(OTHER, "}") || error("Unterminated serializer pattern map");
559 }
5603 else if (consume(OTHER, "[")) {
5612 ret.patternList = true;
5622 all_ws();
5632 var id = consume(ID);
5642 if (id && id.value === "getter") {
5651 ret.names = ["getter"];
566 }
5671 else if (id) {
5681 ret.names = [id.value];
5691 identifiers(ret.names);
570 }
571 else {
5720 ret.names = [];
573 }
5742 all_ws();
5752 consume(OTHER, "]") || error("Unterminated serializer pattern list");
576 }
577 else {
5781 var name = consume(ID) || error("Invalid serializer");
5791 ret.name = name.value;
580 }
5818 all_ws();
5828 consume(OTHER, ";") || error("Unterminated serializer");
5838 return ret;
584 }
5852 else if (consume(OTHER, ";")) {
586 // noop, just parsing
587 }
588 else {
5891 ret.idlType = return_type();
5901 all_ws();
5911 ret.operation = operation_rest();
592 }
5932 return ret;
594 };
595
59647 var interface_ = function (isPartial) {
597144 all_ws();
598210 if (!consume(ID, "interface")) return;
59978 all_ws();
60078 var name = consume(ID) || error("No name for interface");
60178 var ret = {
602 type: "interface"
603 , name: name.value
604 , partial: false
605 , members: []
606 };
607155 if (!isPartial) ret.inheritance = inheritance() || null;
60878 all_ws();
60978 consume(OTHER, "{") || error("Bodyless interface");
61078 while (true) {
611251 all_ws();
612251 if (consume(OTHER, "}")) {
61378 all_ws();
61478 consume(OTHER, ";") || error("Missing semicolon after interface");
61578 return ret;
616 }
617173 var ea = extended_attrs();
618173 all_ws();
619173 var cnt = const_();
620173 if (cnt) {
6219 cnt.extAttrs = ea;
6229 ret.members.push(cnt);
6239 continue;
624 }
625164 var mem = serialiser() || attribute() || operation() || error("Unknown member");
626164 mem.extAttrs = ea;
627164 ret.members.push(mem);
628 }
629 };
630
63147 var partial = function () {
63266 all_ws();
633130 if (!consume(ID, "partial")) return;
6342 var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything");
6352 thing.partial = true;
6362 return thing;
637 };
638
63947 var dictionary = function (isPartial) {
64066 all_ws();
641128 if (!consume(ID, "dictionary")) return;
6424 all_ws();
6434 var name = consume(ID) || error("No name for dictionary");
6444 var ret = {
645 type: "dictionary"
646 , name: name.value
647 , partial: false
648 , members: []
649 };
6507 if (!isPartial) ret.inheritance = inheritance() || null;
6514 all_ws();
6524 consume(OTHER, "{") || error("Bodyless dictionary");
6534 while (true) {
65413 all_ws();
65513 if (consume(OTHER, "}")) {
6564 all_ws();
6574 consume(OTHER, ";") || error("Missing semicolon after dictionary");
6584 return ret;
659 }
6609 var ea = extended_attrs();
6619 all_ws();
6629 var typ = type() || error("No type for dictionary member");
6639 all_ws();
6649 var name = consume(ID) || error("No name for dictionary member");
6659 ret.members.push({
666 type: "field"
667 , name: name.value
668 , idlType: typ
669 , extAttrs: ea
670 , "default": default_()
671 });
6729 all_ws();
6739 consume(OTHER, ";") || error("Unterminated dictionary member");
674 }
675 };
676
67747 var exception = function () {
67861 all_ws();
679113 if (!consume(ID, "exception")) return;
6809 all_ws();
6819 var name = consume(ID) || error("No name for exception");
6829 var ret = {
683 type: "exception"
684 , name: name.value
685 , members: []
686 };
6879 ret.inheritance = inheritance() || null;
6889 all_ws();
6899 consume(OTHER, "{") || error("Bodyless exception");
6909 while (true) {
69116 all_ws();
69216 if (consume(OTHER, "}")) {
6939 all_ws();
6949 consume(OTHER, ";") || error("Missing semicolon after exception");
6959 return ret;
696 }
6977 var ea = extended_attrs();
6987 all_ws();
6997 var cnt = const_();
7007 if (cnt) {
7013 cnt.extAttrs = ea;
7023 ret.members.push(cnt);
703 }
704 else {
7054 var typ = type();
7064 all_ws();
7074 var name = consume(ID);
7084 all_ws();
7094 if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body");
7104 ret.members.push({
711 type: "field"
712 , name: name.value
713 , idlType: typ
714 , extAttrs: ea
715 });
716 }
717 }
718 };
719
72047 var enum_ = function () {
72152 all_ws();
722103 if (!consume(ID, "enum")) return;
7231 all_ws();
7241 var name = consume(ID) || error("No name for enum");
7251 var ret = {
726 type: "enum"
727 , name: name.value
728 , values: []
729 };
7301 all_ws();
7311 consume(OTHER, "{") || error("No curly for enum");
7321 var saw_comma = false;
7331 while (true) {
7344 all_ws();
7354 if (consume(OTHER, "}")) {
7361 all_ws();
7371 if (saw_comma) error("Trailing comma in enum");
7381 consume(OTHER, ";") || error("No semicolon after enum");
7391 return ret;
740 }
7413 var val = consume(STR) || error("Unexpected value in enum");
7423 ret.values.push(val.value.replace(/"/g, ""));
7433 all_ws();
7443 if (consume(OTHER, ",")) {
7452 all_ws();
7462 saw_comma = true;
747 }
748 else {
7491 saw_comma = false;
750 }
751 }
752 };
753
75447 var typedef = function () {
75551 all_ws();
75699 if (!consume(ID, "typedef")) return;
7573 var ret = {
758 type: "typedef"
759 };
7603 all_ws();
7613 ret.extAttrs = extended_attrs();
7623 all_ws();
7633 ret.idlType = type() || error("No type in typedef");
7643 all_ws();
7653 var name = consume(ID) || error("No name in typedef");
7663 ret.name = name.value;
7673 all_ws();
7683 consume(OTHER, ";") || error("Unterminated typedef");
7693 return ret;
770 };
771
77247 var implements_ = function () {
77348 all_ws();
77448 var target = consume(ID);
77595 if (!target) return;
7761 var w = all_ws();
7771 if (consume(ID, "implements")) {
7781 var ret = {
779 type: "implements"
780 , target: target.value
781 };
7821 all_ws();
7831 var imp = consume(ID) || error("Incomplete implements statement");
7841 ret["implements"] = imp.value;
7851 all_ws();
7861 consume(OTHER, ";") || error("No terminating ; for implements statement");
7871 return ret;
788 }
789 else {
790 // rollback
7910 tokens.unshift(w);
7920 tokens.unshift(target);
793 }
794 };
795
79647 var definition = function () {
797144 return callback() ||
798 interface_() ||
799 partial() ||
800 dictionary() ||
801 exception() ||
802 enum_() ||
803 typedef() ||
804 implements_()
805 ;
806 };
807
80847 var definitions = function () {
80947 if (!tokens.length) return [];
81047 var defs = [];
81147 while (true) {
812144 var ea = extended_attrs()
813 , def = definition();
814144 if (!def) {
81547 if (ea.length) error("Stray extended attributes");
81647 break;
817 }
81897 def.extAttrs = ea;
81997 defs.push(def);
820 }
82147 return defs;
822 };
82347 var res = definitions();
82447 if (tokens.length) error("Unrecognised tokens");
82547 return res;
826 };
827
8281 var obj = {
829 parse: function (str) {
83047 var tokens = tokenise(str);
831 // console.log(tokens);
83247 return parse(tokens);
833 }
834 };
8351 if (typeof module !== "undefined" && module.exports) {
8361 module.exports = obj;
837 }
838 else {
8390 window.WebIDL2 = obj;
840 }
841}());
diff --git a/test/fixtures/wpt/resources/webidl2/index.js b/test/fixtures/wpt/resources/webidl2/index.js new file mode 100644 index 00000000000000..09f9eb46aa78f4 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/index.js @@ -0,0 +1 @@ +module.exports = require("./lib/webidl2.js"); diff --git a/test/fixtures/wpt/resources/webidl2/lib/webidl2.js b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js new file mode 100644 index 00000000000000..ef519c09df6d6d --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js @@ -0,0 +1,970 @@ +"use strict"; + +(() => { + // These regular expressions use the sticky flag so they will only match at + // the current location (ie. the offset of lastIndex). + const tokenRe = { + // This expression uses a lookahead assertion to catch false matches + // against integers early. + "float": /-?(?=[0-9]*\.|[0-9]+[eE])(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/y, + "integer": /-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/y, + "identifier": /_?[A-Za-z][0-9A-Z_a-z-]*/y, + "string": /"[^"]*"/y, + "whitespace": /[\t\n\r ]+/y, + "comment": /((\/(\/.*|\*([^*]|\*[^\/])*\*\/)[\t\n\r ]*)+)/y, + "other": /[^\t\n\r 0-9A-Za-z]/y + }; + + const stringTypes = [ + "ByteString", + "DOMString", + "USVString" + ]; + + const argumentNameKeywords = [ + "attribute", + "callback", + "const", + "deleter", + "dictionary", + "enum", + "getter", + "includes", + "inherit", + "interface", + "iterable", + "maplike", + "namespace", + "partial", + "required", + "setlike", + "setter", + "static", + "stringifier", + "typedef", + "unrestricted" + ]; + + const nonRegexTerminals = [ + "FrozenArray", + "Infinity", + "NaN", + "Promise", + "boolean", + "byte", + "double", + "false", + "float", + "implements", + "legacyiterable", + "long", + "mixin", + "null", + "octet", + "optional", + "or", + "readonly", + "record", + "sequence", + "short", + "true", + "unsigned", + "void" + ].concat(argumentNameKeywords, stringTypes); + + const punctuations = [ + "(", + ")", + ",", + "-Infinity", + "...", + ":", + ";", + "<", + "=", + ">", + "?", + "[", + "]", + "{", + "}" + ]; + + function tokenise(str) { + const tokens = []; + let lastIndex = 0; + let trivia = ""; + while (lastIndex < str.length) { + const nextChar = str.charAt(lastIndex); + let result = -1; + + if (/[\t\n\r ]/.test(nextChar)) { + result = attemptTokenMatch("whitespace", { noFlushTrivia: true }); + } else if (nextChar === '/') { + result = attemptTokenMatch("comment", { noFlushTrivia: true }); + } + + if (result !== -1) { + trivia += tokens.pop().value; + } else if (/[-0-9.]/.test(nextChar)) { + result = attemptTokenMatch("float"); + if (result === -1) { + result = attemptTokenMatch("integer"); + } + } else if (/[A-Z_a-z]/.test(nextChar)) { + result = attemptTokenMatch("identifier"); + const token = tokens[tokens.length - 1]; + if (result !== -1 && nonRegexTerminals.includes(token.value)) { + token.type = token.value; + } + } else if (nextChar === '"') { + result = attemptTokenMatch("string"); + } + + for (const punctuation of punctuations) { + if (str.startsWith(punctuation, lastIndex)) { + tokens.push({ type: punctuation, value: punctuation, trivia }); + trivia = ""; + lastIndex += punctuation.length; + result = lastIndex; + break; + } + } + + // other as the last try + if (result === -1) { + result = attemptTokenMatch("other"); + } + if (result === -1) { + throw new Error("Token stream not progressing"); + } + lastIndex = result; + } + return tokens; + + function attemptTokenMatch(type, { noFlushTrivia } = {}) { + const re = tokenRe[type]; + re.lastIndex = lastIndex; + const result = re.exec(str); + if (result) { + tokens.push({ type, value: result[0], trivia }); + if (!noFlushTrivia) { + trivia = ""; + } + return re.lastIndex; + } + return -1; + } + } + + class WebIDLParseError { + constructor(str, line, input, tokens) { + this.message = str; + this.line = line; + this.input = input; + this.tokens = tokens; + } + + toString() { + const escapedInput = JSON.stringify(this.input); + const tokens = JSON.stringify(this.tokens, null, 4); + return `${this.message}, line ${this.line} (tokens: ${escapedInput})\n${tokens}`; + } + } + + function parse(tokens) { + let line = 1; + tokens = tokens.slice(); + const names = new Map(); + let current = null; + + const FLOAT = "float"; + const INT = "integer"; + const ID = "identifier"; + const STR = "string"; + const OTHER = "other"; + + const EMPTY_OPERATION = Object.freeze({ + type: "operation", + getter: false, + setter: false, + deleter: false, + static: false, + stringifier: false + }); + + const EMPTY_IDLTYPE = Object.freeze({ + generic: null, + nullable: false, + union: false, + idlType: null, + extAttrs: [] + }); + + function error(str) { + const maxTokens = 5; + const tok = tokens + .slice(consume_position, consume_position + maxTokens) + .map(t => t.trivia + t.value).join(""); + // Count newlines preceding the actual erroneous token + if (tokens.length) { + line += count(tokens[consume_position].trivia, "\n"); + } + + let message; + if (current) { + message = `Got an error during or right after parsing \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`: ${str}` + } + else { + // throwing before any valid definition + message = `Got an error before parsing any named definition: ${str}`; + } + + throw new WebIDLParseError(message, line, tok, tokens.slice(0, maxTokens)); + } + + function sanitize_name(name, type) { + if (names.has(name)) { + error(`The name "${name}" of type "${names.get(name)}" is already seen`); + } + names.set(name, type); + return name; + } + + let consume_position = 0; + + function probe(type) { + return tokens.length > consume_position && tokens[consume_position].type === type; + } + + function consume(...candidates) { + // TODO: use const when Servo updates its JS engine + for (let type of candidates) { + if (!probe(type)) continue; + const token = tokens[consume_position]; + consume_position++; + line += count(token.trivia, "\n"); + return token; + } + } + + function unescape(identifier) { + return identifier.startsWith('_') ? identifier.slice(1) : identifier; + } + + function unconsume(position) { + while (consume_position > position) { + consume_position--; + line -= count(tokens[consume_position].trivia, "\n"); + } + } + + function count(str, char) { + let total = 0; + for (let i = str.indexOf(char); i !== -1; i = str.indexOf(char, i + 1)) { + ++total; + } + return total; + } + + function integer_type() { + let ret = ""; + if (consume("unsigned")) ret = "unsigned "; + if (consume("short")) return ret + "short"; + if (consume("long")) { + ret += "long"; + if (consume("long")) return ret + " long"; + return ret; + } + if (ret) error("Failed to parse integer type"); + } + + function float_type() { + let ret = ""; + if (consume("unrestricted")) ret = "unrestricted "; + if (consume("float")) return ret + "float"; + if (consume("double")) return ret + "double"; + if (ret) error("Failed to parse float type"); + } + + function primitive_type() { + const num_type = integer_type() || float_type(); + if (num_type) return num_type; + if (consume("boolean")) return "boolean"; + if (consume("byte")) return "byte"; + if (consume("octet")) return "octet"; + } + + function const_value() { + if (consume("true")) return { type: "boolean", value: true }; + if (consume("false")) return { type: "boolean", value: false }; + if (consume("null")) return { type: "null" }; + if (consume("Infinity")) return { type: "Infinity", negative: false }; + if (consume("-Infinity")) return { type: "Infinity", negative: true }; + if (consume("NaN")) return { type: "NaN" }; + const ret = consume(FLOAT, INT); + if (ret) return { type: "number", value: ret.value }; + } + + function type_suffix(obj) { + obj.nullable = !!consume("?"); + if (probe("?")) error("Can't nullable more than once"); + } + + function generic_type(typeName) { + const name = consume("FrozenArray", "Promise", "sequence", "record"); + if (!name) { + return; + } + const ret = { generic: name.type }; + consume("<") || error(`No opening bracket after ${name.type}`); + switch (name.type) { + case "Promise": + if (probe("[")) error("Promise type cannot have extended attribute"); + ret.idlType = return_type(typeName); + break; + case "sequence": + case "FrozenArray": + ret.idlType = type_with_extended_attributes(typeName); + break; + case "record": + if (probe("[")) error("Record key cannot have extended attribute"); + ret.idlType = []; + const keyType = consume(...stringTypes); + if (!keyType) error(`Record key must be a string type`); + ret.idlType.push(Object.assign({ type: typeName }, EMPTY_IDLTYPE, { idlType: keyType.value })); + consume(",") || error("Missing comma after record key type"); + const valueType = type_with_extended_attributes(typeName) || error("Error parsing generic type record"); + ret.idlType.push(valueType); + break; + } + if (!ret.idlType) error(`Error parsing generic type ${name.type}`); + consume(">") || error(`Missing closing bracket after ${name.type}`); + if (name.type === "Promise" && probe("?")) { + error("Promise type cannot be nullable"); + } + type_suffix(ret); + return ret; + } + + function single_type(typeName) { + const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE); + const generic = generic_type(typeName); + if (generic) { + return Object.assign(ret, generic); + } + const prim = primitive_type(); + let name; + if (prim) { + ret.idlType = prim; + } else if (name = consume(ID, ...stringTypes)) { + ret.idlType = name.value; + if (probe("<")) error(`Unsupported generic type ${name.value}`); + } else { + return; + } + type_suffix(ret); + if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable"); + return ret; + } + + function union_type(typeName) { + if (!consume("(")) return; + const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE, { union: true, idlType: [] }); + do { + const typ = type_with_extended_attributes() || error("No type after open parenthesis or 'or' in union type"); + ret.idlType.push(typ); + } while (consume("or")); + if (ret.idlType.length < 2) { + error("At least two types are expected in a union type but found less"); + } + if (!consume(")")) error("Unterminated union type"); + type_suffix(ret); + return ret; + } + + function type(typeName) { + return single_type(typeName) || union_type(typeName); + } + + function type_with_extended_attributes(typeName) { + const extAttrs = extended_attrs(); + const ret = single_type(typeName) || union_type(typeName); + if (extAttrs.length && ret) ret.extAttrs = extAttrs; + return ret; + } + + function argument() { + const start_position = consume_position; + const ret = { optional: false, variadic: false, default: null }; + ret.extAttrs = extended_attrs(); + const opt_token = consume("optional"); + if (opt_token) { + ret.optional = true; + } + ret.idlType = type_with_extended_attributes("argument-type"); + if (!ret.idlType) { + unconsume(start_position); + return; + } + if (!ret.optional && consume("...")) { + ret.variadic = true; + } + const name = consume(ID, ...argumentNameKeywords); + if (!name) { + unconsume(start_position); + return; + } + ret.name = unescape(name.value); + ret.escapedName = name.value; + if (ret.optional) { + ret.default = default_() || null; + } + return ret; + } + + function argument_list() { + const ret = []; + const arg = argument(); + if (!arg) return ret; + ret.push(arg); + while (true) { + if (!consume(",")) return ret; + const nxt = argument() || error("Trailing comma in arguments list"); + ret.push(nxt); + } + } + + function simple_extended_attr() { + const name = consume(ID); + if (!name) return; + const ret = { + name: name.value, + arguments: null, + type: "extended-attribute", + rhs: null + }; + const eq = consume("="); + if (eq) { + ret.rhs = consume(ID, FLOAT, INT, STR); + if (ret.rhs) { + // No trivia exposure yet + ret.rhs.trivia = undefined; + } + } + if (consume("(")) { + if (eq && !ret.rhs) { + // [Exposed=(Window,Worker)] + ret.rhs = { + type: "identifier-list", + value: identifiers() + }; + } + else { + // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)] + ret.arguments = argument_list(); + } + consume(")") || error("Unexpected token in extended attribute argument list"); + } + if (eq && !ret.rhs) error("No right hand side to extended attribute assignment"); + return ret; + } + + // Note: we parse something simpler than the official syntax. It's all that ever + // seems to be used + function extended_attrs() { + const eas = []; + if (!consume("[")) return eas; + eas[0] = simple_extended_attr() || error("Extended attribute with not content"); + while (consume(",")) { + eas.push(simple_extended_attr() || error("Trailing comma in extended attribute")); + } + consume("]") || error("No end of extended attribute"); + return eas; + } + + function default_() { + if (consume("=")) { + const def = const_value(); + if (def) { + return def; + } else if (consume("[")) { + if (!consume("]")) error("Default sequence value must be empty"); + return { type: "sequence", value: [] }; + } else { + const str = consume(STR) || error("No value for default"); + str.value = str.value.slice(1, -1); + // No trivia exposure yet + str.trivia = undefined; + return str; + } + } + } + + function const_() { + if (!consume("const")) return; + const ret = { type: "const", nullable: false }; + let typ = primitive_type(); + if (!typ) { + typ = consume(ID) || error("No type for const"); + typ = typ.value; + } + ret.idlType = Object.assign({ type: "const-type" }, EMPTY_IDLTYPE, { idlType: typ }); + type_suffix(ret); + const name = consume(ID) || error("No name for const"); + ret.name = name.value; + consume("=") || error("No value assignment for const"); + const cnt = const_value(); + if (cnt) ret.value = cnt; + else error("No value for const"); + consume(";") || error("Unterminated const"); + return ret; + } + + function inheritance() { + if (consume(":")) { + const inh = consume(ID) || error("No type in inheritance"); + return inh.value; + } + } + + function operation_rest(ret) { + if (!ret) ret = {}; + const name = consume(ID); + ret.name = name ? unescape(name.value) : null; + ret.escapedName = name ? name.value : null; + consume("(") || error("Invalid operation"); + ret.arguments = argument_list(); + consume(")") || error("Unterminated operation"); + consume(";") || error("Unterminated operation"); + return ret; + } + + function callback() { + let ret; + if (!consume("callback")) return; + const tok = consume("interface"); + if (tok) { + ret = interface_rest(false, "callback interface"); + return ret; + } + const name = consume(ID) || error("No name for callback"); + ret = current = { type: "callback", name: sanitize_name(name.value, "callback") }; + consume("=") || error("No assignment in callback"); + ret.idlType = return_type() || error("Missing return type"); + consume("(") || error("No arguments in callback"); + ret.arguments = argument_list(); + consume(")") || error("Unterminated callback"); + consume(";") || error("Unterminated callback"); + return ret; + } + + function attribute({ noInherit = false, readonly = false } = {}) { + const start_position = consume_position; + const ret = { + type: "attribute", + static: false, + stringifier: false, + inherit: false, + readonly: false + }; + if (!noInherit && consume("inherit")) { + ret.inherit = true; + } + if (consume("readonly")) { + ret.readonly = true; + } else if (readonly && probe("attribute")) { + error("Attributes must be readonly in this context"); + } + const rest = attribute_rest(ret); + if (!rest) { + unconsume(start_position); + } + return rest; + } + + function attribute_rest(ret) { + if (!consume("attribute")) { + return; + } + ret.idlType = type_with_extended_attributes("attribute-type") || error("No type in attribute"); + if (ret.idlType.generic === "sequence") error("Attributes cannot accept sequence types"); + if (ret.idlType.generic === "record") error("Attributes cannot accept record types"); + const name = consume(ID, "required") || error("No name in attribute"); + ret.name = unescape(name.value); + ret.escapedName = name.value; + consume(";") || error("Unterminated attribute"); + return ret; + } + + function return_type(typeName) { + const typ = type(typeName || "return-type"); + if (typ) { + return typ; + } + if (consume("void")) { + return Object.assign({ type: "return-type" }, EMPTY_IDLTYPE, { idlType: "void" }); + } + } + + function operation({ regular = false } = {}) { + const ret = Object.assign({}, EMPTY_OPERATION); + while (!regular) { + if (consume("getter")) ret.getter = true; + else if (consume("setter")) ret.setter = true; + else if (consume("deleter")) ret.deleter = true; + else break; + } + ret.idlType = return_type() || error("Missing return type"); + operation_rest(ret); + return ret; + } + + function static_member() { + if (!consume("static")) return; + const member = attribute({ noInherit: true }) || + operation({ regular: true }) || + error("No body in static member"); + member.static = true; + return member; + } + + function stringifier() { + if (!consume("stringifier")) return; + if (consume(";")) { + return Object.assign({}, EMPTY_OPERATION, { stringifier: true }); + } + const member = attribute({ noInherit: true }) || + operation({ regular: true }) || + error("Unterminated stringifier"); + member.stringifier = true; + return member; + } + + function identifiers() { + const arr = []; + const id = consume(ID); + if (id) { + arr.push(id.value); + } + else error("Expected identifiers but not found"); + while (true) { + if (consume(",")) { + const name = consume(ID) || error("Trailing comma in identifiers list"); + arr.push(name.value); + } else break; + } + return arr; + } + + function iterable_type() { + if (consume("iterable")) return "iterable"; + else if (consume("legacyiterable")) return "legacyiterable"; + else if (consume("maplike")) return "maplike"; + else if (consume("setlike")) return "setlike"; + else return; + } + + function readonly_iterable_type() { + if (consume("maplike")) return "maplike"; + else if (consume("setlike")) return "setlike"; + else return; + } + + function iterable() { + const start_position = consume_position; + const ret = { type: null, idlType: null, readonly: false }; + if (consume("readonly")) { + ret.readonly = true; + } + const consumeItType = ret.readonly ? readonly_iterable_type : iterable_type; + + const ittype = consumeItType(); + if (!ittype) { + unconsume(start_position); + return; + } + + const secondTypeRequired = ittype === "maplike"; + const secondTypeAllowed = secondTypeRequired || ittype === "iterable"; + ret.type = ittype; + if (ret.type !== 'maplike' && ret.type !== 'setlike') + delete ret.readonly; + if (consume("<")) { + ret.idlType = [type_with_extended_attributes()] || error(`Error parsing ${ittype} declaration`); + if (secondTypeAllowed) { + if (consume(",")) { + ret.idlType.push(type_with_extended_attributes()); + } + else if (secondTypeRequired) + error(`Missing second type argument in ${ittype} declaration`); + } + if (!consume(">")) error(`Unterminated ${ittype} declaration`); + if (!consume(";")) error(`Missing semicolon after ${ittype} declaration`); + } else + error(`Error parsing ${ittype} declaration`); + + return ret; + } + + function interface_rest(isPartial, typeName = "interface") { + const name = consume(ID) || error("No name for interface"); + const mems = []; + const ret = current = { + type: typeName, + name: isPartial ? name.value : sanitize_name(name.value, "interface"), + partial: isPartial, + members: mems + }; + if (!isPartial) ret.inheritance = inheritance() || null; + consume("{") || error("Bodyless interface"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after interface"); + return ret; + } + const ea = extended_attrs(); + const mem = const_() || + static_member() || + stringifier() || + iterable() || + attribute() || + operation() || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + function mixin_rest(isPartial) { + if (!consume("mixin")) return; + const name = consume(ID) || error("No name for interface mixin"); + const mems = []; + const ret = current = { + type: "interface mixin", + name: isPartial ? name.value : sanitize_name(name.value, "interface mixin"), + partial: isPartial, + members: mems + }; + consume("{") || error("Bodyless interface mixin"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after interface mixin"); + return ret; + } + const ea = extended_attrs(); + const mem = const_() || + stringifier() || + attribute({ noInherit: true }) || + operation({ regular: true }) || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + function interface_(isPartial) { + if (!consume("interface")) return; + return mixin_rest(isPartial) || + interface_rest(isPartial) || + error("Interface has no proper body"); + } + + function namespace(isPartial) { + if (!consume("namespace")) return; + const name = consume(ID) || error("No name for namespace"); + const mems = []; + const ret = current = { + type: "namespace", + name: isPartial ? name.value : sanitize_name(name.value, "namespace"), + partial: isPartial, + members: mems + }; + consume("{") || error("Bodyless namespace"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after namespace"); + return ret; + } + const ea = extended_attrs(); + const mem = attribute({ noInherit: true, readonly: true }) || + operation({ regular: true }) || + error("Unknown member"); + mem.extAttrs = ea; + ret.members.push(mem); + } + } + + function partial() { + if (!consume("partial")) return; + const thing = dictionary(true) || + interface_(true) || + namespace(true) || + error("Partial doesn't apply to anything"); + return thing; + } + + function dictionary(isPartial) { + if (!consume("dictionary")) return; + const name = consume(ID) || error("No name for dictionary"); + const mems = []; + const ret = current = { + type: "dictionary", + name: isPartial ? name.value : sanitize_name(name.value, "dictionary"), + partial: isPartial, + members: mems + }; + if (!isPartial) ret.inheritance = inheritance() || null; + consume("{") || error("Bodyless dictionary"); + while (true) { + if (consume("}")) { + consume(";") || error("Missing semicolon after dictionary"); + return ret; + } + const ea = extended_attrs(); + const required = consume("required"); + const typ = type_with_extended_attributes("dictionary-type") || error("No type for dictionary member"); + const name = consume(ID) || error("No name for dictionary member"); + const dflt = default_() || null; + if (required && dflt) error("Required member must not have a default"); + const member = { + type: "field", + name: unescape(name.value), + escapedName: name.value, + required: !!required, + idlType: typ, + extAttrs: ea, + default: dflt + }; + ret.members.push(member); + consume(";") || error("Unterminated dictionary member"); + } + } + + function enum_() { + if (!consume("enum")) return; + const name = consume(ID) || error("No name for enum"); + const vals = []; + const ret = current = { + type: "enum", + name: sanitize_name(name.value, "enum"), + values: vals + }; + consume("{") || error("No curly for enum"); + let value_expected = true; + while (true) { + if (consume("}")) { + if (!ret.values.length) error("No value in enum"); + consume(";") || error("No semicolon after enum"); + return ret; + } + else if (!value_expected) { + error("No comma between enum values"); + } + const val = consume(STR) || error("Unexpected value in enum"); + val.value = val.value.slice(1, -1); + // No trivia exposure yet + val.trivia = undefined; + ret.values.push(val); + value_expected = !!consume(","); + } + } + + function typedef() { + if (!consume("typedef")) return; + const ret = { + type: "typedef" + }; + ret.idlType = type_with_extended_attributes("typedef-type") || error("No type in typedef"); + const name = consume(ID) || error("No name in typedef"); + ret.name = sanitize_name(name.value, "typedef"); + current = ret; + consume(";") || error("Unterminated typedef"); + return ret; + } + + function implements_() { + const start_position = consume_position; + const target = consume(ID); + if (!target) return; + if (consume("implements")) { + const ret = { + type: "implements", + target: target.value + }; + const imp = consume(ID) || error("Incomplete implements statement"); + ret.implements = imp.value; + consume(";") || error("No terminating ; for implements statement"); + return ret; + } else { + // rollback + unconsume(start_position); + } + } + + function includes() { + const start_position = consume_position; + const target = consume(ID); + if (!target) return; + if (consume("includes")) { + const ret = { + type: "includes", + target: target.value + }; + const imp = consume(ID) || error("Incomplete includes statement"); + ret.includes = imp.value; + consume(";") || error("No terminating ; for includes statement"); + return ret; + } else { + // rollback + unconsume(start_position); + } + } + + function definition() { + return callback() || + interface_(false) || + partial() || + dictionary(false) || + enum_() || + typedef() || + implements_() || + includes() || + namespace(false); + } + + function definitions() { + if (!tokens.length) return []; + const defs = []; + while (true) { + const ea = extended_attrs(); + const def = definition(); + if (!def) { + if (ea.length) error("Stray extended attributes"); + break; + } + def.extAttrs = ea; + defs.push(def); + } + return defs; + } + const res = definitions(); + if (consume_position < tokens.length) error("Unrecognised tokens"); + return res; + } + + const obj = { + parse(str) { + const tokens = tokenise(str); + return parse(tokens); + } + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = obj; + } else if (typeof define === 'function' && define.amd) { + define([], () => obj); + } else { + (self || window).WebIDL2 = obj; + } +})(); diff --git a/test/fixtures/wpt/resources/webidl2/lib/webidl2.js.headers b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js.headers new file mode 100644 index 00000000000000..6805c323df5a97 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/lib/webidl2.js.headers @@ -0,0 +1 @@ +Content-Type: text/javascript; charset=utf-8 diff --git a/test/fixtures/wpt/resources/webidl2/lib/writer.js b/test/fixtures/wpt/resources/webidl2/lib/writer.js new file mode 100644 index 00000000000000..b3097a6f8a74e4 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/lib/writer.js @@ -0,0 +1,221 @@ +"use strict"; + +(() => { + function write(ast, opt = {}) { + const noop = str => str; + const optNames = "type".split(" "); + const context = []; + for (const o of optNames) { + if (!opt[o]) opt[o] = noop; + } + + function literal(it) { + return it.value; + }; + function type(it) { + if (typeof it === "string") return opt.type(it); // XXX should maintain some context + let ret = extended_attributes(it.extAttrs); + if (it.union) ret += `(${it.idlType.map(type).join(" or ")})`; + else { + if (it.generic) ret += `${it.generic}<`; + if (Array.isArray(it.idlType)) ret += it.idlType.map(type).join(", "); + else ret += type(it.idlType); + if (it.generic) ret += ">"; + } + if (it.nullable) ret += "?"; + + return ret; + }; + function const_value(it) { + const tp = it.type; + if (tp === "boolean") return it.value ? "true" : "false"; + else if (tp === "null") return "null"; + else if (tp === "Infinity") return (it.negative ? "-" : "") + "Infinity"; + else if (tp === "NaN") return "NaN"; + else if (tp === "number") return it.value; + else if (tp === "sequence") return "[]"; + else return `"${it.value}"`; + }; + function argument(arg) { + let ret = extended_attributes(arg.extAttrs); + if (arg.optional) ret += "optional "; + ret += type(arg.idlType); + if (arg.variadic) ret += "..."; + ret += ` ${arg.escapedName}`; + if (arg.default) ret += ` = ${const_value(arg.default)}`; + return ret; + }; + function make_ext_at(it) { + context.unshift(it); + let ret = it.name; + if (it.rhs) { + if (it.rhs.type === "identifier-list") ret += `=(${it.rhs.value.join(",")})`; + else ret += `=${it.rhs.value}`; + } + if (it.arguments) ret += `(${it.arguments.length ? it.arguments.map(argument).join(",") : ""})`; + context.shift(); // XXX need to add more contexts, but not more than needed for ReSpec + return ret; + }; + function extended_attributes(eats) { + if (!eats || !eats.length) return ""; + return `[${eats.map(make_ext_at).join(", ")}]`; + }; + + const modifiers = "getter setter deleter stringifier static".split(" "); + function operation(it) { + let ret = extended_attributes(it.extAttrs); + if (it.stringifier && !it.idlType) return "stringifier;"; + for (const mod of modifiers) { + if (it[mod]) ret += mod + " "; + } + ret += type(it.idlType) + " "; + if (it.name) ret += it.escapedName; + ret += `(${it.arguments.map(argument).join(",")});`; + return ret; + }; + + function attribute(it) { + let ret = extended_attributes(it.extAttrs); + if (it.static) ret += "static "; + if (it.stringifier) ret += "stringifier "; + if (it.inherit) ret += "inherit "; + if (it.readonly) ret += "readonly "; + ret += `attribute ${type(it.idlType)} ${it.escapedName};`; + return ret; + }; + + function interface_(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `interface ${it.name} `; + if (it.inheritance) ret += `: ${it.inheritance} `; + ret += `{${iterate(it.members)}};`; + return ret; + }; + + function interface_mixin(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `interface mixin ${it.name} `; + ret += `{${iterate(it.members)}};`; + return ret; + } + + function namespace(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `namespace ${it.name} `; + ret += `{${iterate(it.members)}};`; + return ret; + } + + function dictionary(it) { + let ret = extended_attributes(it.extAttrs); + if (it.partial) ret += "partial "; + ret += `dictionary ${it.name} `; + if (it.inheritance) ret += `: ${it.inheritance} `; + ret += `{${iterate(it.members)}};`; + return ret; + }; + function field(it) { + let ret = extended_attributes(it.extAttrs); + if (it.required) ret += "required "; + ret += `${type(it.idlType)} ${it.escapedName}`; + if (it.default) ret += ` = ${const_value(it.default)}`; + ret += ";"; + return ret; + }; + function const_(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}const ${type(it.idlType)}${it.nullable ? "?" : ""} ${it.name} = ${const_value(it.value)};`; + }; + function typedef(it) { + let ret = extended_attributes(it.extAttrs); + ret += `typedef ${extended_attributes(it.typeExtAttrs)}`; + return `${ret}${type(it.idlType)} ${it.name};`; + }; + function implements_(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}${it.target} implements ${it.implements};`; + }; + function includes(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}${it.target} includes ${it.includes};`; + }; + function callback(it) { + const ret = extended_attributes(it.extAttrs); + return `${ret}callback ${it.name} = ${type(it.idlType)}(${it.arguments.map(argument).join(",")});`; + }; + function enum_(it) { + let ret = extended_attributes(it.extAttrs); + ret += `enum ${it.name} {`; + for (const v of it.values) { + ret += `"${v.value}",`; + } + return ret + "};"; + }; + function iterable(it) { + return `iterable<${Array.isArray(it.idlType) ? it.idlType.map(type).join(", ") : type(it.idlType)}>;`; + }; + function legacyiterable(it) { + return `legacyiterable<${Array.isArray(it.idlType) ? it.idlType.map(type).join(", ") : type(it.idlType)}>;`; + }; + function maplike(it) { + return `${it.readonly ? "readonly " : ""}maplike<${it.idlType.map(type).join(", ")}>;`; + }; + function setlike(it) { + return `${it.readonly ? "readonly " : ""}setlike<${type(it.idlType[0])}>;`; + }; + function callbackInterface(it) { + return `callback ${interface_(it)}`; + }; + + const table = { + interface: interface_, + "interface mixin": interface_mixin, + namespace, + operation, + attribute, + dictionary, + field, + const: const_, + typedef, + implements: implements_, + includes, + callback, + enum: enum_, + iterable, + legacyiterable, + maplike, + setlike, + "callback interface": callbackInterface + }; + function dispatch(it) { + const dispatcher = table[it.type]; + if (!dispatcher) { + throw new Error(`Type "${it.type}" is unsupported`) + } + return table[it.type](it); + }; + function iterate(things) { + if (!things) return; + let ret = ""; + for (const thing of things) ret += dispatch(thing); + return ret; + }; + return iterate(ast); + }; + + + const obj = { + write + }; + + if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { + module.exports = obj; + } else if (typeof define === 'function' && define.amd) { + define([], () => obj); + } else { + (self || window).WebIDL2Writer = obj; + } +})(); diff --git a/test/fixtures/wpt/resources/webidl2/package-lock.json b/test/fixtures/wpt/resources/webidl2/package-lock.json new file mode 100644 index 00000000000000..b0581037fe9434 --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/package-lock.json @@ -0,0 +1,700 @@ +{ + "name": "webidl2", + "version": "13.0.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz", + "integrity": "sha512-eVXQSbu/RimU6OKcK2/gDJVTFcxXJI4sHbIqw2mhwMZeQ2as/8AhS9DGkEDoHMBBNJZ5B0US63lF56x+KDcxiA==", + "dev": true, + "requires": { + "@babel/highlight": "7.0.0-beta.40" + } + }, + "@babel/highlight": { + "version": "7.0.0-beta.40", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.40.tgz", + "integrity": "sha512-mOhhTrzieV6VO7odgzFGFapiwRK0ei8RZRhfzHhb6cpX3QM8XXuCLXWjN8qBB7JReDdUR80V3LFfFrGUYevhNg==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^3.0.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "^1.1.1" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "diff-match-patch": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.0.tgz", + "integrity": "sha1-HMPIOkkNZ/ldkeOfatHy4Ia2MEg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + } + }, + "expect": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-22.4.0.tgz", + "integrity": "sha512-Fiy862jT3qc70hwIHwwCBNISmaqBrfWKKrtqyMJ6iwZr+6KXtcnHojZFtd63TPRvRl8EQTJ+YXYy2lK6/6u+Hw==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "jest-diff": "^22.4.0", + "jest-get-type": "^22.1.0", + "jest-matcher-utils": "^22.4.0", + "jest-message-util": "^22.4.0", + "jest-regex-util": "^22.1.0" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "jest-diff": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-22.4.0.tgz", + "integrity": "sha512-+/t20WmnkOkB8MOaGaPziI8zWKxquMvYw4Ub+wOzi7AUhmpFXz43buWSxVoZo4J5RnCozpGbX3/FssjJ5KV9Nw==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff": "^3.2.0", + "jest-get-type": "^22.1.0", + "pretty-format": "^22.4.0" + } + }, + "jest-get-type": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-22.1.0.tgz", + "integrity": "sha512-nD97IVOlNP6fjIN5i7j5XRH+hFsHL7VlauBbzRvueaaUe70uohrkz7pL/N8lx/IAwZRTJ//wOdVgh85OgM7g3w==", + "dev": true + }, + "jest-matcher-utils": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-22.4.0.tgz", + "integrity": "sha512-03m3issxUXpWMwDYTfmL8hRNewUB0yCRTeXPm+eq058rZxLHD9f5NtSSO98CWHqe4UyISIxd9Ao9iDVjHWd2qg==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-get-type": "^22.1.0", + "pretty-format": "^22.4.0" + } + }, + "jest-message-util": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-22.4.0.tgz", + "integrity": "sha512-eyCJB0T3hrlpFF2FqQoIB093OulP+1qvATQmD3IOgJgMGqPL6eYw8TbC5P/VCWPqKhGL51xvjIIhow5eZ2wHFw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0-beta.35", + "chalk": "^2.0.1", + "micromatch": "^2.3.11", + "slash": "^1.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-regex-util": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-22.1.0.tgz", + "integrity": "sha512-on0LqVS6Xeh69sw3d1RukVnur+lVOl3zkmb0Q54FHj9wHoq6dbtWqb3TSlnVUyx36hqjJhjgs/QLqs07Bzu72Q==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "jsondiffpatch": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.3.5.tgz", + "integrity": "sha512-v7eaGLDMCHXH+fsIaZhptEUJmS8EJpunq7IM4cc4vIT/kSRAkaZ6ZF4ebiNcyUelL0znbvj6o2B5Gh9v7Og0BQ==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "diff-match-patch": "^1.0.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "math-random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.4.tgz", + "integrity": "sha512-nMOpAPFosU1B4Ix1jdhx5e3q7XO55ic5a8cgYvW27CequcEY+BabS0kUVL1Cw1V5PuVHZWeNRWFLmEPexo79VA==", + "dev": true, + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-format": { + "version": "22.4.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-22.4.0.tgz", + "integrity": "sha512-pvCxP2iODIIk9adXlo4S3GRj0BrJiil68kByAa1PrgG97c1tClh9dLMgp3Z6cHFZrclaABt0UH8PIhwHuFLqYA==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "randomatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", + "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + } + } +} diff --git a/test/fixtures/wpt/resources/webidl2/package.json b/test/fixtures/wpt/resources/webidl2/package.json new file mode 100644 index 00000000000000..92faccafa813fb --- /dev/null +++ b/test/fixtures/wpt/resources/webidl2/package.json @@ -0,0 +1,27 @@ +{ + "name": "webidl2", + "description": "A WebIDL Parser", + "version": "13.0.3", + "contributors": [ + "Robin Berjon (https://berjon.com)", + "Marcos Caceres (https://marcosc.com)", + "Kagami Sascha Rosylight ", + "Timothy Gu " + ], + "license": "W3C", + "dependencies": {}, + "devDependencies": { + "expect": "22.4.0", + "jsondiffpatch": "0.3.5", + "mocha": "5.0.4" + }, + "scripts": { + "test": "mocha", + "acquire": "node test/util/acquire.js" + }, + "repository": "git://github.com/w3c/webidl2.js", + "main": "index.js", + "files": [ + "lib/*" + ] +} diff --git a/test/fixtures/wpt/url/META.yml b/test/fixtures/wpt/url/META.yml new file mode 100644 index 00000000000000..3a789a0d513f0a --- /dev/null +++ b/test/fixtures/wpt/url/META.yml @@ -0,0 +1,8 @@ +spec: https://url.spec.whatwg.org/ +suggested_reviewers: + - mikewest + - domenic + - Sebmaster + - annevk + - GPHemsley + - TimothyGu diff --git a/test/fixtures/wpt/url/README.md b/test/fixtures/wpt/url/README.md new file mode 100644 index 00000000000000..823a8eec022282 --- /dev/null +++ b/test/fixtures/wpt/url/README.md @@ -0,0 +1,53 @@ +## urltestdata.json + +These tests are for browsers, but the data for +`a-element.html`, `url-constructor.html`, `a-element-xhtml.xhtml`, and `failure.html` +is in `resources/urltestdata.json` and can be re-used by non-browser implementations. +This file contains a JSON array of comments as strings and test cases as objects. +The keys for each test case are: + +* `base`: an absolute URL as a string whose [parsing] without a base of its own must succeed. + This key is always present, + and may have a value like `"about:blank"` when `input` is an absolute URL. +* `input`: an URL as a string to be [parsed][parsing] with `base` as its base URL. +* Either: + * `failure` with the value `true`, indicating that parsing `input` should return failure, + * or `href`, `origin`, `protocol`, `username`, `password`, `host`, `hostname`, `port`, + `pathname`, `search`, and `hash` with string values; + indicating that parsing `input` should return an URL record + and that the getters of each corresponding attribute in that URL’s [API] + should return the corresponding value. + + The `origin` key may be missing. + In that case, the API’s `origin` attribute is not tested. + +In addition to testing that parsing `input` against `base` gives the result, a test harness for the +`URL` constructor (or similar APIs) should additionally test the following pattern: if `failure` is +true, parsing `about:blank` against `input` must give failure. This tests that the logic for +converting base URLs into strings properly fails the whole parsing algorithm if the base URL cannot +be parsed. + +## setters_tests.json + +`resources/setters_tests.json` is self-documented. + +## toascii.json + +`resources/toascii.json` is a JSON resource containing an array where each item is an object +consisting of an optional `comment` field and mandatory `input` and `output` fields. `input` is the +domain to be parsed according to the rules of UTS #46 (as stipulated by the URL Standard). `output` +gives the expected output of the parser after serialization. An `output` of `null` means parsing is +expected to fail. + +## URL parser's encoding argument + +Tests in `/encoding` and `/html/infrastructure/urls/resolving-urls/query-encoding/` cover the +encoding argument to the URL parser. + +## Specification + +The tests in this directory assert conformance with [the URL Standard][URL]. + +[parsing]: https://url.spec.whatwg.org/#concept-basic-url-parser +[API]: https://url.spec.whatwg.org/#api +[URL]: https://url.spec.whatwg.org/ diff --git a/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml b/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml new file mode 100644 index 00000000000000..effcf04bee3fb0 --- /dev/null +++ b/test/fixtures/wpt/url/a-element-origin-xhtml.xhtml @@ -0,0 +1,15 @@ + + + + + URL Test + + + + + +
+ + + + diff --git a/test/fixtures/wpt/url/a-element-origin.html b/test/fixtures/wpt/url/a-element-origin.html new file mode 100644 index 00000000000000..9cc8e94cbed060 --- /dev/null +++ b/test/fixtures/wpt/url/a-element-origin.html @@ -0,0 +1,8 @@ + + + + + +
+ + diff --git a/test/fixtures/wpt/url/a-element-xhtml.xhtml b/test/fixtures/wpt/url/a-element-xhtml.xhtml new file mode 100644 index 00000000000000..c6c67cf3ce619b --- /dev/null +++ b/test/fixtures/wpt/url/a-element-xhtml.xhtml @@ -0,0 +1,15 @@ + + + + + URL Test + + + + + +
+ + + + diff --git a/test/fixtures/wpt/url/a-element.html b/test/fixtures/wpt/url/a-element.html new file mode 100644 index 00000000000000..05c37f30b71e12 --- /dev/null +++ b/test/fixtures/wpt/url/a-element.html @@ -0,0 +1,8 @@ + + + + + +
+ + diff --git a/test/fixtures/wpt/url/data-uri-fragment.html b/test/fixtures/wpt/url/data-uri-fragment.html new file mode 100644 index 00000000000000..e77d96f03d821d --- /dev/null +++ b/test/fixtures/wpt/url/data-uri-fragment.html @@ -0,0 +1,34 @@ + + +Data URI parsing of fragments + + + + + + + + + diff --git a/test/fixtures/wpt/url/failure.html b/test/fixtures/wpt/url/failure.html new file mode 100644 index 00000000000000..13a90cc8d097c1 --- /dev/null +++ b/test/fixtures/wpt/url/failure.html @@ -0,0 +1,48 @@ + + +Test URL parser failure consistency + + +
+ + diff --git a/test/fixtures/wpt/url/historical.any.js b/test/fixtures/wpt/url/historical.any.js new file mode 100644 index 00000000000000..c3797ad263850c --- /dev/null +++ b/test/fixtures/wpt/url/historical.any.js @@ -0,0 +1,29 @@ +test(function() { + assert_false("searchParams" in self.location, + "location object should not have a searchParams attribute"); +}, "searchParams on location object"); + +if(self.GLOBAL.isWindow()) { + test(() => { + assert_false("searchParams" in document.createElement("a")) + assert_false("searchParams" in document.createElement("area")) + }, " and .searchParams should be undefined"); +} + +test(function() { + var url = new URL("./foo", "http://www.example.org"); + assert_equals(url.href, "http://www.example.org/foo"); + assert_throws(new TypeError(), function() { + url.href = "./bar"; + }); +}, "Setting URL's href attribute and base URLs"); + +test(function() { + assert_equals(URL.domainToASCII, undefined); +}, "URL.domainToASCII should be undefined"); + +test(function() { + assert_equals(URL.domainToUnicode, undefined); +}, "URL.domainToUnicode should be undefined"); + +done(); diff --git a/test/fixtures/wpt/url/idlharness.any.js b/test/fixtures/wpt/url/idlharness.any.js new file mode 100644 index 00000000000000..4a0e52f12b3c32 --- /dev/null +++ b/test/fixtures/wpt/url/idlharness.any.js @@ -0,0 +1,13 @@ +// META: script=/resources/WebIDLParser.js +// META: script=/resources/idlharness.js + +idl_test( + ['url'], + [], // no deps + idl_array => { + idl_array.add_objects({ + URL: ['new URL("http://foo")'], + URLSearchParams: ['new URLSearchParams("hi=there&thank=you")'] + }); + } +); diff --git a/test/fixtures/wpt/url/resources/a-element-origin.js b/test/fixtures/wpt/url/resources/a-element-origin.js new file mode 100644 index 00000000000000..3b8cb1cbbe7c75 --- /dev/null +++ b/test/fixtures/wpt/url/resources/a-element-origin.js @@ -0,0 +1,25 @@ +promise_test(() => fetch("resources/urltestdata.json").then(res => res.json()).then(runURLTests), "Loading data…"); + +function setBase(base) { + document.getElementById("base").href = base +} + +function bURL(url, base) { + base = base || "about:blank" + setBase(base) + var a = document.createElement("a") + a.setAttribute("href", url) + return a +} + +function runURLTests(urltests) { + for(var i = 0, l = urltests.length; i < l; i++) { + var expected = urltests[i] + if (typeof expected === "string" || !("origin" in expected)) continue + + test(function() { + var url = bURL(expected.input, expected.base) + assert_equals(url.origin, expected.origin, "origin") + }, "Parsing origin: <" + expected.input + "> against <" + expected.base + ">") + } +} diff --git a/test/fixtures/wpt/url/resources/a-element.js b/test/fixtures/wpt/url/resources/a-element.js new file mode 100644 index 00000000000000..f64531bc8bd528 --- /dev/null +++ b/test/fixtures/wpt/url/resources/a-element.js @@ -0,0 +1,42 @@ +promise_test(() => fetch("resources/urltestdata.json").then(res => res.json()).then(runURLTests), "Loading data…"); + +function setBase(base) { + document.getElementById("base").href = base +} + +function bURL(url, base) { + base = base || "about:blank" + setBase(base) + var a = document.createElement("a") + a.setAttribute("href", url) + return a +} + +function runURLTests(urltests) { + for(var i = 0, l = urltests.length; i < l; i++) { + var expected = urltests[i] + if (typeof expected === "string") continue // skip comments + + test(function() { + var url = bURL(expected.input, expected.base) + if(expected.failure) { + if(url.protocol !== ':') { + assert_unreached("Expected URL to fail parsing") + } + assert_equals(url.href, expected.input, "failure should set href to input") + return + } + + assert_equals(url.href, expected.href, "href") + assert_equals(url.protocol, expected.protocol, "protocol") + assert_equals(url.username, expected.username, "username") + assert_equals(url.password, expected.password, "password") + assert_equals(url.host, expected.host, "host") + assert_equals(url.hostname, expected.hostname, "hostname") + assert_equals(url.port, expected.port, "port") + assert_equals(url.pathname, expected.pathname, "pathname") + assert_equals(url.search, expected.search, "search") + assert_equals(url.hash, expected.hash, "hash") + }, "Parsing: <" + expected.input + "> against <" + expected.base + ">") + } +} diff --git a/test/fixtures/wpt/url/resources/setters_tests.json b/test/fixtures/wpt/url/resources/setters_tests.json new file mode 100644 index 00000000000000..db23d924732800 --- /dev/null +++ b/test/fixtures/wpt/url/resources/setters_tests.json @@ -0,0 +1,1866 @@ +{ + "comment": [ + "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members", + "", + "This file contains a JSON object.", + "Other than 'comment', each key is an attribute of the `URL` interface", + "defined in WHATWG’s URL Standard.", + "The values are arrays of test case objects for that attribute.", + "", + "To run a test case for the attribute `attr`:", + "", + "* Create a new `URL` object with the value for the 'href' key", + " the constructor single parameter. (Without a base URL.)", + " This must not throw.", + "* Set the attribute `attr` to (invoke its setter with)", + " with the value of for 'new_value' key.", + "* The value for the 'expected' key is another object.", + " For each `key` / `value` pair of that object,", + " get the attribute `key` (invoke its getter).", + " The returned string must be equal to `value`.", + "", + "Note: the 'href' setter is already covered by urltestdata.json." + ], + "protocol": [ + { + "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.", + "href": "a://example.net", + "new_value": "", + "expected": { + "href": "a://example.net", + "protocol": "a:" + } + }, + { + "href": "a://example.net", + "new_value": "b", + "expected": { + "href": "b://example.net", + "protocol": "b:" + } + }, + { + "href": "javascript:alert(1)", + "new_value": "defuse", + "expected": { + "href": "defuse:alert(1)", + "protocol": "defuse:" + } + }, + { + "comment": "Upper-case ASCII is lower-cased", + "href": "a://example.net", + "new_value": "B", + "expected": { + "href": "b://example.net", + "protocol": "b:" + } + }, + { + "comment": "Non-ASCII is rejected", + "href": "a://example.net", + "new_value": "é", + "expected": { + "href": "a://example.net", + "protocol": "a:" + } + }, + { + "comment": "No leading digit", + "href": "a://example.net", + "new_value": "0b", + "expected": { + "href": "a://example.net", + "protocol": "a:" + } + }, + { + "comment": "No leading punctuation", + "href": "a://example.net", + "new_value": "+b", + "expected": { + "href": "a://example.net", + "protocol": "a:" + } + }, + { + "href": "a://example.net", + "new_value": "bC0+-.", + "expected": { + "href": "bc0+-.://example.net", + "protocol": "bc0+-.:" + } + }, + { + "comment": "Only some punctuation is acceptable", + "href": "a://example.net", + "new_value": "b,c", + "expected": { + "href": "a://example.net", + "protocol": "a:" + } + }, + { + "comment": "Non-ASCII is rejected", + "href": "a://example.net", + "new_value": "bé", + "expected": { + "href": "a://example.net", + "protocol": "a:" + } + }, + { + "comment": "Can’t switch from URL containing username/password/port to file", + "href": "http://test@example.net", + "new_value": "file", + "expected": { + "href": "http://test@example.net/", + "protocol": "http:" + } + }, + { + "href": "gopher://example.net:1234", + "new_value": "file", + "expected": { + "href": "gopher://example.net:1234/", + "protocol": "gopher:" + } + }, + { + "href": "wss://x:x@example.net:1234", + "new_value": "file", + "expected": { + "href": "wss://x:x@example.net:1234/", + "protocol": "wss:" + } + }, + { + "comment": "Can’t switch from file URL with no host", + "href": "file://localhost/", + "new_value": "http", + "expected": { + "href": "file:///", + "protocol": "file:" + } + }, + { + "href": "file:///test", + "new_value": "gopher", + "expected": { + "href": "file:///test", + "protocol": "file:" + } + }, + { + "href": "file:", + "new_value": "wss", + "expected": { + "href": "file:///", + "protocol": "file:" + } + }, + { + "comment": "Can’t switch from special scheme to non-special", + "href": "http://example.net", + "new_value": "b", + "expected": { + "href": "http://example.net/", + "protocol": "http:" + } + }, + { + "href": "file://hi/path", + "new_value": "s", + "expected": { + "href": "file://hi/path", + "protocol": "file:" + } + }, + { + "href": "https://example.net", + "new_value": "s", + "expected": { + "href": "https://example.net/", + "protocol": "https:" + } + }, + { + "href": "ftp://example.net", + "new_value": "test", + "expected": { + "href": "ftp://example.net/", + "protocol": "ftp:" + } + }, + { + "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.", + "href": "mailto:me@example.net", + "new_value": "http", + "expected": { + "href": "mailto:me@example.net", + "protocol": "mailto:" + } + }, + { + "comment": "Can’t switch from non-special scheme to special", + "href": "ssh://me@example.net", + "new_value": "http", + "expected": { + "href": "ssh://me@example.net", + "protocol": "ssh:" + } + }, + { + "href": "ssh://me@example.net", + "new_value": "gopher", + "expected": { + "href": "ssh://me@example.net", + "protocol": "ssh:" + } + }, + { + "href": "ssh://me@example.net", + "new_value": "file", + "expected": { + "href": "ssh://me@example.net", + "protocol": "ssh:" + } + }, + { + "href": "ssh://example.net", + "new_value": "file", + "expected": { + "href": "ssh://example.net", + "protocol": "ssh:" + } + }, + { + "href": "nonsense:///test", + "new_value": "https", + "expected": { + "href": "nonsense:///test", + "protocol": "nonsense:" + } + }, + { + "comment": "Stuff after the first ':' is ignored", + "href": "http://example.net", + "new_value": "https:foo : bar", + "expected": { + "href": "https://example.net/", + "protocol": "https:" + } + }, + { + "comment": "Stuff after the first ':' is ignored", + "href": "data:text/html,

Test", + "new_value": "view-source+data:foo : bar", + "expected": { + "href": "view-source+data:text/html,

Test", + "protocol": "view-source+data:" + } + }, + { + "comment": "Port is set to null if it is the default for new scheme.", + "href": "http://foo.com:443/", + "new_value": "https", + "expected": { + "href": "https://foo.com/", + "protocol": "https:", + "port": "" + } + } + ], + "username": [ + { + "comment": "No host means no username", + "href": "file:///home/you/index.html", + "new_value": "me", + "expected": { + "href": "file:///home/you/index.html", + "username": "" + } + }, + { + "comment": "No host means no username", + "href": "unix:/run/foo.socket", + "new_value": "me", + "expected": { + "href": "unix:/run/foo.socket", + "username": "" + } + }, + { + "comment": "Cannot-be-a-base means no username", + "href": "mailto:you@example.net", + "new_value": "me", + "expected": { + "href": "mailto:you@example.net", + "username": "" + } + }, + { + "href": "javascript:alert(1)", + "new_value": "wario", + "expected": { + "href": "javascript:alert(1)", + "username": "" + } + }, + { + "href": "http://example.net", + "new_value": "me", + "expected": { + "href": "http://me@example.net/", + "username": "me" + } + }, + { + "href": "http://:secret@example.net", + "new_value": "me", + "expected": { + "href": "http://me:secret@example.net/", + "username": "me" + } + }, + { + "href": "http://me@example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "username": "" + } + }, + { + "href": "http://me:secret@example.net", + "new_value": "", + "expected": { + "href": "http://:secret@example.net/", + "username": "" + } + }, + { + "comment": "UTF-8 percent encoding with the userinfo encode set.", + "href": "http://example.net", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", + "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is.", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://%c3%89t%C3%A9@example.net/", + "username": "%c3%89t%C3%A9" + } + }, + { + "href": "sc:///", + "new_value": "x", + "expected": { + "href": "sc:///", + "username": "" + } + }, + { + "href": "javascript://x/", + "new_value": "wario", + "expected": { + "href": "javascript://wario@x/", + "username": "wario" + } + }, + { + "href": "file://test/", + "new_value": "test", + "expected": { + "href": "file://test/", + "username": "" + } + } + ], + "password": [ + { + "comment": "No host means no password", + "href": "file:///home/me/index.html", + "new_value": "secret", + "expected": { + "href": "file:///home/me/index.html", + "password": "" + } + }, + { + "comment": "No host means no password", + "href": "unix:/run/foo.socket", + "new_value": "secret", + "expected": { + "href": "unix:/run/foo.socket", + "password": "" + } + }, + { + "comment": "Cannot-be-a-base means no password", + "href": "mailto:me@example.net", + "new_value": "secret", + "expected": { + "href": "mailto:me@example.net", + "password": "" + } + }, + { + "href": "http://example.net", + "new_value": "secret", + "expected": { + "href": "http://:secret@example.net/", + "password": "secret" + } + }, + { + "href": "http://me@example.net", + "new_value": "secret", + "expected": { + "href": "http://me:secret@example.net/", + "password": "secret" + } + }, + { + "href": "http://:secret@example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "password": "" + } + }, + { + "href": "http://me:secret@example.net", + "new_value": "", + "expected": { + "href": "http://me@example.net/", + "password": "" + } + }, + { + "comment": "UTF-8 percent encoding with the userinfo encode set.", + "href": "http://example.net", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", + "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is.", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://:%c3%89t%C3%A9@example.net/", + "password": "%c3%89t%C3%A9" + } + }, + { + "href": "sc:///", + "new_value": "x", + "expected": { + "href": "sc:///", + "password": "" + } + }, + { + "href": "javascript://x/", + "new_value": "bowser", + "expected": { + "href": "javascript://:bowser@x/", + "password": "bowser" + } + }, + { + "href": "file://test/", + "new_value": "test", + "expected": { + "href": "file://test/", + "password": "" + } + } + ], + "host": [ + { + "comment": "Non-special scheme", + "href": "sc://x/", + "new_value": "\u0000", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "href": "sc://x/", + "new_value": "\u0009", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000A", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000D", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": " ", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "href": "sc://x/", + "new_value": "#", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "/", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "?", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "@", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "href": "sc://x/", + "new_value": "ß", + "expected": { + "href": "sc://%C3%9F/", + "host": "%C3%9F", + "hostname": "%C3%9F" + } + }, + { + "comment": "IDNA Nontransitional_Processing", + "href": "https://x/", + "new_value": "ß", + "expected": { + "href": "https://xn--zca/", + "host": "xn--zca", + "hostname": "xn--zca" + } + }, + { + "comment": "Cannot-be-a-base means no host", + "href": "mailto:me@example.net", + "new_value": "example.com", + "expected": { + "href": "mailto:me@example.net", + "host": "" + } + }, + { + "comment": "Cannot-be-a-base means no password", + "href": "data:text/plain,Stuff", + "new_value": "example.net", + "expected": { + "href": "data:text/plain,Stuff", + "host": "" + } + }, + { + "href": "http://example.net", + "new_value": "example.com:8080", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Port number is unchanged if not specified in the new value", + "href": "http://example.net:8080", + "new_value": "example.com", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Port number is unchanged if not specified", + "href": "http://example.net:8080", + "new_value": "example.com:", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "The empty host is not valid for special schemes", + "href": "http://example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "host": "example.net" + } + }, + { + "comment": "The empty host is OK for non-special schemes", + "href": "view-source+http://example.net/foo", + "new_value": "", + "expected": { + "href": "view-source+http:///foo", + "host": "" + } + }, + { + "comment": "Path-only URLs can gain a host", + "href": "a:/foo", + "new_value": "example.net", + "expected": { + "href": "a://example.net/foo", + "host": "example.net" + } + }, + { + "comment": "IPv4 address syntax is normalized", + "href": "http://example.net", + "new_value": "0x7F000001:8080", + "expected": { + "href": "http://127.0.0.1:8080/", + "host": "127.0.0.1:8080", + "hostname": "127.0.0.1", + "port": "8080" + } + }, + { + "comment": "IPv6 address syntax is normalized", + "href": "http://example.net", + "new_value": "[::0:01]:2", + "expected": { + "href": "http://[::1]:2/", + "host": "[::1]:2", + "hostname": "[::1]", + "port": "2" + } + }, + { + "comment": "Default port number is removed", + "href": "http://example.net", + "new_value": "example.com:80", + "expected": { + "href": "http://example.com/", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Default port number is removed", + "href": "https://example.net", + "new_value": "example.com:443", + "expected": { + "href": "https://example.com/", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Default port number is only removed for the relevant scheme", + "href": "https://example.net", + "new_value": "example.com:80", + "expected": { + "href": "https://example.com:80/", + "host": "example.com:80", + "hostname": "example.com", + "port": "80" + } + }, + { + "comment": "Port number is removed if new port is scheme default and existing URL has a non-default port", + "href": "http://example.net:8080", + "new_value": "example.com:80", + "expected": { + "href": "http://example.com/", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com/stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080/stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com?stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080?stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com#stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080#stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "example.com:8080\\stuff", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", + "href": "view-source+http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "view-source+http://example.net/path", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "view-source+http://example.net/path", + "new_value": "example.com:8080stuff2", + "expected": { + "href": "view-source+http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "example.com:8080stuff2", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "example.com:8080+2", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Port numbers are 16 bit integers", + "href": "http://example.net/path", + "new_value": "example.com:65535", + "expected": { + "href": "http://example.com:65535/path", + "host": "example.com:65535", + "hostname": "example.com", + "port": "65535" + } + }, + { + "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.", + "href": "http://example.net/path", + "new_value": "example.com:65536", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Broken IPv6", + "href": "http://example.net/", + "new_value": "[google.com]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.4x]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "file://y/", + "new_value": "x:123", + "expected": { + "href": "file://y/", + "host": "y", + "hostname": "y", + "port": "" + } + }, + { + "href": "file://y/", + "new_value": "loc%41lhost", + "expected": { + "href": "file:///", + "host": "", + "hostname": "", + "port": "" + } + }, + { + "href": "file://hi/x", + "new_value": "", + "expected": { + "href": "file:///x", + "host": "", + "hostname": "", + "port": "" + } + }, + { + "href": "sc://test@test/", + "new_value": "", + "expected": { + "href": "sc://test@test/", + "host": "test", + "hostname": "test", + "username": "test" + } + }, + { + "href": "sc://test:12/", + "new_value": "", + "expected": { + "href": "sc://test:12/", + "host": "test:12", + "hostname": "test", + "port": "12" + } + } + ], + "hostname": [ + { + "comment": "Non-special scheme", + "href": "sc://x/", + "new_value": "\u0000", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "href": "sc://x/", + "new_value": "\u0009", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000A", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "\u000D", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": " ", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "href": "sc://x/", + "new_value": "#", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "/", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "?", + "expected": { + "href": "sc:///", + "host": "", + "hostname": "" + } + }, + { + "href": "sc://x/", + "new_value": "@", + "expected": { + "href": "sc://x/", + "host": "x", + "hostname": "x" + } + }, + { + "comment": "Cannot-be-a-base means no host", + "href": "mailto:me@example.net", + "new_value": "example.com", + "expected": { + "href": "mailto:me@example.net", + "host": "" + } + }, + { + "comment": "Cannot-be-a-base means no password", + "href": "data:text/plain,Stuff", + "new_value": "example.net", + "expected": { + "href": "data:text/plain,Stuff", + "host": "" + } + }, + { + "href": "http://example.net:8080", + "new_value": "example.com", + "expected": { + "href": "http://example.com:8080/", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "The empty host is not valid for special schemes", + "href": "http://example.net", + "new_value": "", + "expected": { + "href": "http://example.net/", + "host": "example.net" + } + }, + { + "comment": "The empty host is OK for non-special schemes", + "href": "view-source+http://example.net/foo", + "new_value": "", + "expected": { + "href": "view-source+http:///foo", + "host": "" + } + }, + { + "comment": "Path-only URLs can gain a host", + "href": "a:/foo", + "new_value": "example.net", + "expected": { + "href": "a://example.net/foo", + "host": "example.net" + } + }, + { + "comment": "IPv4 address syntax is normalized", + "href": "http://example.net:8080", + "new_value": "0x7F000001", + "expected": { + "href": "http://127.0.0.1:8080/", + "host": "127.0.0.1:8080", + "hostname": "127.0.0.1", + "port": "8080" + } + }, + { + "comment": "IPv6 address syntax is normalized", + "href": "http://example.net", + "new_value": "[::0:01]", + "expected": { + "href": "http://[::1]/", + "host": "[::1]", + "hostname": "[::1]", + "port": "" + } + }, + { + "comment": "Stuff after a : delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com:8080", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a : delimiter is ignored", + "href": "http://example.net:8080/path", + "new_value": "example.com:", + "expected": { + "href": "http://example.com:8080/path", + "host": "example.com:8080", + "hostname": "example.com", + "port": "8080" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com/stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com?stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "example.com#stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "http://example.com/path", + "host": "example.com", + "hostname": "example.com", + "port": "" + } + }, + { + "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", + "href": "view-source+http://example.net/path", + "new_value": "example.com\\stuff", + "expected": { + "href": "view-source+http://example.net/path", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Broken IPv6", + "href": "http://example.net/", + "new_value": "[google.com]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.4x]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.3.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.2.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "http://example.net/", + "new_value": "[::1.]", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net" + } + }, + { + "href": "file://y/", + "new_value": "x:123", + "expected": { + "href": "file://y/", + "host": "y", + "hostname": "y", + "port": "" + } + }, + { + "href": "file://y/", + "new_value": "loc%41lhost", + "expected": { + "href": "file:///", + "host": "", + "hostname": "", + "port": "" + } + }, + { + "href": "file://hi/x", + "new_value": "", + "expected": { + "href": "file:///x", + "host": "", + "hostname": "", + "port": "" + } + }, + { + "href": "sc://test@test/", + "new_value": "", + "expected": { + "href": "sc://test@test/", + "host": "test", + "hostname": "test", + "username": "test" + } + }, + { + "href": "sc://test:12/", + "new_value": "", + "expected": { + "href": "sc://test:12/", + "host": "test:12", + "hostname": "test", + "port": "12" + } + } + ], + "port": [ + { + "href": "http://example.net", + "new_value": "8080", + "expected": { + "href": "http://example.net:8080/", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Port number is removed if empty is the new value", + "href": "http://example.net:8080", + "new_value": "", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Default port number is removed", + "href": "http://example.net:8080", + "new_value": "80", + "expected": { + "href": "http://example.net/", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Default port number is removed", + "href": "https://example.net:4433", + "new_value": "443", + "expected": { + "href": "https://example.net/", + "host": "example.net", + "hostname": "example.net", + "port": "" + } + }, + { + "comment": "Default port number is only removed for the relevant scheme", + "href": "https://example.net", + "new_value": "80", + "expected": { + "href": "https://example.net:80/", + "host": "example.net:80", + "hostname": "example.net", + "port": "80" + } + }, + { + "comment": "Stuff after a / delimiter is ignored", + "href": "http://example.net/path", + "new_value": "8080/stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Stuff after a ? delimiter is ignored", + "href": "http://example.net/path", + "new_value": "8080?stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Stuff after a # delimiter is ignored", + "href": "http://example.net/path", + "new_value": "8080#stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Stuff after a \\ delimiter is ignored for special schemes", + "href": "http://example.net/path", + "new_value": "8080\\stuff", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "view-source+http://example.net/path", + "new_value": "8080stuff2", + "expected": { + "href": "view-source+http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "8080stuff2", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", + "href": "http://example.net/path", + "new_value": "8080+2", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Port numbers are 16 bit integers", + "href": "http://example.net/path", + "new_value": "65535", + "expected": { + "href": "http://example.net:65535/path", + "host": "example.net:65535", + "hostname": "example.net", + "port": "65535" + } + }, + { + "comment": "Port numbers are 16 bit integers, overflowing is an error", + "href": "http://example.net:8080/path", + "new_value": "65536", + "expected": { + "href": "http://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "comment": "Port numbers are 16 bit integers, overflowing is an error", + "href": "non-special://example.net:8080/path", + "new_value": "65536", + "expected": { + "href": "non-special://example.net:8080/path", + "host": "example.net:8080", + "hostname": "example.net", + "port": "8080" + } + }, + { + "href": "file://test/", + "new_value": "12", + "expected": { + "href": "file://test/", + "port": "" + } + }, + { + "href": "file://localhost/", + "new_value": "12", + "expected": { + "href": "file:///", + "port": "" + } + }, + { + "href": "non-base:value", + "new_value": "12", + "expected": { + "href": "non-base:value", + "port": "" + } + }, + { + "href": "sc:///", + "new_value": "12", + "expected": { + "href": "sc:///", + "port": "" + } + }, + { + "href": "sc://x/", + "new_value": "12", + "expected": { + "href": "sc://x:12/", + "port": "12" + } + }, + { + "href": "javascript://x/", + "new_value": "12", + "expected": { + "href": "javascript://x:12/", + "port": "12" + } + } + ], + "pathname": [ + { + "comment": "Cannot-be-a-base don’t have a path", + "href": "mailto:me@example.net", + "new_value": "/foo", + "expected": { + "href": "mailto:me@example.net", + "pathname": "me@example.net" + } + }, + { + "href": "unix:/run/foo.socket?timeout=10", + "new_value": "/var/log/../run/bar.socket", + "expected": { + "href": "unix:/var/run/bar.socket?timeout=10", + "pathname": "/var/run/bar.socket" + } + }, + { + "href": "https://example.net#nav", + "new_value": "home", + "expected": { + "href": "https://example.net/home#nav", + "pathname": "/home" + } + }, + { + "href": "https://example.net#nav", + "new_value": "../home", + "expected": { + "href": "https://example.net/home#nav", + "pathname": "/home" + } + }, + { + "comment": "\\ is a segment delimiter for 'special' URLs", + "href": "http://example.net/home?lang=fr#nav", + "new_value": "\\a\\%2E\\b\\%2e.\\c", + "expected": { + "href": "http://example.net/a/c?lang=fr#nav", + "pathname": "/a/c" + } + }, + { + "comment": "\\ is *not* a segment delimiter for non-'special' URLs", + "href": "view-source+http://example.net/home?lang=fr#nav", + "new_value": "\\a\\%2E\\b\\%2e.\\c", + "expected": { + "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav", + "pathname": "/\\a\\%2E\\b\\%2e.\\c" + } + }, + { + "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.", + "href": "a:/", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", + "pathname": "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.", + "href": "http://example.net", + "new_value": "%2e%2E%c3%89té", + "expected": { + "href": "http://example.net/%2e%2E%c3%89t%C3%A9", + "pathname": "/%2e%2E%c3%89t%C3%A9" + } + }, + { + "comment": "? needs to be encoded", + "href": "http://example.net", + "new_value": "?", + "expected": { + "href": "http://example.net/%3F", + "pathname": "/%3F" + } + }, + { + "comment": "# needs to be encoded", + "href": "http://example.net", + "new_value": "#", + "expected": { + "href": "http://example.net/%23", + "pathname": "/%23" + } + }, + { + "comment": "? needs to be encoded, non-special scheme", + "href": "sc://example.net", + "new_value": "?", + "expected": { + "href": "sc://example.net/%3F", + "pathname": "/%3F" + } + }, + { + "comment": "# needs to be encoded, non-special scheme", + "href": "sc://example.net", + "new_value": "#", + "expected": { + "href": "sc://example.net/%23", + "pathname": "/%23" + } + }, + { + "comment": "File URLs and (back)slashes", + "href": "file://monkey/", + "new_value": "\\\\", + "expected": { + "href": "file://monkey/", + "pathname": "/" + } + }, + { + "comment": "File URLs and (back)slashes", + "href": "file:///unicorn", + "new_value": "//\\/", + "expected": { + "href": "file:///", + "pathname": "/" + } + }, + { + "comment": "File URLs and (back)slashes", + "href": "file:///unicorn", + "new_value": "//monkey/..//", + "expected": { + "href": "file:///", + "pathname": "/" + } + } + ], + "search": [ + { + "href": "https://example.net#nav", + "new_value": "lang=fr", + "expected": { + "href": "https://example.net/?lang=fr#nav", + "search": "?lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "lang=fr", + "expected": { + "href": "https://example.net/?lang=fr#nav", + "search": "?lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "?lang=fr", + "expected": { + "href": "https://example.net/?lang=fr#nav", + "search": "?lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "??lang=fr", + "expected": { + "href": "https://example.net/??lang=fr#nav", + "search": "??lang=fr" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "?", + "expected": { + "href": "https://example.net/?#nav", + "search": "" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "", + "expected": { + "href": "https://example.net/#nav", + "search": "" + } + }, + { + "href": "https://example.net?lang=en-US", + "new_value": "", + "expected": { + "href": "https://example.net/", + "search": "" + } + }, + { + "href": "https://example.net", + "new_value": "", + "expected": { + "href": "https://example.net/", + "search": "" + } + }, + { + "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.", + "href": "a:/", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + "search": "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://example.net/?%c3%89t%C3%A9", + "search": "?%c3%89t%C3%A9" + } + } + ], + "hash": [ + { + "href": "https://example.net", + "new_value": "main", + "expected": { + "href": "https://example.net/#main", + "hash": "#main" + } + }, + { + "href": "https://example.net#nav", + "new_value": "main", + "expected": { + "href": "https://example.net/#main", + "hash": "#main" + } + }, + { + "href": "https://example.net?lang=en-US", + "new_value": "##nav", + "expected": { + "href": "https://example.net/?lang=en-US##nav", + "hash": "##nav" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "#main", + "expected": { + "href": "https://example.net/?lang=en-US#main", + "hash": "#main" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "#", + "expected": { + "href": "https://example.net/?lang=en-US#", + "hash": "" + } + }, + { + "href": "https://example.net?lang=en-US#nav", + "new_value": "", + "expected": { + "href": "https://example.net/?lang=en-US", + "hash": "" + } + }, + { + "href": "http://example.net", + "new_value": "#foo bar", + "expected": { + "href": "http://example.net/#foo%20bar", + "hash": "#foo%20bar" + } + }, + { + "href": "http://example.net", + "new_value": "#foo\"bar", + "expected": { + "href": "http://example.net/#foo%22bar", + "hash": "#foo%22bar" + } + }, + { + "href": "http://example.net", + "new_value": "#foobar", + "expected": { + "href": "http://example.net/#foo%3Ebar", + "hash": "#foo%3Ebar" + } + }, + { + "href": "http://example.net", + "new_value": "#foo`bar", + "expected": { + "href": "http://example.net/#foo%60bar", + "hash": "#foo%60bar" + } + }, + { + "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed", + "href": "a:/", + "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", + "expected": { + "href": "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", + "hash": "#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" + } + }, + { + "comment": "Bytes already percent-encoded are left as-is", + "href": "http://example.net", + "new_value": "%c3%89té", + "expected": { + "href": "http://example.net/#%c3%89t%C3%A9", + "hash": "#%c3%89t%C3%A9" + } + }, + { + "href": "javascript:alert(1)", + "new_value": "castle", + "expected": { + "href": "javascript:alert(1)#castle", + "hash": "#castle" + } + } + ] +} diff --git a/test/fixtures/wpt/url/resources/toascii.json b/test/fixtures/wpt/url/resources/toascii.json new file mode 100644 index 00000000000000..814f06e794866d --- /dev/null +++ b/test/fixtures/wpt/url/resources/toascii.json @@ -0,0 +1,149 @@ +[ + "This resource is focused on highlighting issues with UTS #46 ToASCII", + { + "comment": "Label with hyphens in 3rd and 4th position", + "input": "aa--", + "output": "aa--" + }, + { + "input": "a†--", + "output": "xn--a---kp0a" + }, + { + "input": "ab--c", + "output": "ab--c" + }, + { + "comment": "Label with leading hyphen", + "input": "-x", + "output": "-x" + }, + { + "input": "-†", + "output": "xn----xhn" + }, + { + "input": "-x.xn--nxa", + "output": "-x.xn--nxa" + }, + { + "input": "-x.β", + "output": "-x.xn--nxa" + }, + { + "comment": "Label with trailing hyphen", + "input": "x-.xn--nxa", + "output": "x-.xn--nxa" + }, + { + "input": "x-.β", + "output": "x-.xn--nxa" + }, + { + "comment": "Empty labels", + "input": "x..xn--nxa", + "output": "x..xn--nxa" + }, + { + "input": "x..β", + "output": "x..xn--nxa" + }, + { + "comment": "Invalid Punycode", + "input": "xn--a", + "output": null + }, + { + "input": "xn--a.xn--nxa", + "output": null + }, + { + "input": "xn--a.β", + "output": null + }, + { + "comment": "Valid Punycode", + "input": "xn--nxa.xn--nxa", + "output": "xn--nxa.xn--nxa" + }, + { + "comment": "Mixed", + "input": "xn--nxa.β", + "output": "xn--nxa.xn--nxa" + }, + { + "input": "ab--c.xn--nxa", + "output": "ab--c.xn--nxa" + }, + { + "input": "ab--c.β", + "output": "ab--c.xn--nxa" + }, + { + "comment": "CheckJoiners is true", + "input": "\u200D.example", + "output": null + }, + { + "input": "xn--1ug.example", + "output": null + }, + { + "comment": "CheckBidi is true", + "input": "يa", + "output": null + }, + { + "input": "xn--a-yoc", + "output": null + }, + { + "comment": "processing_option is Nontransitional_Processing", + "input": "ශ්‍රී", + "output": "xn--10cl1a0b660p" + }, + { + "input": "نامه‌ای", + "output": "xn--mgba3gch31f060k" + }, + { + "comment": "U+FFFD", + "input": "\uFFFD.com", + "output": null + }, + { + "comment": "U+FFFD character encoded in Punycode", + "input": "xn--zn7c.com", + "output": null + }, + { + "comment": "Label longer than 63 code points", + "input": "x01234567890123456789012345678901234567890123456789012345678901x", + "output": "x01234567890123456789012345678901234567890123456789012345678901x" + }, + { + "input": "x01234567890123456789012345678901234567890123456789012345678901†", + "output": "xn--x01234567890123456789012345678901234567890123456789012345678901-6963b" + }, + { + "input": "x01234567890123456789012345678901234567890123456789012345678901x.xn--nxa", + "output": "x01234567890123456789012345678901234567890123456789012345678901x.xn--nxa" + }, + { + "input": "x01234567890123456789012345678901234567890123456789012345678901x.β", + "output": "x01234567890123456789012345678901234567890123456789012345678901x.xn--nxa" + }, + { + "comment": "Domain excluding TLD longer than 253 code points", + "input": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x", + "output": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x" + }, + { + "input": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--nxa", + "output": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--nxa" + }, + { + "input": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.β", + "output": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--nxa" + } +] diff --git a/test/fixtures/wpt/url/resources/urltestdata.json b/test/fixtures/wpt/url/resources/urltestdata.json new file mode 100644 index 00000000000000..26b8ea2e0bc9a1 --- /dev/null +++ b/test/fixtures/wpt/url/resources/urltestdata.json @@ -0,0 +1,6670 @@ +[ + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js", + { + "input": "http://example\t.\norg", + "base": "http://example.org/foo/bar", + "href": "http://example.org/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://user:pass@foo:21/bar;par?b#c", + "base": "http://example.org/foo/bar", + "href": "http://user:pass@foo:21/bar;par?b#c", + "origin": "http://foo:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "foo:21", + "hostname": "foo", + "port": "21", + "pathname": "/bar;par", + "search": "?b", + "hash": "#c" + }, + { + "input": "https://test:@test", + "base": "about:blank", + "href": "https://test@test/", + "origin": "https://test", + "protocol": "https:", + "username": "test", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://:@test", + "base": "about:blank", + "href": "https://test/", + "origin": "https://test", + "protocol": "https:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://test:@test/x", + "base": "about:blank", + "href": "non-special://test@test/x", + "origin": "null", + "protocol": "non-special:", + "username": "test", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "non-special://:@test/x", + "base": "about:blank", + "href": "non-special://test/x", + "origin": "null", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + { + "input": "http:foo.com", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/foo.com", + "search": "", + "hash": "" + }, + { + "input": "\t :foo.com \n", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com", + "search": "", + "hash": "" + }, + { + "input": " foo.com ", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/foo.com", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/foo.com", + "search": "", + "hash": "" + }, + { + "input": "a:\t foo.com", + "base": "http://example.org/foo/bar", + "href": "a: foo.com", + "origin": "null", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": " foo.com", + "search": "", + "hash": "" + }, + { + "input": "http://f:21/ b ? d # e ", + "base": "http://example.org/foo/bar", + "href": "http://f:21/%20b%20?%20d%20#%20e", + "origin": "http://f:21", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:21", + "hostname": "f", + "port": "21", + "pathname": "/%20b%20", + "search": "?%20d%20", + "hash": "#%20e" + }, + { + "input": "lolscheme:x x#x x", + "base": "about:blank", + "href": "lolscheme:x x#x%20x", + "protocol": "lolscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "x x", + "search": "", + "hash": "#x%20x" + }, + { + "input": "http://f:/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:0/c", + "base": "http://example.org/foo/bar", + "href": "http://f:0/c", + "origin": "http://f:0", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:0", + "hostname": "f", + "port": "0", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:00000000000000/c", + "base": "http://example.org/foo/bar", + "href": "http://f:0/c", + "origin": "http://f:0", + "protocol": "http:", + "username": "", + "password": "", + "host": "f:0", + "hostname": "f", + "port": "0", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:00000000000000000000080/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:b/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f: /c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f:\n/c", + "base": "http://example.org/foo/bar", + "href": "http://f/c", + "origin": "http://f", + "protocol": "http:", + "username": "", + "password": "", + "host": "f", + "hostname": "f", + "port": "", + "pathname": "/c", + "search": "", + "hash": "" + }, + { + "input": "http://f:fifty-two/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "non-special://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://f: 21 / b ? d # e ", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": " \t", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": ":foo.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com/", + "search": "", + "hash": "" + }, + { + "input": ":foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:foo.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:foo.com/", + "search": "", + "hash": "" + }, + { + "input": ":", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:", + "search": "", + "hash": "" + }, + { + "input": ":a", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:a", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:a", + "search": "", + "hash": "" + }, + { + "input": ":/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:/", + "search": "", + "hash": "" + }, + { + "input": ":\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:/", + "search": "", + "hash": "" + }, + { + "input": ":#", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:#", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:", + "search": "", + "hash": "" + }, + { + "input": "#", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "#/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#/" + }, + { + "input": "#\\", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#\\", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#\\" + }, + { + "input": "#;?", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#;?", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#;?" + }, + { + "input": "?", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar?", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": ":23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:23", + "search": "", + "hash": "" + }, + { + "input": "/:23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/:23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/:23", + "search": "", + "hash": "" + }, + { + "input": "::", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/::", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/::", + "search": "", + "hash": "" + }, + { + "input": "::23", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/::23", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/::23", + "search": "", + "hash": "" + }, + { + "input": "foo://", + "base": "http://example.org/foo/bar", + "href": "foo://", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@c:29/d", + "base": "http://example.org/foo/bar", + "href": "http://a:b@c:29/d", + "origin": "http://c:29", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "c:29", + "hostname": "c", + "port": "29", + "pathname": "/d", + "search": "", + "hash": "" + }, + { + "input": "http::@c:29", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/:@c:29", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/:@c:29", + "search": "", + "hash": "" + }, + { + "input": "http://&a:foo(b]c@d:2/", + "base": "http://example.org/foo/bar", + "href": "http://&a:foo(b%5Dc@d:2/", + "origin": "http://d:2", + "protocol": "http:", + "username": "&a", + "password": "foo(b%5Dc", + "host": "d:2", + "hostname": "d", + "port": "2", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://::@c@d:2", + "base": "http://example.org/foo/bar", + "href": "http://:%3A%40c@d:2/", + "origin": "http://d:2", + "protocol": "http:", + "username": "", + "password": "%3A%40c", + "host": "d:2", + "hostname": "d", + "port": "2", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo.com:b@d/", + "base": "http://example.org/foo/bar", + "href": "http://foo.com:b@d/", + "origin": "http://d", + "protocol": "http:", + "username": "foo.com", + "password": "b", + "host": "d", + "hostname": "d", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo.com/\\@", + "base": "http://example.org/foo/bar", + "href": "http://foo.com//@", + "origin": "http://foo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.com", + "hostname": "foo.com", + "port": "", + "pathname": "//@", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://foo.com/", + "origin": "http://foo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.com", + "hostname": "foo.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\a\\b:c\\d@foo.com\\", + "base": "http://example.org/foo/bar", + "href": "http://a/b:c/d@foo.com/", + "origin": "http://a", + "protocol": "http:", + "username": "", + "password": "", + "host": "a", + "hostname": "a", + "port": "", + "pathname": "/b:c/d@foo.com/", + "search": "", + "hash": "" + }, + { + "input": "foo:/", + "base": "http://example.org/foo/bar", + "href": "foo:/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "foo:/bar.com/", + "base": "http://example.org/foo/bar", + "href": "foo:/bar.com/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/bar.com/", + "search": "", + "hash": "" + }, + { + "input": "foo://///////", + "base": "http://example.org/foo/bar", + "href": "foo://///////", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///////", + "search": "", + "hash": "" + }, + { + "input": "foo://///////bar.com/", + "base": "http://example.org/foo/bar", + "href": "foo://///////bar.com/", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "///////bar.com/", + "search": "", + "hash": "" + }, + { + "input": "foo:////://///", + "base": "http://example.org/foo/bar", + "href": "foo:////://///", + "origin": "null", + "protocol": "foo:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//://///", + "search": "", + "hash": "" + }, + { + "input": "c:/foo", + "base": "http://example.org/foo/bar", + "href": "c:/foo", + "origin": "null", + "protocol": "c:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "//foo/bar", + "base": "http://example.org/foo/bar", + "href": "http://foo/bar", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/bar", + "search": "", + "hash": "" + }, + { + "input": "http://foo/path;a??e#f#g", + "base": "http://example.org/foo/bar", + "href": "http://foo/path;a??e#f#g", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/path;a", + "search": "??e", + "hash": "#f#g" + }, + { + "input": "http://foo/abcd?efgh?ijkl", + "base": "http://example.org/foo/bar", + "href": "http://foo/abcd?efgh?ijkl", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/abcd", + "search": "?efgh?ijkl", + "hash": "" + }, + { + "input": "http://foo/abcd#foo?bar", + "base": "http://example.org/foo/bar", + "href": "http://foo/abcd#foo?bar", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/abcd", + "search": "", + "hash": "#foo?bar" + }, + { + "input": "[61:24:74]:98", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/[61:24:74]:98", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/[61:24:74]:98", + "search": "", + "hash": "" + }, + { + "input": "http:[61:27]/:foo", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/[61:27]/:foo", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/[61:27]/:foo", + "search": "", + "hash": "" + }, + { + "input": "http://[1::2]:3:4", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1]", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://2001::1]:80", + "base": "http://example.org/foo/bar", + "failure": true + }, + { + "input": "http://[2001::1]", + "base": "http://example.org/foo/bar", + "href": "http://[2001::1]/", + "origin": "http://[2001::1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[2001::1]", + "hostname": "[2001::1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[::127.0.0.1]", + "base": "http://example.org/foo/bar", + "href": "http://[::7f00:1]/", + "origin": "http://[::7f00:1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[::7f00:1]", + "hostname": "[::7f00:1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[0:0:0:0:0:0:13.1.68.3]", + "base": "http://example.org/foo/bar", + "href": "http://[::d01:4403]/", + "origin": "http://[::d01:4403]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[::d01:4403]", + "hostname": "[::d01:4403]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[2001::1]:80", + "base": "http://example.org/foo/bar", + "href": "http://[2001::1]/", + "origin": "http://[2001::1]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[2001::1]", + "hostname": "[2001::1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/example.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/example.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftp:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:/example.com/", + "base": "http://example.org/foo/bar", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:/example.com/", + "base": "http://example.org/foo/bar", + "href": "madeupscheme:/example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file:/example.com/", + "base": "http://example.org/foo/bar", + "href": "file:///example.com/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file://example:1/", + "base": "about:blank", + "failure": true + }, + { + "input": "file://example:test/", + "base": "about:blank", + "failure": true + }, + { + "input": "file://example%/", + "base": "about:blank", + "failure": true + }, + { + "input": "file://[example]/", + "base": "about:blank", + "failure": true + }, + { + "input": "ftps:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ftps:/example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:/example.com/", + "base": "http://example.org/foo/bar", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:/example.com/", + "base": "http://example.org/foo/bar", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:/example.com/", + "base": "http://example.org/foo/bar", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/example.com/", + "base": "http://example.org/foo/bar", + "href": "data:/example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/example.com/", + "base": "http://example.org/foo/bar", + "href": "javascript:/example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/example.com/", + "base": "http://example.org/foo/bar", + "href": "mailto:/example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "http:example.com/", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/example.com/", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftp:example.com/", + "base": "http://example.org/foo/bar", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:example.com/", + "base": "http://example.org/foo/bar", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:example.com/", + "base": "http://example.org/foo/bar", + "href": "madeupscheme:example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:example.com/", + "base": "http://example.org/foo/bar", + "href": "ftps:example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:example.com/", + "base": "http://example.org/foo/bar", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:example.com/", + "base": "http://example.org/foo/bar", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:example.com/", + "base": "http://example.org/foo/bar", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:example.com/", + "base": "http://example.org/foo/bar", + "href": "data:example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:example.com/", + "base": "http://example.org/foo/bar", + "href": "javascript:example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:example.com/", + "base": "http://example.org/foo/bar", + "href": "mailto:example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "/a/b/c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/b/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/b/c", + "search": "", + "hash": "" + }, + { + "input": "/a/ /c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/%20/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/%20/c", + "search": "", + "hash": "" + }, + { + "input": "/a%2fc", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a%2fc", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a%2fc", + "search": "", + "hash": "" + }, + { + "input": "/a/%2f/c", + "base": "http://example.org/foo/bar", + "href": "http://example.org/a/%2f/c", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/a/%2f/c", + "search": "", + "hash": "" + }, + { + "input": "#β", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar#%CE%B2", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "#%CE%B2" + }, + { + "input": "data:text/html,test#test", + "base": "http://example.org/foo/bar", + "href": "data:text/html,test#test", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "text/html,test", + "search": "", + "hash": "#test" + }, + { + "input": "tel:1234567890", + "base": "http://example.org/foo/bar", + "href": "tel:1234567890", + "origin": "null", + "protocol": "tel:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "1234567890", + "search": "", + "hash": "" + }, + "# Based on https://felixfbecker.github.io/whatwg-url-custom-host-repro/", + { + "input": "ssh://example.com/foo/bar.git", + "base": "http://example.org/", + "href": "ssh://example.com/foo/bar.git", + "origin": "null", + "protocol": "ssh:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/bar.git", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html", + { + "input": "file:c:\\foo\\bar.html", + "base": "file:///tmp/mock/path", + "href": "file:///c:/foo/bar.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar.html", + "search": "", + "hash": "" + }, + { + "input": " File:c|////foo\\bar.html", + "base": "file:///tmp/mock/path", + "href": "file:///c:////foo/bar.html", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:////foo/bar.html", + "search": "", + "hash": "" + }, + { + "input": "C|/foo/bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/C|\\foo\\bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "//C|/foo/bar", + "base": "file:///tmp/mock/path", + "href": "file:///C:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "//server/file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "\\\\server\\file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "/\\server/file", + "base": "file:///tmp/mock/path", + "href": "file://server/file", + "protocol": "file:", + "username": "", + "password": "", + "host": "server", + "hostname": "server", + "port": "", + "pathname": "/file", + "search": "", + "hash": "" + }, + { + "input": "file:///foo/bar.txt", + "base": "file:///tmp/mock/path", + "href": "file:///foo/bar.txt", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/foo/bar.txt", + "search": "", + "hash": "" + }, + { + "input": "file:///home/me", + "base": "file:///tmp/mock/path", + "href": "file:///home/me", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/home/me", + "search": "", + "hash": "" + }, + { + "input": "//", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "///test", + "base": "file:///tmp/mock/path", + "href": "file:///test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "file://test", + "base": "file:///tmp/mock/path", + "href": "file://test/", + "protocol": "file:", + "username": "", + "password": "", + "host": "test", + "hostname": "test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost/", + "base": "file:///tmp/mock/path", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file://localhost/test", + "base": "file:///tmp/mock/path", + "href": "file:///test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "test", + "base": "file:///tmp/mock/path", + "href": "file:///tmp/mock/test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/tmp/mock/test", + "search": "", + "hash": "" + }, + { + "input": "file:test", + "base": "file:///tmp/mock/path", + "href": "file:///tmp/mock/test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/tmp/mock/test", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js", + { + "input": "http://example.com/././foo", + "base": "about:blank", + "href": "http://example.com/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/./.foo", + "base": "about:blank", + "href": "http://example.com/.foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/.foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/.", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/./", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/..", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/..bar", + "base": "about:blank", + "href": "http://example.com/foo/..bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/..bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../ton", + "base": "about:blank", + "href": "http://example.com/foo/ton", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/ton", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar/../ton/../../a", + "base": "about:blank", + "href": "http://example.com/a", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/a", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/../../..", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/../../../ton", + "base": "about:blank", + "href": "http://example.com/ton", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/ton", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e%2", + "base": "about:blank", + "href": "http://example.com/foo/%2e%2", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/%2e%2", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar", + "base": "about:blank", + "href": "http://example.com/%2e.bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%2e.bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com////../..", + "base": "about:blank", + "href": "http://example.com//", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar//../..", + "base": "about:blank", + "href": "http://example.com/foo/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo/bar//..", + "base": "about:blank", + "href": "http://example.com/foo/bar/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo/bar/", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo", + "base": "about:blank", + "href": "http://example.com/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%20foo", + "base": "about:blank", + "href": "http://example.com/%20foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%20foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%", + "base": "about:blank", + "href": "http://example.com/foo%", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2", + "base": "about:blank", + "href": "http://example.com/foo%2", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2zbar", + "base": "about:blank", + "href": "http://example.com/foo%2zbar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2zbar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%2©zbar", + "base": "about:blank", + "href": "http://example.com/foo%2%C3%82%C2%A9zbar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%2%C3%82%C2%A9zbar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%41%7a", + "base": "about:blank", + "href": "http://example.com/foo%41%7a", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%41%7a", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo\t\u0091%91", + "base": "about:blank", + "href": "http://example.com/foo%C2%91%91", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%C2%91%91", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo%00%51", + "base": "about:blank", + "href": "http://example.com/foo%00%51", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foo%00%51", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/(%28:%3A%29)", + "base": "about:blank", + "href": "http://example.com/(%28:%3A%29)", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/(%28:%3A%29)", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%3A%3a%3C%3c", + "base": "about:blank", + "href": "http://example.com/%3A%3a%3C%3c", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%3A%3a%3C%3c", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/foo\tbar", + "base": "about:blank", + "href": "http://example.com/foobar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/foobar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com\\\\foo\\\\bar", + "base": "about:blank", + "href": "http://example.com//foo//bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "//foo//bar", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", + "base": "about:blank", + "href": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%7Ffp3%3Eju%3Dduvgw%3Dd", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/@asdf%40", + "base": "about:blank", + "href": "http://example.com/@asdf%40", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/@asdf%40", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/你好你好", + "base": "about:blank", + "href": "http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/‥/foo", + "base": "about:blank", + "href": "http://example.com/%E2%80%A5/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E2%80%A5/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com//foo", + "base": "about:blank", + "href": "http://example.com/%EF%BB%BF/foo", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%EF%BB%BF/foo", + "search": "", + "hash": "" + }, + { + "input": "http://example.com/‮/foo/‭/bar", + "base": "about:blank", + "href": "http://example.com/%E2%80%AE/foo/%E2%80%AD/bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/%E2%80%AE/foo/%E2%80%AD/bar", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js", + { + "input": "http://www.google.com/foo?bar=baz#", + "base": "about:blank", + "href": "http://www.google.com/foo?bar=baz#", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "?bar=baz", + "hash": "" + }, + { + "input": "http://www.google.com/foo?bar=baz# »", + "base": "about:blank", + "href": "http://www.google.com/foo?bar=baz#%20%C2%BB", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "?bar=baz", + "hash": "#%20%C2%BB" + }, + { + "input": "data:test# »", + "base": "about:blank", + "href": "data:test#%20%C2%BB", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "", + "hash": "#%20%C2%BB" + }, + { + "input": "http://www.google.com", + "base": "about:blank", + "href": "http://www.google.com/", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.0x00A80001", + "base": "about:blank", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://www/foo%2Ehtml", + "base": "about:blank", + "href": "http://www/foo%2Ehtml", + "origin": "http://www", + "protocol": "http:", + "username": "", + "password": "", + "host": "www", + "hostname": "www", + "port": "", + "pathname": "/foo%2Ehtml", + "search": "", + "hash": "" + }, + { + "input": "http://www/foo/%2E/html", + "base": "about:blank", + "href": "http://www/foo/html", + "origin": "http://www", + "protocol": "http:", + "username": "", + "password": "", + "host": "www", + "hostname": "www", + "port": "", + "pathname": "/foo/html", + "search": "", + "hash": "" + }, + { + "input": "http://user:pass@/", + "base": "about:blank", + "failure": true + }, + { + "input": "http://%25DOMAIN:foobar@foodomain.com/", + "base": "about:blank", + "href": "http://%25DOMAIN:foobar@foodomain.com/", + "origin": "http://foodomain.com", + "protocol": "http:", + "username": "%25DOMAIN", + "password": "foobar", + "host": "foodomain.com", + "hostname": "foodomain.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:\\\\www.google.com\\foo", + "base": "about:blank", + "href": "http://www.google.com/foo", + "origin": "http://www.google.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.google.com", + "hostname": "www.google.com", + "port": "", + "pathname": "/foo", + "search": "", + "hash": "" + }, + { + "input": "http://foo:80/", + "base": "about:blank", + "href": "http://foo/", + "origin": "http://foo", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo:81/", + "base": "about:blank", + "href": "http://foo:81/", + "origin": "http://foo:81", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "httpa://foo:80/", + "base": "about:blank", + "href": "httpa://foo:80/", + "origin": "null", + "protocol": "httpa:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://foo:-80/", + "base": "about:blank", + "failure": true + }, + { + "input": "https://foo:443/", + "base": "about:blank", + "href": "https://foo/", + "origin": "https://foo", + "protocol": "https:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://foo:80/", + "base": "about:blank", + "href": "https://foo:80/", + "origin": "https://foo:80", + "protocol": "https:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp://foo:21/", + "base": "about:blank", + "href": "ftp://foo/", + "origin": "ftp://foo", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp://foo:80/", + "base": "about:blank", + "href": "ftp://foo:80/", + "origin": "ftp://foo:80", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "gopher://foo:70/", + "base": "about:blank", + "href": "gopher://foo/", + "origin": "gopher://foo", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "gopher://foo:443/", + "base": "about:blank", + "href": "gopher://foo:443/", + "origin": "gopher://foo:443", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "foo:443", + "hostname": "foo", + "port": "443", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:80/", + "base": "about:blank", + "href": "ws://foo/", + "origin": "ws://foo", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:81/", + "base": "about:blank", + "href": "ws://foo:81/", + "origin": "ws://foo:81", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:443/", + "base": "about:blank", + "href": "ws://foo:443/", + "origin": "ws://foo:443", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:443", + "hostname": "foo", + "port": "443", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws://foo:815/", + "base": "about:blank", + "href": "ws://foo:815/", + "origin": "ws://foo:815", + "protocol": "ws:", + "username": "", + "password": "", + "host": "foo:815", + "hostname": "foo", + "port": "815", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:80/", + "base": "about:blank", + "href": "wss://foo:80/", + "origin": "wss://foo:80", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:80", + "hostname": "foo", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:81/", + "base": "about:blank", + "href": "wss://foo:81/", + "origin": "wss://foo:81", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:81", + "hostname": "foo", + "port": "81", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:443/", + "base": "about:blank", + "href": "wss://foo/", + "origin": "wss://foo", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo", + "hostname": "foo", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss://foo:815/", + "base": "about:blank", + "href": "wss://foo:815/", + "origin": "wss://foo:815", + "protocol": "wss:", + "username": "", + "password": "", + "host": "foo:815", + "hostname": "foo", + "port": "815", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/example.com/", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp:/example.com/", + "base": "about:blank", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:/example.com/", + "base": "about:blank", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:/example.com/", + "base": "about:blank", + "href": "madeupscheme:/example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "file:/example.com/", + "base": "about:blank", + "href": "file:///example.com/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:/example.com/", + "base": "about:blank", + "href": "ftps:/example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:/example.com/", + "base": "about:blank", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:/example.com/", + "base": "about:blank", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:/example.com/", + "base": "about:blank", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/example.com/", + "base": "about:blank", + "href": "data:/example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/example.com/", + "base": "about:blank", + "href": "javascript:/example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/example.com/", + "base": "about:blank", + "href": "mailto:/example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/example.com/", + "search": "", + "hash": "" + }, + { + "input": "http:example.com/", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ftp:example.com/", + "base": "about:blank", + "href": "ftp://example.com/", + "origin": "ftp://example.com", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https:example.com/", + "base": "about:blank", + "href": "https://example.com/", + "origin": "https://example.com", + "protocol": "https:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "madeupscheme:example.com/", + "base": "about:blank", + "href": "madeupscheme:example.com/", + "origin": "null", + "protocol": "madeupscheme:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "ftps:example.com/", + "base": "about:blank", + "href": "ftps:example.com/", + "origin": "null", + "protocol": "ftps:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "gopher:example.com/", + "base": "about:blank", + "href": "gopher://example.com/", + "origin": "gopher://example.com", + "protocol": "gopher:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ws:example.com/", + "base": "about:blank", + "href": "ws://example.com/", + "origin": "ws://example.com", + "protocol": "ws:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "wss:example.com/", + "base": "about:blank", + "href": "wss://example.com/", + "origin": "wss://example.com", + "protocol": "wss:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:example.com/", + "base": "about:blank", + "href": "data:example.com/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "javascript:example.com/", + "base": "about:blank", + "href": "javascript:example.com/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + { + "input": "mailto:example.com/", + "base": "about:blank", + "href": "mailto:example.com/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "example.com/", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html", + { + "input": "http:@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:a:b@www.example.com", + "base": "about:blank", + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/a:b@www.example.com", + "base": "about:blank", + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:b@www.example.com", + "base": "about:blank", + "href": "http://a:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://@pple.com", + "base": "about:blank", + "href": "http://pple.com/", + "origin": "http://pple.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "pple.com", + "hostname": "pple.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http::b@www.example.com", + "base": "about:blank", + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/:b@www.example.com", + "base": "about:blank", + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://:b@www.example.com", + "base": "about:blank", + "href": "http://:b@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "b", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/:@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://user@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:/@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "https:@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:a:b@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:/a:b@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://a:b@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http::@/www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:a:@www.example.com", + "base": "about:blank", + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:/a:@www.example.com", + "base": "about:blank", + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://a:@www.example.com", + "base": "about:blank", + "href": "http://a@www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "a", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://www.@pple.com", + "base": "about:blank", + "href": "http://www.@pple.com/", + "origin": "http://pple.com", + "protocol": "http:", + "username": "www.", + "password": "", + "host": "pple.com", + "hostname": "pple.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http:@:www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http:/@:www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://@:www.example.com", + "base": "about:blank", + "failure": true + }, + { + "input": "http://:@www.example.com", + "base": "about:blank", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# Others", + { + "input": "/", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": ".", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "http://www.example.com/test", + "href": "http://www.example.com/", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "./test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../aaa/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/aaa/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/aaa/test.txt", + "search": "", + "hash": "" + }, + { + "input": "../../test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/test.txt", + "search": "", + "hash": "" + }, + { + "input": "中/test.txt", + "base": "http://www.example.com/test", + "href": "http://www.example.com/%E4%B8%AD/test.txt", + "origin": "http://www.example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example.com", + "hostname": "www.example.com", + "port": "", + "pathname": "/%E4%B8%AD/test.txt", + "search": "", + "hash": "" + }, + { + "input": "http://www.example2.com", + "base": "http://www.example.com/test", + "href": "http://www.example2.com/", + "origin": "http://www.example2.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example2.com", + "hostname": "www.example2.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "//www.example2.com", + "base": "http://www.example.com/test", + "href": "http://www.example2.com/", + "origin": "http://www.example2.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.example2.com", + "hostname": "www.example2.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:...", + "base": "http://www.example.com/test", + "href": "file:///...", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/...", + "search": "", + "hash": "" + }, + { + "input": "file:..", + "base": "http://www.example.com/test", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:a", + "base": "http://www.example.com/test", + "href": "file:///a", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/a", + "search": "", + "hash": "" + }, + "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html", + "Basic canonicalization, uppercase should be converted to lowercase", + { + "input": "http://ExAmPlE.CoM", + "base": "http://other.com/", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://example example.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://Goo%20 goo%7C|.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[:]", + "base": "http://other.com/", + "failure": true + }, + "U+3000 is mapped to U+0020 (space) which is disallowed", + { + "input": "http://GOO\u00a0\u3000goo.com", + "base": "http://other.com/", + "failure": true + }, + "Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored", + { + "input": "http://GOO\u200b\u2060\ufeffgoo.com", + "base": "http://other.com/", + "href": "http://googoo.com/", + "origin": "http://googoo.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "googoo.com", + "hostname": "googoo.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Leading and trailing C0 control or space", + { + "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ", + "base": "about:blank", + "href": "http://example.com/", + "origin": "http://example.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)", + { + "input": "http://www.foo。bar.com", + "base": "http://other.com/", + "href": "http://www.foo.bar.com/", + "origin": "http://www.foo.bar.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "www.foo.bar.com", + "hostname": "www.foo.bar.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0", + { + "input": "http://\ufdd0zyx.com", + "base": "http://other.com/", + "failure": true + }, + "This is the same as previous but escaped", + { + "input": "http://%ef%b7%90zyx.com", + "base": "http://other.com/", + "failure": true + }, + "U+FFFD", + { + "input": "https://\ufffd", + "base": "about:blank", + "failure": true + }, + { + "input": "https://%EF%BF%BD", + "base": "about:blank", + "failure": true + }, + { + "input": "https://x/\ufffd?\ufffd#\ufffd", + "base": "about:blank", + "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD", + "origin": "https://x", + "protocol": "https:", + "username": "", + "password": "", + "host": "x", + "hostname": "x", + "port": "", + "pathname": "/%EF%BF%BD", + "search": "?%EF%BF%BD", + "hash": "#%EF%BF%BD" + }, + "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", + { + "input": "http://Go.com", + "base": "http://other.com/", + "href": "http://go.com/", + "origin": "http://go.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "go.com", + "hostname": "go.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257", + { + "input": "http://%41.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%ef%bc%85%ef%bc%94%ef%bc%91.com", + "base": "http://other.com/", + "failure": true + }, + "...%00 in fullwidth should fail (also as escaped UTF-8 input)", + { + "input": "http://%00.com", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://%ef%bc%85%ef%bc%90%ef%bc%90.com", + "base": "http://other.com/", + "failure": true + }, + "Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN", + { + "input": "http://你好你好", + "base": "http://other.com/", + "href": "http://xn--6qqa088eba/", + "origin": "http://xn--6qqa088eba", + "protocol": "http:", + "username": "", + "password": "", + "host": "xn--6qqa088eba", + "hostname": "xn--6qqa088eba", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://faß.ExAmPlE/", + "base": "about:blank", + "href": "https://xn--fa-hia.example/", + "origin": "https://xn--fa-hia.example", + "protocol": "https:", + "username": "", + "password": "", + "host": "xn--fa-hia.example", + "hostname": "xn--fa-hia.example", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://faß.ExAmPlE/", + "base": "about:blank", + "href": "sc://fa%C3%9F.ExAmPlE/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "fa%C3%9F.ExAmPlE", + "hostname": "fa%C3%9F.ExAmPlE", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191", + { + "input": "http://%zz%66%a.com", + "base": "http://other.com/", + "failure": true + }, + "If we get an invalid character that has been escaped.", + { + "input": "http://%25", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://hello%00", + "base": "http://other.com/", + "failure": true + }, + "Escaped numbers should be treated like IP addresses if they are.", + { + "input": "http://%30%78%63%30%2e%30%32%35%30.01", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://%30%78%63%30%2e%30%32%35%30.01%2e", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.0.257", + "base": "http://other.com/", + "failure": true + }, + "Invalid escaping in hosts causes failure", + { + "input": "http://%3g%78%63%30%2e%30%32%35%30%2E.01", + "base": "http://other.com/", + "failure": true + }, + "A space in a host causes failure", + { + "input": "http://192.168.0.1 hello", + "base": "http://other.com/", + "failure": true + }, + { + "input": "https://x x:12", + "base": "about:blank", + "failure": true + }, + "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP", + { + "input": "http://0Xc0.0250.01", + "base": "http://other.com/", + "href": "http://192.168.0.1/", + "origin": "http://192.168.0.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.0.1", + "hostname": "192.168.0.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Domains with empty labels", + { + "input": "http://./", + "base": "about:blank", + "href": "http://./", + "origin": "http://.", + "protocol": "http:", + "username": "", + "password": "", + "host": ".", + "hostname": ".", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://../", + "base": "about:blank", + "href": "http://../", + "origin": "http://..", + "protocol": "http:", + "username": "", + "password": "", + "host": "..", + "hostname": "..", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0..0x300/", + "base": "about:blank", + "href": "http://0..0x300/", + "origin": "http://0..0x300", + "protocol": "http:", + "username": "", + "password": "", + "host": "0..0x300", + "hostname": "0..0x300", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Broken IPv6", + { + "input": "http://[www.google.com]/", + "base": "about:blank", + "failure": true + }, + { + "input": "http://[google.com]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.3.4x]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.3.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.2.]", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://[::1.]", + "base": "http://other.com/", + "failure": true + }, + "Misc Unicode", + { + "input": "http://foo:💩@example.com/bar", + "base": "http://other.com/", + "href": "http://foo:%F0%9F%92%A9@example.com/bar", + "origin": "http://example.com", + "protocol": "http:", + "username": "foo", + "password": "%F0%9F%92%A9", + "host": "example.com", + "hostname": "example.com", + "port": "", + "pathname": "/bar", + "search": "", + "hash": "" + }, + "# resolving a fragment against any scheme succeeds", + { + "input": "#", + "base": "test:test", + "href": "test:test#", + "origin": "null", + "protocol": "test:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "", + "hash": "" + }, + { + "input": "#x", + "base": "mailto:x@x.com", + "href": "mailto:x@x.com#x", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "x@x.com", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "data:,", + "href": "data:,#x", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": ",", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "about:blank", + "href": "about:blank#x", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "blank", + "search": "", + "hash": "#x" + }, + { + "input": "#", + "base": "test:test?test", + "href": "test:test?test#", + "origin": "null", + "protocol": "test:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "test", + "search": "?test", + "hash": "" + }, + "# multiple @ in authority state", + { + "input": "https://@test@test@example:800/", + "base": "http://doesnotmatter/", + "href": "https://%40test%40test@example:800/", + "origin": "https://example:800", + "protocol": "https:", + "username": "%40test%40test", + "password": "", + "host": "example:800", + "hostname": "example", + "port": "800", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://@@@example", + "base": "http://doesnotmatter/", + "href": "https://%40%40@example/", + "origin": "https://example", + "protocol": "https:", + "username": "%40%40", + "password": "", + "host": "example", + "hostname": "example", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "non-az-09 characters", + { + "input": "http://`{}:`{}@h/`{}?`{}", + "base": "http://doesnotmatter/", + "href": "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}", + "origin": "http://h", + "protocol": "http:", + "username": "%60%7B%7D", + "password": "%60%7B%7D", + "host": "h", + "hostname": "h", + "port": "", + "pathname": "/%60%7B%7D", + "search": "?`{}", + "hash": "" + }, + "byte is ' and url is special", + { + "input": "http://host/?'", + "base": "about:blank", + "href": "http://host/?%27", + "origin": "http://host", + "protocol": "http:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/", + "search": "?%27", + "hash": "" + }, + { + "input": "notspecial://host/?'", + "base": "about:blank", + "href": "notspecial://host/?'", + "origin": "null", + "protocol": "notspecial:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/", + "search": "?'", + "hash": "" + }, + "# Credentials in base", + { + "input": "/some/path", + "base": "http://user@example.org/smth", + "href": "http://user@example.org/some/path", + "origin": "http://example.org", + "protocol": "http:", + "username": "user", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/some/path", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "http://user:pass@example.org:21/smth", + "href": "http://user:pass@example.org:21/smth", + "origin": "http://example.org:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "example.org:21", + "hostname": "example.org", + "port": "21", + "pathname": "/smth", + "search": "", + "hash": "" + }, + { + "input": "/some/path", + "base": "http://user:pass@example.org:21/smth", + "href": "http://user:pass@example.org:21/some/path", + "origin": "http://example.org:21", + "protocol": "http:", + "username": "user", + "password": "pass", + "host": "example.org:21", + "hostname": "example.org", + "port": "21", + "pathname": "/some/path", + "search": "", + "hash": "" + }, + "# a set of tests designed by zcorpan for relative URLs with unknown schemes", + { + "input": "i", + "base": "sc:sd", + "failure": true + }, + { + "input": "i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "i", + "base": "sc:/pa/pa", + "href": "sc:/pa/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/i", + "search": "", + "hash": "" + }, + { + "input": "i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "i", + "base": "sc:///pa/pa", + "href": "sc:///pa/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc:sd", + "failure": true + }, + { + "input": "../i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "../i", + "base": "sc:/pa/pa", + "href": "sc:/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "../i", + "base": "sc:///pa/pa", + "href": "sc:///i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc:sd", + "failure": true + }, + { + "input": "/i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "/i", + "base": "sc:/pa/pa", + "href": "sc:/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc://ho/pa", + "href": "sc://ho/i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "/i", + "base": "sc:///pa/pa", + "href": "sc:///i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/i", + "search": "", + "hash": "" + }, + { + "input": "?i", + "base": "sc:sd", + "failure": true + }, + { + "input": "?i", + "base": "sc:sd/sd", + "failure": true + }, + { + "input": "?i", + "base": "sc:/pa/pa", + "href": "sc:/pa/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "?i", + "hash": "" + }, + { + "input": "?i", + "base": "sc://ho/pa", + "href": "sc://ho/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/pa", + "search": "?i", + "hash": "" + }, + { + "input": "?i", + "base": "sc:///pa/pa", + "href": "sc:///pa/pa?i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "?i", + "hash": "" + }, + { + "input": "#i", + "base": "sc:sd", + "href": "sc:sd#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "sd", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:sd/sd", + "href": "sc:sd/sd#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "sd/sd", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:/pa/pa", + "href": "sc:/pa/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc://ho/pa", + "href": "sc://ho/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "ho", + "hostname": "ho", + "port": "", + "pathname": "/pa", + "search": "", + "hash": "#i" + }, + { + "input": "#i", + "base": "sc:///pa/pa", + "href": "sc:///pa/pa#i", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pa/pa", + "search": "", + "hash": "#i" + }, + "# make sure that relative URL logic works on known typically non-relative schemes too", + { + "input": "about:/../", + "base": "about:blank", + "href": "about:/", + "origin": "null", + "protocol": "about:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "data:/../", + "base": "about:blank", + "href": "data:/", + "origin": "null", + "protocol": "data:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "javascript:/../", + "base": "about:blank", + "href": "javascript:/", + "origin": "null", + "protocol": "javascript:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "mailto:/../", + "base": "about:blank", + "href": "mailto:/", + "origin": "null", + "protocol": "mailto:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# unknown schemes and their hosts", + { + "input": "sc://ñ.test/", + "base": "about:blank", + "href": "sc://%C3%B1.test/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1.test", + "hostname": "%C3%B1.test", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://\u001F!\"$&'()*+,-.;<=>^_`{|}~/", + "base": "about:blank", + "href": "sc://%1F!\"$&'()*+,-.;<=>^_`{|}~/", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%1F!\"$&'()*+,-.;<=>^_`{|}~", + "hostname": "%1F!\"$&'()*+,-.;<=>^_`{|}~", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://\u0000/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc:// /", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://%/", + "base": "about:blank", + "href": "sc://%/", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%", + "hostname": "%", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "sc://@/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://te@s:t@/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://:/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://:12/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://[/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://\\/", + "base": "about:blank", + "failure": true + }, + { + "input": "sc://]/", + "base": "about:blank", + "failure": true + }, + { + "input": "x", + "base": "sc://ñ", + "href": "sc://%C3%B1/x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "/x", + "search": "", + "hash": "" + }, + "# unknown schemes and backslashes", + { + "input": "sc:\\../", + "base": "about:blank", + "href": "sc:\\../", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "\\../", + "search": "", + "hash": "" + }, + "# unknown scheme with path looking like a password", + { + "input": "sc::a@example.net", + "base": "about:blank", + "href": "sc::a@example.net", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": ":a@example.net", + "search": "", + "hash": "" + }, + "# unknown scheme with bogus percent-encoding", + { + "input": "wow:%NBD", + "base": "about:blank", + "href": "wow:%NBD", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%NBD", + "search": "", + "hash": "" + }, + { + "input": "wow:%1G", + "base": "about:blank", + "href": "wow:%1G", + "origin": "null", + "protocol": "wow:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "%1G", + "search": "", + "hash": "" + }, + "# Hosts and percent-encoding", + { + "input": "ftp://example.com%80/", + "base": "about:blank", + "failure": true + }, + { + "input": "ftp://example.com%A0/", + "base": "about:blank", + "failure": true + }, + { + "input": "https://example.com%80/", + "base": "about:blank", + "failure": true + }, + { + "input": "https://example.com%A0/", + "base": "about:blank", + "failure": true + }, + { + "input": "ftp://%e2%98%83", + "base": "about:blank", + "href": "ftp://xn--n3h/", + "origin": "ftp://xn--n3h", + "protocol": "ftp:", + "username": "", + "password": "", + "host": "xn--n3h", + "hostname": "xn--n3h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://%e2%98%83", + "base": "about:blank", + "href": "https://xn--n3h/", + "origin": "https://xn--n3h", + "protocol": "https:", + "username": "", + "password": "", + "host": "xn--n3h", + "hostname": "xn--n3h", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# tests from jsdom/whatwg-url designed for code coverage", + { + "input": "http://127.0.0.1:10100/relative_import.html", + "base": "about:blank", + "href": "http://127.0.0.1:10100/relative_import.html", + "origin": "http://127.0.0.1:10100", + "protocol": "http:", + "username": "", + "password": "", + "host": "127.0.0.1:10100", + "hostname": "127.0.0.1", + "port": "10100", + "pathname": "/relative_import.html", + "search": "", + "hash": "" + }, + { + "input": "http://facebook.com/?foo=%7B%22abc%22", + "base": "about:blank", + "href": "http://facebook.com/?foo=%7B%22abc%22", + "origin": "http://facebook.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "facebook.com", + "hostname": "facebook.com", + "port": "", + "pathname": "/", + "search": "?foo=%7B%22abc%22", + "hash": "" + }, + { + "input": "https://localhost:3000/jqueryui@1.2.3", + "base": "about:blank", + "href": "https://localhost:3000/jqueryui@1.2.3", + "origin": "https://localhost:3000", + "protocol": "https:", + "username": "", + "password": "", + "host": "localhost:3000", + "hostname": "localhost", + "port": "3000", + "pathname": "/jqueryui@1.2.3", + "search": "", + "hash": "" + }, + "# tab/LF/CR", + { + "input": "h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg", + "base": "about:blank", + "href": "http://host:9000/path?query#frag", + "origin": "http://host:9000", + "protocol": "http:", + "username": "", + "password": "", + "host": "host:9000", + "hostname": "host", + "port": "9000", + "pathname": "/path", + "search": "?query", + "hash": "#frag" + }, + "# Stringification of URL.searchParams", + { + "input": "?a=b&c=d", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar?a=b&c=d", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "?a=b&c=d", + "searchParams": "a=b&c=d", + "hash": "" + }, + { + "input": "??a=b&c=d", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar??a=b&c=d", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "??a=b&c=d", + "searchParams": "%3Fa=b&c=d", + "hash": "" + }, + "# Scheme only", + { + "input": "http:", + "base": "http://example.org/foo/bar", + "href": "http://example.org/foo/bar", + "origin": "http://example.org", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/foo/bar", + "search": "", + "searchParams": "", + "hash": "" + }, + { + "input": "http:", + "base": "https://example.org/foo/bar", + "failure": true + }, + { + "input": "sc:", + "base": "https://example.org/foo/bar", + "href": "sc:", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "searchParams": "", + "hash": "" + }, + "# Percent encoding of fragments", + { + "input": "http://foo.bar/baz?qux#foo\bbar", + "base": "about:blank", + "href": "http://foo.bar/baz?qux#foo%08bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%08bar" + }, + { + "input": "http://foo.bar/baz?qux#foo\"bar", + "base": "about:blank", + "href": "http://foo.bar/baz?qux#foo%22bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%22bar" + }, + { + "input": "http://foo.bar/baz?qux#foobar", + "base": "about:blank", + "href": "http://foo.bar/baz?qux#foo%3Ebar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%3Ebar" + }, + { + "input": "http://foo.bar/baz?qux#foo`bar", + "base": "about:blank", + "href": "http://foo.bar/baz?qux#foo%60bar", + "origin": "http://foo.bar", + "protocol": "http:", + "username": "", + "password": "", + "host": "foo.bar", + "hostname": "foo.bar", + "port": "", + "pathname": "/baz", + "search": "?qux", + "searchParams": "qux=", + "hash": "#foo%60bar" + }, + "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)", + { + "input": "http://192.168.257", + "base": "http://other.com/", + "href": "http://192.168.1.1/", + "origin": "http://192.168.1.1", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.1.1", + "hostname": "192.168.1.1", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://192.168.257.com", + "base": "http://other.com/", + "href": "http://192.168.257.com/", + "origin": "http://192.168.257.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "192.168.257.com", + "hostname": "192.168.257.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://256", + "base": "http://other.com/", + "href": "http://0.0.1.0/", + "origin": "http://0.0.1.0", + "protocol": "http:", + "username": "", + "password": "", + "host": "0.0.1.0", + "hostname": "0.0.1.0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://256.com", + "base": "http://other.com/", + "href": "http://256.com/", + "origin": "http://256.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "256.com", + "hostname": "256.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999", + "base": "http://other.com/", + "href": "http://59.154.201.255/", + "origin": "http://59.154.201.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "59.154.201.255", + "hostname": "59.154.201.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://999999999.com", + "base": "http://other.com/", + "href": "http://999999999.com/", + "origin": "http://999999999.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "999999999.com", + "hostname": "999999999.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://10000000000", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://10000000000.com", + "base": "http://other.com/", + "href": "http://10000000000.com/", + "origin": "http://10000000000.com", + "protocol": "http:", + "username": "", + "password": "", + "host": "10000000000.com", + "hostname": "10000000000.com", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://4294967295", + "base": "http://other.com/", + "href": "http://255.255.255.255/", + "origin": "http://255.255.255.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "255.255.255.255", + "hostname": "255.255.255.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://4294967296", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://0xffffffff", + "base": "http://other.com/", + "href": "http://255.255.255.255/", + "origin": "http://255.255.255.255", + "protocol": "http:", + "username": "", + "password": "", + "host": "255.255.255.255", + "hostname": "255.255.255.255", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0xffffffff1", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://256.256.256.256", + "base": "http://other.com/", + "failure": true + }, + { + "input": "http://256.256.256.256.256", + "base": "http://other.com/", + "href": "http://256.256.256.256.256/", + "origin": "http://256.256.256.256.256", + "protocol": "http:", + "username": "", + "password": "", + "host": "256.256.256.256.256", + "hostname": "256.256.256.256.256", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "https://0x.0x.0", + "base": "about:blank", + "href": "https://0.0.0.0/", + "origin": "https://0.0.0.0", + "protocol": "https:", + "username": "", + "password": "", + "host": "0.0.0.0", + "hostname": "0.0.0.0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)", + { + "input": "https://0x100000000/test", + "base": "about:blank", + "failure": true + }, + { + "input": "https://256.0.0.1/test", + "base": "about:blank", + "failure": true + }, + "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", + { + "input": "file:///C%3A/", + "base": "about:blank", + "href": "file:///C%3A/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C%3A/", + "search": "", + "hash": "" + }, + { + "input": "file:///C%7C/", + "base": "about:blank", + "href": "file:///C%7C/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C%7C/", + "search": "", + "hash": "" + }, + "# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)", + { + "input": "pix/submit.gif", + "base": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html", + "href": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///C:/", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# More file URL tests by zcorpan and annevk", + { + "input": "/", + "base": "file:///C:/a/b", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "//d:", + "base": "file:///C:/a/b", + "href": "file:///d:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/d:", + "search": "", + "hash": "" + }, + { + "input": "//d:/..", + "base": "file:///C:/a/b", + "href": "file:///d:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/d:/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///ab:/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "..", + "base": "file:///1:/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "", + "base": "file:///test?test#test", + "href": "file:///test?test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "" + }, + { + "input": "file:", + "base": "file:///test?test#test", + "href": "file:///test?test", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "" + }, + { + "input": "?x", + "base": "file:///test?test#test", + "href": "file:///test?x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?x", + "hash": "" + }, + { + "input": "file:?x", + "base": "file:///test?test#test", + "href": "file:///test?x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?x", + "hash": "" + }, + { + "input": "#x", + "base": "file:///test?test#test", + "href": "file:///test?test#x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "#x" + }, + { + "input": "file:#x", + "base": "file:///test?test#test", + "href": "file:///test?test#x", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test", + "search": "?test", + "hash": "#x" + }, + "# File URLs and many (back)slashes", + { + "input": "file:\\\\//", + "base": "about:blank", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:\\\\\\\\", + "base": "about:blank", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:\\\\\\\\?fox", + "base": "about:blank", + "href": "file:///?fox", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "?fox", + "hash": "" + }, + { + "input": "file:\\\\\\\\#guppy", + "base": "about:blank", + "href": "file:///#guppy", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "#guppy" + }, + { + "input": "file://spider///", + "base": "about:blank", + "href": "file://spider/", + "protocol": "file:", + "username": "", + "password": "", + "host": "spider", + "hostname": "spider", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:\\\\localhost//", + "base": "about:blank", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:///localhost//cat", + "base": "about:blank", + "href": "file:///localhost//cat", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/localhost//cat", + "search": "", + "hash": "" + }, + { + "input": "file://\\/localhost//cat", + "base": "about:blank", + "href": "file:///localhost//cat", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/localhost//cat", + "search": "", + "hash": "" + }, + { + "input": "file://localhost//a//../..//", + "base": "about:blank", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "/////mouse", + "base": "file:///elephant", + "href": "file:///mouse", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/mouse", + "search": "", + "hash": "" + }, + { + "input": "\\//pig", + "base": "file://lion/", + "href": "file:///pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pig", + "search": "", + "hash": "" + }, + { + "input": "\\/localhost//pig", + "base": "file://lion/", + "href": "file:///pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pig", + "search": "", + "hash": "" + }, + { + "input": "//localhost//pig", + "base": "file://lion/", + "href": "file:///pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/pig", + "search": "", + "hash": "" + }, + { + "input": "/..//localhost//pig", + "base": "file://lion/", + "href": "file://lion/localhost//pig", + "protocol": "file:", + "username": "", + "password": "", + "host": "lion", + "hostname": "lion", + "port": "", + "pathname": "/localhost//pig", + "search": "", + "hash": "" + }, + { + "input": "file://", + "base": "file://ape/", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "# File URLs with non-empty hosts", + { + "input": "/rooibos", + "base": "file://tea/", + "href": "file://tea/rooibos", + "protocol": "file:", + "username": "", + "password": "", + "host": "tea", + "hostname": "tea", + "port": "", + "pathname": "/rooibos", + "search": "", + "hash": "" + }, + { + "input": "/?chai", + "base": "file://tea/", + "href": "file://tea/?chai", + "protocol": "file:", + "username": "", + "password": "", + "host": "tea", + "hostname": "tea", + "port": "", + "pathname": "/", + "search": "?chai", + "hash": "" + }, + "# Windows drive letter handling with the 'file:' base URL", + { + "input": "C|", + "base": "file://host/dir/file", + "href": "file:///C:", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|#", + "base": "file://host/dir/file", + "href": "file:///C:#", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|?", + "base": "file://host/dir/file", + "href": "file:///C:?", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:", + "search": "", + "hash": "" + }, + { + "input": "C|/", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\n/", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C|\\", + "base": "file://host/dir/file", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "C", + "base": "file://host/dir/file", + "href": "file://host/dir/C", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C", + "search": "", + "hash": "" + }, + { + "input": "C|a", + "base": "file://host/dir/file", + "href": "file://host/dir/C|a", + "protocol": "file:", + "username": "", + "password": "", + "host": "host", + "hostname": "host", + "port": "", + "pathname": "/dir/C|a", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk in the file slash state", + { + "input": "/c:/foo/bar", + "base": "file:///c:/baz/qux", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/c|/foo/bar", + "base": "file:///c:/baz/qux", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "file:\\c:\\foo\\bar", + "base": "file:///c:/baz/qux", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "/c:/foo/bar", + "base": "file://host/path", + "href": "file:///c:/foo/bar", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/c:/foo/bar", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk with not empty host", + { + "input": "file://example.net/C:/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://1.2.3.4/C:/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://[1::8]/C:/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# Windows drive letter quirk (no host)", + { + "input": "file:/C|/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + { + "input": "file://C|/", + "base": "about:blank", + "href": "file:///C:/", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/C:/", + "search": "", + "hash": "" + }, + "# file URLs without base URL by Rimas Misevičius", + { + "input": "file:", + "base": "about:blank", + "href": "file:///", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "file:?q=v", + "base": "about:blank", + "href": "file:///?q=v", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "?q=v", + "hash": "" + }, + { + "input": "file:#frag", + "base": "about:blank", + "href": "file:///#frag", + "protocol": "file:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "#frag" + }, + "# IPv6 tests", + { + "input": "http://[1:0::]", + "base": "http://example.net/", + "href": "http://[1::]/", + "origin": "http://[1::]", + "protocol": "http:", + "username": "", + "password": "", + "host": "[1::]", + "hostname": "[1::]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[0:1:2:3:4:5:6:7:8]", + "base": "http://example.net/", + "failure": true + }, + { + "input": "https://[0::0::0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:.0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:0:]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1.00.0.0.0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1.290.0.0.0]", + "base": "about:blank", + "failure": true + }, + { + "input": "https://[0:1.23.23]", + "base": "about:blank", + "failure": true + }, + "# Empty host", + { + "input": "http://?", + "base": "about:blank", + "failure": true + }, + { + "input": "http://#", + "base": "about:blank", + "failure": true + }, + "Port overflow (2^32 + 81)", + { + "input": "http://f:4294967377/c", + "base": "http://example.org/", + "failure": true + }, + "Port overflow (2^64 + 81)", + { + "input": "http://f:18446744073709551697/c", + "base": "http://example.org/", + "failure": true + }, + "Port overflow (2^128 + 81)", + { + "input": "http://f:340282366920938463463374607431768211537/c", + "base": "http://example.org/", + "failure": true + }, + "# Non-special-URL path tests", + { + "input": "sc://ñ", + "base": "about:blank", + "href": "sc://%C3%B1", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "sc://ñ?x", + "base": "about:blank", + "href": "sc://%C3%B1?x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "?x", + "hash": "" + }, + { + "input": "sc://ñ#x", + "base": "about:blank", + "href": "sc://%C3%B1#x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "", + "hash": "#x" + }, + { + "input": "#x", + "base": "sc://ñ", + "href": "sc://%C3%B1#x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "", + "hash": "#x" + }, + { + "input": "?x", + "base": "sc://ñ", + "href": "sc://%C3%B1?x", + "origin": "null", + "protocol": "sc:", + "username": "", + "password": "", + "host": "%C3%B1", + "hostname": "%C3%B1", + "port": "", + "pathname": "", + "search": "?x", + "hash": "" + }, + { + "input": "sc://?", + "base": "about:blank", + "href": "sc://?", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "sc://#", + "base": "about:blank", + "href": "sc://#", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "", + "search": "", + "hash": "" + }, + { + "input": "///", + "base": "sc://x/", + "href": "sc:///", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "////", + "base": "sc://x/", + "href": "sc:////", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//", + "search": "", + "hash": "" + }, + { + "input": "////x/", + "base": "sc://x/", + "href": "sc:////x/", + "protocol": "sc:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "//x/", + "search": "", + "hash": "" + }, + { + "input": "tftp://foobar.com/someconfig;mode=netascii", + "base": "about:blank", + "href": "tftp://foobar.com/someconfig;mode=netascii", + "origin": "null", + "protocol": "tftp:", + "username": "", + "password": "", + "host": "foobar.com", + "hostname": "foobar.com", + "port": "", + "pathname": "/someconfig;mode=netascii", + "search": "", + "hash": "" + }, + { + "input": "telnet://user:pass@foobar.com:23/", + "base": "about:blank", + "href": "telnet://user:pass@foobar.com:23/", + "origin": "null", + "protocol": "telnet:", + "username": "user", + "password": "pass", + "host": "foobar.com:23", + "hostname": "foobar.com", + "port": "23", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "ut2004://10.10.10.10:7777/Index.ut2", + "base": "about:blank", + "href": "ut2004://10.10.10.10:7777/Index.ut2", + "origin": "null", + "protocol": "ut2004:", + "username": "", + "password": "", + "host": "10.10.10.10:7777", + "hostname": "10.10.10.10", + "port": "7777", + "pathname": "/Index.ut2", + "search": "", + "hash": "" + }, + { + "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", + "base": "about:blank", + "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", + "origin": "null", + "protocol": "redis:", + "username": "foo", + "password": "bar", + "host": "somehost:6379", + "hostname": "somehost", + "port": "6379", + "pathname": "/0", + "search": "?baz=bam&qux=baz", + "hash": "" + }, + { + "input": "rsync://foo@host:911/sup", + "base": "about:blank", + "href": "rsync://foo@host:911/sup", + "origin": "null", + "protocol": "rsync:", + "username": "foo", + "password": "", + "host": "host:911", + "hostname": "host", + "port": "911", + "pathname": "/sup", + "search": "", + "hash": "" + }, + { + "input": "git://github.com/foo/bar.git", + "base": "about:blank", + "href": "git://github.com/foo/bar.git", + "origin": "null", + "protocol": "git:", + "username": "", + "password": "", + "host": "github.com", + "hostname": "github.com", + "port": "", + "pathname": "/foo/bar.git", + "search": "", + "hash": "" + }, + { + "input": "irc://myserver.com:6999/channel?passwd", + "base": "about:blank", + "href": "irc://myserver.com:6999/channel?passwd", + "origin": "null", + "protocol": "irc:", + "username": "", + "password": "", + "host": "myserver.com:6999", + "hostname": "myserver.com", + "port": "6999", + "pathname": "/channel", + "search": "?passwd", + "hash": "" + }, + { + "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT", + "base": "about:blank", + "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT", + "origin": "null", + "protocol": "dns:", + "username": "", + "password": "", + "host": "fw.example.org:9999", + "hostname": "fw.example.org", + "port": "9999", + "pathname": "/foo.bar.org", + "search": "?type=TXT", + "hash": "" + }, + { + "input": "ldap://localhost:389/ou=People,o=JNDITutorial", + "base": "about:blank", + "href": "ldap://localhost:389/ou=People,o=JNDITutorial", + "origin": "null", + "protocol": "ldap:", + "username": "", + "password": "", + "host": "localhost:389", + "hostname": "localhost", + "port": "389", + "pathname": "/ou=People,o=JNDITutorial", + "search": "", + "hash": "" + }, + { + "input": "git+https://github.com/foo/bar", + "base": "about:blank", + "href": "git+https://github.com/foo/bar", + "origin": "null", + "protocol": "git+https:", + "username": "", + "password": "", + "host": "github.com", + "hostname": "github.com", + "port": "", + "pathname": "/foo/bar", + "search": "", + "hash": "" + }, + { + "input": "urn:ietf:rfc:2648", + "base": "about:blank", + "href": "urn:ietf:rfc:2648", + "origin": "null", + "protocol": "urn:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "ietf:rfc:2648", + "search": "", + "hash": "" + }, + { + "input": "tag:joe@example.org,2001:foo/bar", + "base": "about:blank", + "href": "tag:joe@example.org,2001:foo/bar", + "origin": "null", + "protocol": "tag:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "joe@example.org,2001:foo/bar", + "search": "", + "hash": "" + }, + "# percent encoded hosts in non-special-URLs", + { + "input": "non-special://%E2%80%A0/", + "base": "about:blank", + "href": "non-special://%E2%80%A0/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "%E2%80%A0", + "hostname": "%E2%80%A0", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://H%4fSt/path", + "base": "about:blank", + "href": "non-special://H%4fSt/path", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "H%4fSt", + "hostname": "H%4fSt", + "port": "", + "pathname": "/path", + "search": "", + "hash": "" + }, + "# IPv6 in non-special-URLs", + { + "input": "non-special://[1:2:0:0:5:0:0:0]/", + "base": "about:blank", + "href": "non-special://[1:2:0:0:5::]/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2:0:0:5::]", + "hostname": "[1:2:0:0:5::]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[1:2:0:0:0:0:0:3]/", + "base": "about:blank", + "href": "non-special://[1:2::3]/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2::3]", + "hostname": "[1:2::3]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[1:2::3]:80/", + "base": "about:blank", + "href": "non-special://[1:2::3]:80/", + "protocol": "non-special:", + "username": "", + "password": "", + "host": "[1:2::3]:80", + "hostname": "[1:2::3]", + "port": "80", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "non-special://[:80/", + "base": "about:blank", + "failure": true + }, + { + "input": "blob:https://example.com:443/", + "base": "about:blank", + "href": "blob:https://example.com:443/", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "https://example.com:443/", + "search": "", + "hash": "" + }, + { + "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", + "base": "about:blank", + "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", + "protocol": "blob:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "d3958f5c-0777-0845-9dcf-2cb28783acaf", + "search": "", + "hash": "" + }, + "Invalid IPv4 radix digits", + { + "input": "http://0177.0.0.0189", + "base": "about:blank", + "href": "http://0177.0.0.0189/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0177.0.0.0189", + "hostname": "0177.0.0.0189", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0x7f.0.0.0x7g", + "base": "about:blank", + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://0X7F.0.0.0X7G", + "base": "about:blank", + "href": "http://0x7f.0.0.0x7g/", + "protocol": "http:", + "username": "", + "password": "", + "host": "0x7f.0.0.0x7g", + "hostname": "0x7f.0.0.0x7g", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Invalid IPv4 portion of IPv6 address", + { + "input": "http://[::127.0.0.0.1]", + "base": "about:blank", + "failure": true + }, + "Uncompressed IPv6 addresses with 0", + { + "input": "http://[0:1:0:1:0:1:0:1]", + "base": "about:blank", + "href": "http://[0:1:0:1:0:1:0:1]/", + "protocol": "http:", + "username": "", + "password": "", + "host": "[0:1:0:1:0:1:0:1]", + "hostname": "[0:1:0:1:0:1:0:1]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + { + "input": "http://[1:0:1:0:1:0:1:0]", + "base": "about:blank", + "href": "http://[1:0:1:0:1:0:1:0]/", + "protocol": "http:", + "username": "", + "password": "", + "host": "[1:0:1:0:1:0:1:0]", + "hostname": "[1:0:1:0:1:0:1:0]", + "port": "", + "pathname": "/", + "search": "", + "hash": "" + }, + "Percent-encoded query and fragment", + { + "input": "http://example.org/test?\u0022", + "base": "about:blank", + "href": "http://example.org/test?%22", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%22", + "hash": "" + }, + { + "input": "http://example.org/test?\u0023", + "base": "about:blank", + "href": "http://example.org/test?#", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "", + "hash": "" + }, + { + "input": "http://example.org/test?\u003C", + "base": "about:blank", + "href": "http://example.org/test?%3C", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%3C", + "hash": "" + }, + { + "input": "http://example.org/test?\u003E", + "base": "about:blank", + "href": "http://example.org/test?%3E", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%3E", + "hash": "" + }, + { + "input": "http://example.org/test?\u2323", + "base": "about:blank", + "href": "http://example.org/test?%E2%8C%A3", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%E2%8C%A3", + "hash": "" + }, + { + "input": "http://example.org/test?%23%23", + "base": "about:blank", + "href": "http://example.org/test?%23%23", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%23%23", + "hash": "" + }, + { + "input": "http://example.org/test?%GH", + "base": "about:blank", + "href": "http://example.org/test?%GH", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?%GH", + "hash": "" + }, + { + "input": "http://example.org/test?a#%EF", + "base": "about:blank", + "href": "http://example.org/test?a#%EF", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#%EF" + }, + { + "input": "http://example.org/test?a#%GH", + "base": "about:blank", + "href": "http://example.org/test?a#%GH", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#%GH" + }, + "URLs that require a non-about:blank base. (Also serve as invalid base tests.)", + { + "input": "a", + "base": "about:blank", + "failure": true + }, + { + "input": "a/", + "base": "about:blank", + "failure": true + }, + { + "input": "a//", + "base": "about:blank", + "failure": true + }, + "Bases that don't fail to parse but fail to be bases", + { + "input": "test-a-colon.html", + "base": "a:", + "failure": true + }, + { + "input": "test-a-colon-b.html", + "base": "a:b", + "failure": true + }, + "Other base URL tests, that must succeed", + { + "input": "test-a-colon-slash.html", + "base": "a:/", + "href": "a:/test-a-colon-slash.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-slash.html", + "base": "a://", + "href": "a:///test-a-colon-slash-slash.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash-slash.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-b.html", + "base": "a:/b", + "href": "a:/test-a-colon-slash-b.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "", + "hostname": "", + "port": "", + "pathname": "/test-a-colon-slash-b.html", + "search": "", + "hash": "" + }, + { + "input": "test-a-colon-slash-slash-b.html", + "base": "a://b", + "href": "a://b/test-a-colon-slash-slash-b.html", + "protocol": "a:", + "username": "", + "password": "", + "host": "b", + "hostname": "b", + "port": "", + "pathname": "/test-a-colon-slash-slash-b.html", + "search": "", + "hash": "" + }, + "Null code point in fragment", + { + "input": "http://example.org/test?a#b\u0000c", + "base": "about:blank", + "href": "http://example.org/test?a#bc", + "protocol": "http:", + "username": "", + "password": "", + "host": "example.org", + "hostname": "example.org", + "port": "", + "pathname": "/test", + "search": "?a", + "hash": "#bc" + } +] diff --git a/test/fixtures/wpt/url/toascii.window.js b/test/fixtures/wpt/url/toascii.window.js new file mode 100644 index 00000000000000..b28c664479a26a --- /dev/null +++ b/test/fixtures/wpt/url/toascii.window.js @@ -0,0 +1,54 @@ +promise_test(() => fetch("resources/toascii.json").then(res => res.json()).then(runTests), "Loading data…"); + +function makeURL(type, input) { + input = "https://" + input + "/x" + if(type === "url") { + return new URL(input) + } else { + const url = document.createElement(type) + url.href = input + return url + } +} + +function runTests(tests) { + for(var i = 0, l = tests.length; i < l; i++) { + let hostTest = tests[i] + if (typeof hostTest === "string") { + continue // skip comments + } + const typeName = { "url": "URL", "a": "", "area": "" } + ;["url", "a", "area"].forEach((type) => { + test(() => { + if(hostTest.output !== null) { + const url = makeURL("url", hostTest.input) + assert_equals(url.host, hostTest.output) + assert_equals(url.hostname, hostTest.output) + assert_equals(url.pathname, "/x") + assert_equals(url.href, "https://" + hostTest.output + "/x") + } else { + if(type === "url") { + assert_throws(new TypeError, () => makeURL("url", hostTest.input)) + } else { + const url = makeURL(type, hostTest.input) + assert_equals(url.host, "") + assert_equals(url.hostname, "") + assert_equals(url.pathname, "") + assert_equals(url.href, "https://" + hostTest.input + "/x") + } + } + }, hostTest.input + " (using " + typeName[type] + ")") + ;["host", "hostname"].forEach((val) => { + test(() => { + const url = makeURL(type, "x") + url[val] = hostTest.input + if(hostTest.output !== null) { + assert_equals(url[val], hostTest.output) + } else { + assert_equals(url[val], "x") + } + }, hostTest.input + " (using " + typeName[type] + "." + val + ")") + }) + }) + } +} diff --git a/test/fixtures/wpt/url/url-constructor.html b/test/fixtures/wpt/url/url-constructor.html new file mode 100644 index 00000000000000..cb4c0db3571d2f --- /dev/null +++ b/test/fixtures/wpt/url/url-constructor.html @@ -0,0 +1,44 @@ + + + + +

+ diff --git a/test/fixtures/wpt/url/url-origin.html b/test/fixtures/wpt/url/url-origin.html new file mode 100644 index 00000000000000..fccb643ed6c806 --- /dev/null +++ b/test/fixtures/wpt/url/url-origin.html @@ -0,0 +1,24 @@ + + + + +
+ diff --git a/test/fixtures/wpt/url/url-searchparams.any.js b/test/fixtures/wpt/url/url-searchparams.any.js new file mode 100644 index 00000000000000..c55ae58d3b1e5b --- /dev/null +++ b/test/fixtures/wpt/url/url-searchparams.any.js @@ -0,0 +1,72 @@ +function bURL(url, base) { + return new URL(url, base || "about:blank") +} + +function runURLSearchParamTests() { + test(function() { + var url = bURL('http://example.org/?a=b') + assert_true("searchParams" in url) + var searchParams = url.searchParams + assert_true(url.searchParams === searchParams, 'Object identity should hold.') + }, 'URL.searchParams getter') + + test(function() { + var url = bURL('http://example.org/?a=b') + assert_true("searchParams" in url) + var searchParams = url.searchParams + assert_equals(searchParams.toString(), 'a=b') + + searchParams.set('a', 'b') + assert_equals(url.searchParams.toString(), 'a=b') + assert_equals(url.search, '?a=b') + url.search = '' + assert_equals(url.searchParams.toString(), '') + assert_equals(url.search, '') + assert_equals(searchParams.toString(), '') + }, 'URL.searchParams updating, clearing') + + test(function() { + 'use strict' + var urlString = 'http://example.org' + var url = bURL(urlString) + assert_throws(TypeError(), function() { url.searchParams = new URLSearchParams(urlString) }) + }, 'URL.searchParams setter, invalid values') + + test(function() { + var url = bURL('http://example.org/file?a=b&c=d') + assert_true("searchParams" in url) + var searchParams = url.searchParams + assert_equals(url.search, '?a=b&c=d') + assert_equals(searchParams.toString(), 'a=b&c=d') + + // Test that setting 'search' propagates to the URL object's query object. + url.search = 'e=f&g=h' + assert_equals(url.search, '?e=f&g=h') + assert_equals(searchParams.toString(), 'e=f&g=h') + + // ..and same but with a leading '?'. + url.search = '?e=f&g=h' + assert_equals(url.search, '?e=f&g=h') + assert_equals(searchParams.toString(), 'e=f&g=h') + + // And in the other direction, altering searchParams propagates + // back to 'search'. + searchParams.append('i', ' j ') + assert_equals(url.search, '?e=f&g=h&i=+j+') + assert_equals(url.searchParams.toString(), 'e=f&g=h&i=+j+') + assert_equals(searchParams.get('i'), ' j ') + + searchParams.set('e', 'updated') + assert_equals(url.search, '?e=updated&g=h&i=+j+') + assert_equals(searchParams.get('e'), 'updated') + + var url2 = bURL('http://example.org/file??a=b&c=d') + assert_equals(url2.search, '??a=b&c=d') + assert_equals(url2.searchParams.toString(), '%3Fa=b&c=d') + + url2.href = 'http://example.org/file??a=b' + assert_equals(url2.search, '??a=b') + assert_equals(url2.searchParams.toString(), '%3Fa=b') + }, 'URL.searchParams and URL.search setters, update propagation') +} +runURLSearchParamTests() diff --git a/test/fixtures/wpt/url/url-setters.html b/test/fixtures/wpt/url/url-setters.html new file mode 100644 index 00000000000000..db30cf0774da44 --- /dev/null +++ b/test/fixtures/wpt/url/url-setters.html @@ -0,0 +1,48 @@ + + + + +
+ diff --git a/test/fixtures/wpt/url/url-tojson.any.js b/test/fixtures/wpt/url/url-tojson.any.js new file mode 100644 index 00000000000000..65165f96c572d9 --- /dev/null +++ b/test/fixtures/wpt/url/url-tojson.any.js @@ -0,0 +1,4 @@ +test(() => { + const a = new URL("https://example.com/") + assert_equals(JSON.stringify(a), "\"https://example.com/\"") +}) diff --git a/test/fixtures/wpt/url/urlencoded-parser.any.js b/test/fixtures/wpt/url/urlencoded-parser.any.js new file mode 100644 index 00000000000000..65e894b94c26b0 --- /dev/null +++ b/test/fixtures/wpt/url/urlencoded-parser.any.js @@ -0,0 +1,63 @@ +[ + { "input": "test", "output": [["test", ""]] }, + { "input": "\uFEFFtest=\uFEFF", "output": [["\uFEFFtest", "\uFEFF"]] }, + { "input": "%EF%BB%BFtest=%EF%BB%BF", "output": [["\uFEFFtest", "\uFEFF"]] }, + { "input": "%FE%FF", "output": [["\uFFFD\uFFFD", ""]] }, + { "input": "%FF%FE", "output": [["\uFFFD\uFFFD", ""]] }, + { "input": "†&†=x", "output": [["†", ""], ["†", "x"]] }, + { "input": "%C2", "output": [["\uFFFD", ""]] }, + { "input": "%C2x", "output": [["\uFFFDx", ""]] }, + { "input": "_charset_=windows-1252&test=%C2x", "output": [["_charset_", "windows-1252"], ["test", "\uFFFDx"]] }, + { "input": '', "output": [] }, + { "input": 'a', "output": [['a', '']] }, + { "input": 'a=b', "output": [['a', 'b']] }, + { "input": 'a=', "output": [['a', '']] }, + { "input": '=b', "output": [['', 'b']] }, + { "input": '&', "output": [] }, + { "input": '&a', "output": [['a', '']] }, + { "input": 'a&', "output": [['a', '']] }, + { "input": 'a&a', "output": [['a', ''], ['a', '']] }, + { "input": 'a&b&c', "output": [['a', ''], ['b', ''], ['c', '']] }, + { "input": 'a=b&c=d', "output": [['a', 'b'], ['c', 'd']] }, + { "input": 'a=b&c=d&', "output": [['a', 'b'], ['c', 'd']] }, + { "input": '&&&a=b&&&&c=d&', "output": [['a', 'b'], ['c', 'd']] }, + { "input": 'a=a&a=b&a=c', "output": [['a', 'a'], ['a', 'b'], ['a', 'c']] }, + { "input": 'a==a', "output": [['a', '=a']] }, + { "input": 'a=a+b+c+d', "output": [['a', 'a b c d']] }, + { "input": '%=a', "output": [['%', 'a']] }, + { "input": '%a=a', "output": [['%a', 'a']] }, + { "input": '%a_=a', "output": [['%a_', 'a']] }, + { "input": '%61=a', "output": [['a', 'a']] }, + { "input": '%61+%4d%4D=', "output": [['a MM', '']] } +].forEach((val) => { + test(() => { + let sp = new URLSearchParams(val.input), + i = 0 + for (let item of sp) { + assert_array_equals(item, val.output[i]) + i++ + } + }, "URLSearchParams constructed with: " + val.input) + + promise_test(() => { + let init = new Request("about:blank", { body: val.input, method: "LADIDA", headers: {"Content-Type": "application/x-www-form-urlencoded;charset=windows-1252"} }).formData() + return init.then((fd) => { + let i = 0 + for (let item of fd) { + assert_array_equals(item, val.output[i]) + i++ + } + }) + }, "request.formData() with input: " + val.input) + + promise_test(() => { + let init = new Response(val.input, { headers: {"Content-Type": "application/x-www-form-urlencoded;charset=shift_jis"} }).formData() + return init.then((fd) => { + let i = 0 + for (let item of fd) { + assert_array_equals(item, val.output[i]) + i++ + } + }) + }, "response.formData() with input: " + val.input) +}); diff --git a/test/fixtures/wpt/url/urlsearchparams-append.any.js b/test/fixtures/wpt/url/urlsearchparams-append.any.js new file mode 100644 index 00000000000000..5a7376144d0637 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-append.any.js @@ -0,0 +1,39 @@ +test(function() { + var params = new URLSearchParams(); + params.append('a', 'b'); + assert_equals(params + '', 'a=b'); + params.append('a', 'b'); + assert_equals(params + '', 'a=b&a=b'); + params.append('a', 'c'); + assert_equals(params + '', 'a=b&a=b&a=c'); +}, 'Append same name'); + +test(function() { + var params = new URLSearchParams(); + params.append('', ''); + assert_equals(params + '', '='); + params.append('', ''); + assert_equals(params + '', '=&='); +}, 'Append empty strings'); + +test(function() { + var params = new URLSearchParams(); + params.append(null, null); + assert_equals(params + '', 'null=null'); + params.append(null, null); + assert_equals(params + '', 'null=null&null=null'); +}, 'Append null'); + +test(function() { + var params = new URLSearchParams(); + params.append('first', 1); + params.append('second', 2); + params.append('third', ''); + params.append('first', 10); + assert_true(params.has('first'), 'Search params object has name "first"'); + assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); + assert_equals(params.get('second'), '2', 'Search params object has name "second" with value "2"'); + assert_equals(params.get('third'), '', 'Search params object has name "third" with value ""'); + params.append('first', 10); + assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); +}, 'Append multiple'); diff --git a/test/fixtures/wpt/url/urlsearchparams-constructor.any.js b/test/fixtures/wpt/url/urlsearchparams-constructor.any.js new file mode 100644 index 00000000000000..6fff03f00fdddd --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-constructor.any.js @@ -0,0 +1,178 @@ +test(function() { + var params = new URLSearchParams(); + assert_equals(params + '', ''); + params = new URLSearchParams(''); + assert_equals(params + '', ''); + params = new URLSearchParams('a=b'); + assert_equals(params + '', 'a=b'); + params = new URLSearchParams(params); + assert_equals(params + '', 'a=b'); +}, 'Basic URLSearchParams construction'); + +test(function() { + var params = new URLSearchParams() + assert_equals(params.toString(), "") +}, "URLSearchParams constructor, no arguments") + +test(() => { + var params = new URLSearchParams(DOMException); + assert_equals(params.toString(), "INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25") + assert_throws(new TypeError(), () => new URLSearchParams(DOMException.prototype), + "Constructing a URLSearchParams from DOMException.prototype should throw due to branding checks"); +}, "URLSearchParams constructor, DOMException as argument") + +test(() => { + var params = new URLSearchParams(''); + assert_true(params != null, 'constructor returned non-null value.'); + assert_equals(params.__proto__, URLSearchParams.prototype, 'expected URLSearchParams.prototype as prototype.'); +}, "URLSearchParams constructor, empty string as argument") + +test(() => { + var params = new URLSearchParams({}); + assert_equals(params + '', ""); +}, 'URLSearchParams constructor, {} as argument'); + +test(function() { + var params = new URLSearchParams('a=b'); + assert_true(params != null, 'constructor returned non-null value.'); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_false(params.has('b'), 'Search params object has not got name "b"'); + + params = new URLSearchParams('a=b&c'); + assert_true(params != null, 'constructor returned non-null value.'); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_true(params.has('c'), 'Search params object has name "c"'); + + params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); + assert_true(params != null, 'constructor returned non-null value.'); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_true(params.has('a b'), 'Search params object has name "a b"'); + assert_true(params.has(' '), 'Search params object has name " "'); + assert_false(params.has('c'), 'Search params object did not have the name "c"'); + assert_true(params.has(' c'), 'Search params object has name " c"'); + assert_true(params.has('møø'), 'Search params object has name "møø"'); +}, 'URLSearchParams constructor, string.'); + +test(function() { + var seed = new URLSearchParams('a=b&c=d'); + var params = new URLSearchParams(seed); + assert_true(params != null, 'constructor returned non-null value.'); + assert_equals(params.get('a'), 'b'); + assert_equals(params.get('c'), 'd'); + assert_false(params.has('d')); + // The name-value pairs are copied when created; later updates + // should not be observable. + seed.append('e', 'f'); + assert_false(params.has('e')); + params.append('g', 'h'); + assert_false(seed.has('g')); +}, 'URLSearchParams constructor, object.'); + +test(function() { + var params = new URLSearchParams('a=b+c'); + assert_equals(params.get('a'), 'b c'); + params = new URLSearchParams('a+b=c'); + assert_equals(params.get('a b'), 'c'); +}, 'Parse +'); + +test(function() { + const testValue = '+15555555555'; + const params = new URLSearchParams(); + params.set('query', testValue); + var newParams = new URLSearchParams(params.toString()); + + assert_equals(params.toString(), 'query=%2B15555555555'); + assert_equals(params.get('query'), testValue); + assert_equals(newParams.get('query'), testValue); +}, 'Parse encoded +'); + +test(function() { + var params = new URLSearchParams('a=b c'); + assert_equals(params.get('a'), 'b c'); + params = new URLSearchParams('a b=c'); + assert_equals(params.get('a b'), 'c'); +}, 'Parse space'); + +test(function() { + var params = new URLSearchParams('a=b%20c'); + assert_equals(params.get('a'), 'b c'); + params = new URLSearchParams('a%20b=c'); + assert_equals(params.get('a b'), 'c'); +}, 'Parse %20'); + +test(function() { + var params = new URLSearchParams('a=b\0c'); + assert_equals(params.get('a'), 'b\0c'); + params = new URLSearchParams('a\0b=c'); + assert_equals(params.get('a\0b'), 'c'); +}, 'Parse \\0'); + +test(function() { + var params = new URLSearchParams('a=b%00c'); + assert_equals(params.get('a'), 'b\0c'); + params = new URLSearchParams('a%00b=c'); + assert_equals(params.get('a\0b'), 'c'); +}, 'Parse %00'); + +test(function() { + var params = new URLSearchParams('a=b\u2384'); + assert_equals(params.get('a'), 'b\u2384'); + params = new URLSearchParams('a\u2384b=c'); + assert_equals(params.get('a\u2384b'), 'c'); +}, 'Parse \u2384'); // Unicode Character 'COMPOSITION SYMBOL' (U+2384) + +test(function() { + var params = new URLSearchParams('a=b%e2%8e%84'); + assert_equals(params.get('a'), 'b\u2384'); + params = new URLSearchParams('a%e2%8e%84b=c'); + assert_equals(params.get('a\u2384b'), 'c'); +}, 'Parse %e2%8e%84'); // Unicode Character 'COMPOSITION SYMBOL' (U+2384) + +test(function() { + var params = new URLSearchParams('a=b\uD83D\uDCA9c'); + assert_equals(params.get('a'), 'b\uD83D\uDCA9c'); + params = new URLSearchParams('a\uD83D\uDCA9b=c'); + assert_equals(params.get('a\uD83D\uDCA9b'), 'c'); +}, 'Parse \uD83D\uDCA9'); // Unicode Character 'PILE OF POO' (U+1F4A9) + +test(function() { + var params = new URLSearchParams('a=b%f0%9f%92%a9c'); + assert_equals(params.get('a'), 'b\uD83D\uDCA9c'); + params = new URLSearchParams('a%f0%9f%92%a9b=c'); + assert_equals(params.get('a\uD83D\uDCA9b'), 'c'); +}, 'Parse %f0%9f%92%a9'); // Unicode Character 'PILE OF POO' (U+1F4A9) + +test(function() { + var params = new URLSearchParams([]); + assert_true(params != null, 'constructor returned non-null value.'); + params = new URLSearchParams([['a', 'b'], ['c', 'd']]); + assert_equals(params.get("a"), "b"); + assert_equals(params.get("c"), "d"); + assert_throws(new TypeError(), function() { new URLSearchParams([[1]]); }); + assert_throws(new TypeError(), function() { new URLSearchParams([[1,2,3]]); }); +}, "Constructor with sequence of sequences of strings"); + +[ + { "input": {"+": "%C2"}, "output": [["+", "%C2"]], "name": "object with +" }, + { "input": {c: "x", a: "?"}, "output": [["c", "x"], ["a", "?"]], "name": "object with two keys" }, + { "input": [["c", "x"], ["a", "?"]], "output": [["c", "x"], ["a", "?"]], "name": "array with two keys" }, + { "input": {"a\0b": "42", "c\uD83D": "23", "d\u1234": "foo"}, "output": [["a\0b", "42"], ["c\uFFFD", "23"], ["d\u1234", "foo"]], "name": "object with NULL, non-ASCII, and surrogate keys" } +].forEach((val) => { + test(() => { + let params = new URLSearchParams(val.input), + i = 0 + for (let param of params) { + assert_array_equals(param, val.output[i]) + i++ + } + }, "Construct with " + val.name) +}) + +test(() => { + var params = new URLSearchParams() + params[Symbol.iterator] = function *() { + yield ["a", "b"] + } + let params2 = new URLSearchParams(params) + assert_equals(params2.get("a"), "b") +}, "Custom [Symbol.iterator]") diff --git a/test/fixtures/wpt/url/urlsearchparams-delete.any.js b/test/fixtures/wpt/url/urlsearchparams-delete.any.js new file mode 100644 index 00000000000000..1aa9b313736de2 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-delete.any.js @@ -0,0 +1,45 @@ +test(function() { + var params = new URLSearchParams('a=b&c=d'); + params.delete('a'); + assert_equals(params + '', 'c=d'); + params = new URLSearchParams('a=a&b=b&a=a&c=c'); + params.delete('a'); + assert_equals(params + '', 'b=b&c=c'); + params = new URLSearchParams('a=a&=&b=b&c=c'); + params.delete(''); + assert_equals(params + '', 'a=a&b=b&c=c'); + params = new URLSearchParams('a=a&null=null&b=b'); + params.delete(null); + assert_equals(params + '', 'a=a&b=b'); + params = new URLSearchParams('a=a&undefined=undefined&b=b'); + params.delete(undefined); + assert_equals(params + '', 'a=a&b=b'); +}, 'Delete basics'); + +test(function() { + var params = new URLSearchParams(); + params.append('first', 1); + assert_true(params.has('first'), 'Search params object has name "first"'); + assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); + params.delete('first'); + assert_false(params.has('first'), 'Search params object has no "first" name'); + params.append('first', 1); + params.append('first', 10); + params.delete('first'); + assert_false(params.has('first'), 'Search params object has no "first" name'); +}, 'Deleting appended multiple'); + +test(function() { + var url = new URL('http://example.com/?param1¶m2'); + url.searchParams.delete('param1'); + url.searchParams.delete('param2'); + assert_equals(url.href, 'http://example.com/', 'url.href does not have ?'); + assert_equals(url.search, '', 'url.search does not have ?'); +}, 'Deleting all params removes ? from URL'); + +test(function() { + var url = new URL('http://example.com/?'); + url.searchParams.delete('param1'); + assert_equals(url.href, 'http://example.com/', 'url.href does not have ?'); + assert_equals(url.search, '', 'url.search does not have ?'); +}, 'Removing non-existent param removes ? from URL'); diff --git a/test/fixtures/wpt/url/urlsearchparams-foreach.any.js b/test/fixtures/wpt/url/urlsearchparams-foreach.any.js new file mode 100644 index 00000000000000..7969a0cb11a271 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-foreach.any.js @@ -0,0 +1,76 @@ +test(function() { + var params = new URLSearchParams('a=1&b=2&c=3'); + var keys = []; + var values = []; + params.forEach(function(value, key) { + keys.push(key); + values.push(value); + }); + assert_array_equals(keys, ['a', 'b', 'c']); + assert_array_equals(values, ['1', '2', '3']); +}, "ForEach Check"); + +test(function() { + let a = new URL("http://a.b/c?a=1&b=2&c=3&d=4"); + let b = a.searchParams; + var c = []; + for (i of b) { + a.search = "x=1&y=2&z=3"; + c.push(i); + } + assert_array_equals(c[0], ["a","1"]); + assert_array_equals(c[1], ["y","2"]); + assert_array_equals(c[2], ["z","3"]); +}, "For-of Check"); + +test(function() { + let a = new URL("http://a.b/c"); + let b = a.searchParams; + for (i of b) { + assert_unreached(i); + } +}, "empty"); + +test(function() { + const url = new URL("http://localhost/query?param0=0¶m1=1¶m2=2"); + const searchParams = url.searchParams; + const seen = []; + for (param of searchParams) { + if (param[0] === 'param0') { + searchParams.delete('param1'); + } + seen.push(param); + } + + assert_array_equals(seen[0], ["param0", "0"]); + assert_array_equals(seen[1], ["param2", "2"]); +}, "delete next param during iteration"); + +test(function() { + const url = new URL("http://localhost/query?param0=0¶m1=1¶m2=2"); + const searchParams = url.searchParams; + const seen = []; + for (param of searchParams) { + if (param[0] === 'param0') { + searchParams.delete('param0'); + // 'param1=1' is now in the first slot, so the next iteration will see 'param2=2'. + } else { + seen.push(param); + } + } + + assert_array_equals(seen[0], ["param2", "2"]); +}, "delete current param during iteration"); + +test(function() { + const url = new URL("http://localhost/query?param0=0¶m1=1¶m2=2"); + const searchParams = url.searchParams; + const seen = []; + for (param of searchParams) { + seen.push(param[0]); + searchParams.delete(param[0]); + } + + assert_array_equals(seen, ["param0", "param2"], "param1 should not have been seen by the loop"); + assert_equals(String(searchParams), "param1=1", "param1 should remain"); +}, "delete every param seen during iteration"); diff --git a/test/fixtures/wpt/url/urlsearchparams-get.any.js b/test/fixtures/wpt/url/urlsearchparams-get.any.js new file mode 100644 index 00000000000000..a2610fc933a772 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-get.any.js @@ -0,0 +1,21 @@ +test(function() { + var params = new URLSearchParams('a=b&c=d'); + assert_equals(params.get('a'), 'b'); + assert_equals(params.get('c'), 'd'); + assert_equals(params.get('e'), null); + params = new URLSearchParams('a=b&c=d&a=e'); + assert_equals(params.get('a'), 'b'); + params = new URLSearchParams('=b&c=d'); + assert_equals(params.get(''), 'b'); + params = new URLSearchParams('a=&c=d&a=e'); + assert_equals(params.get('a'), ''); +}, 'Get basics'); + +test(function() { + var params = new URLSearchParams('first=second&third&&'); + assert_true(params != null, 'constructor returned non-null value.'); + assert_true(params.has('first'), 'Search params object has name "first"'); + assert_equals(params.get('first'), 'second', 'Search params object has name "first" with value "second"'); + assert_equals(params.get('third'), '', 'Search params object has name "third" with the empty value.'); + assert_equals(params.get('fourth'), null, 'Search params object has no "fourth" name and value.'); +}, 'More get() basics'); diff --git a/test/fixtures/wpt/url/urlsearchparams-getall.any.js b/test/fixtures/wpt/url/urlsearchparams-getall.any.js new file mode 100644 index 00000000000000..5d1a35352acf2c --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-getall.any.js @@ -0,0 +1,25 @@ +test(function() { + var params = new URLSearchParams('a=b&c=d'); + assert_array_equals(params.getAll('a'), ['b']); + assert_array_equals(params.getAll('c'), ['d']); + assert_array_equals(params.getAll('e'), []); + params = new URLSearchParams('a=b&c=d&a=e'); + assert_array_equals(params.getAll('a'), ['b', 'e']); + params = new URLSearchParams('=b&c=d'); + assert_array_equals(params.getAll(''), ['b']); + params = new URLSearchParams('a=&c=d&a=e'); + assert_array_equals(params.getAll('a'), ['', 'e']); +}, 'getAll() basics'); + +test(function() { + var params = new URLSearchParams('a=1&a=2&a=3&a'); + assert_true(params.has('a'), 'Search params object has name "a"'); + var matches = params.getAll('a'); + assert_true(matches && matches.length == 4, 'Search params object has values for name "a"'); + assert_array_equals(matches, ['1', '2', '3', ''], 'Search params object has expected name "a" values'); + params.set('a', 'one'); + assert_equals(params.get('a'), 'one', 'Search params object has name "a" with value "one"'); + var matches = params.getAll('a'); + assert_true(matches && matches.length == 1, 'Search params object has values for name "a"'); + assert_array_equals(matches, ['one'], 'Search params object has expected name "a" values'); +}, 'getAll() multiples'); diff --git a/test/fixtures/wpt/url/urlsearchparams-has.any.js b/test/fixtures/wpt/url/urlsearchparams-has.any.js new file mode 100644 index 00000000000000..673dce77dc44ab --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-has.any.js @@ -0,0 +1,24 @@ +test(function() { + var params = new URLSearchParams('a=b&c=d'); + assert_true(params.has('a')); + assert_true(params.has('c')); + assert_false(params.has('e')); + params = new URLSearchParams('a=b&c=d&a=e'); + assert_true(params.has('a')); + params = new URLSearchParams('=b&c=d'); + assert_true(params.has('')); + params = new URLSearchParams('null=a'); + assert_true(params.has(null)); +}, 'Has basics'); + +test(function() { + var params = new URLSearchParams('a=b&c=d&&'); + params.append('first', 1); + params.append('first', 2); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_true(params.has('c'), 'Search params object has name "c"'); + assert_true(params.has('first'), 'Search params object has name "first"'); + assert_false(params.has('d'), 'Search params object has no name "d"'); + params.delete('first'); + assert_false(params.has('first'), 'Search params object has no name "first"'); +}, 'has() following delete()'); diff --git a/test/fixtures/wpt/url/urlsearchparams-set.any.js b/test/fixtures/wpt/url/urlsearchparams-set.any.js new file mode 100644 index 00000000000000..eb24cac87b6dca --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-set.any.js @@ -0,0 +1,22 @@ +test(function() { + var params = new URLSearchParams('a=b&c=d'); + params.set('a', 'B'); + assert_equals(params + '', 'a=B&c=d'); + params = new URLSearchParams('a=b&c=d&a=e'); + params.set('a', 'B'); + assert_equals(params + '', 'a=B&c=d') + params.set('e', 'f'); + assert_equals(params + '', 'a=B&c=d&e=f') +}, 'Set basics'); + +test(function() { + var params = new URLSearchParams('a=1&a=2&a=3'); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_equals(params.get('a'), '1', 'Search params object has name "a" with value "1"'); + params.set('first', 4); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_equals(params.get('a'), '1', 'Search params object has name "a" with value "1"'); + params.set('a', 4); + assert_true(params.has('a'), 'Search params object has name "a"'); + assert_equals(params.get('a'), '4', 'Search params object has name "a" with value "4"'); +}, 'URLSearchParams.set'); diff --git a/test/fixtures/wpt/url/urlsearchparams-sort.any.js b/test/fixtures/wpt/url/urlsearchparams-sort.any.js new file mode 100644 index 00000000000000..4fd8cef69239d2 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-sort.any.js @@ -0,0 +1,62 @@ +[ + { + "input": "z=b&a=b&z=a&a=a", + "output": [["a", "b"], ["a", "a"], ["z", "b"], ["z", "a"]] + }, + { + "input": "\uFFFD=x&\uFFFC&\uFFFD=a", + "output": [["\uFFFC", ""], ["\uFFFD", "x"], ["\uFFFD", "a"]] + }, + { + "input": "ffi&🌈", // 🌈 > code point, but < code unit because two code units + "output": [["🌈", ""], ["ffi", ""]] + }, + { + "input": "é&e\uFFFD&e\u0301", + "output": [["e\u0301", ""], ["e\uFFFD", ""], ["é", ""]] + }, + { + "input": "z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g", + "output": [["a", "a"], ["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"], ["a", "g"], ["z", "z"], ["z", "y"], ["z", "x"], ["z", "w"], ["z", "v"], ["z", "u"], ["z", "t"]] + }, + { + "input": "bbb&bb&aaa&aa=x&aa=y", + "output": [["aa", "x"], ["aa", "y"], ["aaa", ""], ["bb", ""], ["bbb", ""]] + }, + { + "input": "z=z&=f&=t&=x", + "output": [["", "f"], ["", "t"], ["", "x"], ["z", "z"]] + }, + { + "input": "a🌈&a💩", + "output": [["a🌈", ""], ["a💩", ""]] + } +].forEach((val) => { + test(() => { + let params = new URLSearchParams(val.input), + i = 0 + params.sort() + for(let param of params) { + assert_array_equals(param, val.output[i]) + i++ + } + }, "Parse and sort: " + val.input) + + test(() => { + let url = new URL("?" + val.input, "https://example/") + url.searchParams.sort() + let params = new URLSearchParams(url.search), + i = 0 + for(let param of params) { + assert_array_equals(param, val.output[i]) + i++ + } + }, "URL parse and sort: " + val.input) +}) + +test(function() { + const url = new URL("http://example.com/?") + url.searchParams.sort() + assert_equals(url.href, "http://example.com/") + assert_equals(url.search, "") +}, "Sorting non-existent params removes ? from URL") diff --git a/test/fixtures/wpt/url/urlsearchparams-stringifier.any.js b/test/fixtures/wpt/url/urlsearchparams-stringifier.any.js new file mode 100644 index 00000000000000..ef95c1434c7964 --- /dev/null +++ b/test/fixtures/wpt/url/urlsearchparams-stringifier.any.js @@ -0,0 +1,123 @@ +test(function() { + var params = new URLSearchParams(); + params.append('a', 'b c'); + assert_equals(params + '', 'a=b+c'); + params.delete('a'); + params.append('a b', 'c'); + assert_equals(params + '', 'a+b=c'); +}, 'Serialize space'); + +test(function() { + var params = new URLSearchParams(); + params.append('a', ''); + assert_equals(params + '', 'a='); + params.append('a', ''); + assert_equals(params + '', 'a=&a='); + params.append('', 'b'); + assert_equals(params + '', 'a=&a=&=b'); + params.append('', ''); + assert_equals(params + '', 'a=&a=&=b&='); + params.append('', ''); + assert_equals(params + '', 'a=&a=&=b&=&='); +}, 'Serialize empty value'); + +test(function() { + var params = new URLSearchParams(); + params.append('', 'b'); + assert_equals(params + '', '=b'); + params.append('', 'b'); + assert_equals(params + '', '=b&=b'); +}, 'Serialize empty name'); + +test(function() { + var params = new URLSearchParams(); + params.append('', ''); + assert_equals(params + '', '='); + params.append('', ''); + assert_equals(params + '', '=&='); +}, 'Serialize empty name and value'); + +test(function() { + var params = new URLSearchParams(); + params.append('a', 'b+c'); + assert_equals(params + '', 'a=b%2Bc'); + params.delete('a'); + params.append('a+b', 'c'); + assert_equals(params + '', 'a%2Bb=c'); +}, 'Serialize +'); + +test(function() { + var params = new URLSearchParams(); + params.append('=', 'a'); + assert_equals(params + '', '%3D=a'); + params.append('b', '='); + assert_equals(params + '', '%3D=a&b=%3D'); +}, 'Serialize ='); + +test(function() { + var params = new URLSearchParams(); + params.append('&', 'a'); + assert_equals(params + '', '%26=a'); + params.append('b', '&'); + assert_equals(params + '', '%26=a&b=%26'); +}, 'Serialize &'); + +test(function() { + var params = new URLSearchParams(); + params.append('a', '*-._'); + assert_equals(params + '', 'a=*-._'); + params.delete('a'); + params.append('*-._', 'c'); + assert_equals(params + '', '*-._=c'); +}, 'Serialize *-._'); + +test(function() { + var params = new URLSearchParams(); + params.append('a', 'b%c'); + assert_equals(params + '', 'a=b%25c'); + params.delete('a'); + params.append('a%b', 'c'); + assert_equals(params + '', 'a%25b=c'); +}, 'Serialize %'); + +test(function() { + var params = new URLSearchParams(); + params.append('a', 'b\0c'); + assert_equals(params + '', 'a=b%00c'); + params.delete('a'); + params.append('a\0b', 'c'); + assert_equals(params + '', 'a%00b=c'); +}, 'Serialize \\0'); + +test(function() { + var params = new URLSearchParams(); + params.append('a', 'b\uD83D\uDCA9c'); + assert_equals(params + '', 'a=b%F0%9F%92%A9c'); + params.delete('a'); + params.append('a\uD83D\uDCA9b', 'c'); + assert_equals(params + '', 'a%F0%9F%92%A9b=c'); +}, 'Serialize \uD83D\uDCA9'); // Unicode Character 'PILE OF POO' (U+1F4A9) + +test(function() { + var params; + params = new URLSearchParams('a=b&c=d&&e&&'); + assert_equals(params.toString(), 'a=b&c=d&e='); + params = new URLSearchParams('a = b &a=b&c=d%20'); + assert_equals(params.toString(), 'a+=+b+&a=b&c=d+'); + // The lone '=' _does_ survive the roundtrip. + params = new URLSearchParams('a=&a=b'); + assert_equals(params.toString(), 'a=&a=b'); +}, 'URLSearchParams.toString'); + +test(() => { + const url = new URL('http://www.example.com/?a=b,c'); + const params = url.searchParams; + + assert_equals(url.toString(), 'http://www.example.com/?a=b,c'); + assert_equals(params.toString(), 'a=b%2Cc'); + + params.append('x', 'y'); + + assert_equals(url.toString(), 'http://www.example.com/?a=b%2Cc&x=y'); + assert_equals(params.toString(), 'a=b%2Cc&x=y'); +}, 'URLSearchParams connected to URL'); diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json new file mode 100644 index 00000000000000..9ce98bcbb8d7ba --- /dev/null +++ b/test/fixtures/wpt/versions.json @@ -0,0 +1,18 @@ +{ + "resources": { + "commit": "679a364421ce3704289df21e1ff985c14b360981", + "path": "resources" + }, + "interfaces": { + "commit": "db7f86289e47f0d124593cd27926529a6265ddb3", + "path": "interfaces" + }, + "console": { + "commit": "9786a4b1317c03b89ea3bf2e997f2e2b6a3690ae", + "path": "console" + }, + "url": { + "commit": "75b0f336c50105c6fea47ad253d57219dfa744d3", + "path": "url" + } +} \ No newline at end of file From 3f935d74e0acb92666e9f6600551b04d6ce45ac0 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 1 Oct 2018 15:37:08 +0200 Subject: [PATCH 132/249] test: remove WPT tests that are now .any.js in the upstream In favor of actual .any.js tests that will be run with the WPT harness in a subsequent patch. The other types of .js tests (e.g. .window.js tests) and the .html tests remained to be supported or migrated in the upstream. PR-URL: https://github.com/nodejs/node/pull/24035 Refs: https://github.com/nodejs/node/issues/23192 Reviewed-By: Daijiro Wachi --- .../test-whatwg-console-is-a-namespace.js | 47 ----- .../test-whatwg-console-label-conversion.js | 45 ----- .../test-whatwg-console-tests-historical.js | 36 ---- test/parallel/test-whatwg-url-historical.js | 46 ----- .../test-whatwg-url-searchparams-append.js | 49 ----- ...est-whatwg-url-searchparams-constructor.js | 191 ------------------ .../test-whatwg-url-searchparams-delete.js | 59 ------ .../test-whatwg-url-searchparams-foreach.js | 47 ----- .../test-whatwg-url-searchparams-get.js | 34 ---- .../test-whatwg-url-searchparams-getall.js | 39 ---- .../test-whatwg-url-searchparams-has.js | 37 ---- .../test-whatwg-url-searchparams-set.js | 35 ---- .../test-whatwg-url-searchparams-sort.js | 63 ------ ...est-whatwg-url-searchparams-stringifier.js | 123 ----------- test/parallel/test-whatwg-url-tojson.js | 17 -- 15 files changed, 868 deletions(-) delete mode 100644 test/parallel/test-whatwg-console-is-a-namespace.js delete mode 100644 test/parallel/test-whatwg-console-label-conversion.js delete mode 100644 test/parallel/test-whatwg-console-tests-historical.js delete mode 100644 test/parallel/test-whatwg-url-historical.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-append.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-constructor.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-delete.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-foreach.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-get.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-getall.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-has.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-set.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-sort.js delete mode 100644 test/parallel/test-whatwg-url-searchparams-stringifier.js delete mode 100644 test/parallel/test-whatwg-url-tojson.js diff --git a/test/parallel/test-whatwg-console-is-a-namespace.js b/test/parallel/test-whatwg-console-is-a-namespace.js deleted file mode 100644 index fb28e751a322af..00000000000000 --- a/test/parallel/test-whatwg-console-is-a-namespace.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -require('../common'); - -const { test, assert_equals, assert_true, assert_false } = - require('../common/wpt'); - -const self = global; - -/* eslint-disable quotes, max-len */ - -/* The following tests should not be modified as they are copied */ -/* WPT Refs: - https://github.com/w3c/web-platform-tests/blob/40e451c/console/console-is-a-namespace.any.js - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ - -// https://heycam.github.io/webidl/#es-namespaces -// https://console.spec.whatwg.org/#console-namespace - -test(() => { - assert_true(self.hasOwnProperty("console")); -}, "console exists on the global object"); - -test(() => { - const propDesc = Object.getOwnPropertyDescriptor(self, "console"); - assert_equals(propDesc.writable, true, "must be writable"); - assert_equals(propDesc.enumerable, false, "must not be enumerable"); - assert_equals(propDesc.configurable, true, "must be configurable"); - assert_equals(propDesc.value, console, "must have the right value"); -}, "console has the right property descriptors"); - -test(() => { - assert_false("Console" in self); -}, "Console (uppercase, as if it were an interface) must not exist"); - -test(() => { - const prototype1 = Object.getPrototypeOf(console); - const prototype2 = Object.getPrototypeOf(prototype1); - - // This got commented out from the original test because in Node.js all - // functions are declared on the prototype. - // assert_equals(Object.getOwnPropertyNames(prototype1).length, 0, "The [[Prototype]] must have no properties"); - assert_equals(prototype2, Object.prototype, "The [[Prototype]]'s [[Prototype]] must be %ObjectPrototype%"); -}, "The prototype chain must be correct"); - -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-console-label-conversion.js b/test/parallel/test-whatwg-console-label-conversion.js deleted file mode 100644 index 9131a0c175d11c..00000000000000 --- a/test/parallel/test-whatwg-console-label-conversion.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -require('../common'); - -const { test, assert_true, assert_throws } = - require('../common/wpt'); - -/* eslint-disable max-len, object-curly-spacing */ - -/* The following tests should not be modified as they are copied */ -/* WPT Refs: - https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/console/console-label-conversion.any.js - License: https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/LICENSE.md -*/ - -// https://console.spec.whatwg/org/#counting -// https://console.spec.whatwg/org/#timing - -const methods = ['count', 'countReset', 'time', 'timeLog', 'timeEnd']; - -for (const method of methods) { - test(() => { - let labelToStringCalled = false; - - console[method]({ - toString() { - labelToStringCalled = true; - } - }); - - assert_true(labelToStringCalled, `${method}() must call toString() on label when label is an object`); - }, `console.${method}()'s label gets converted to string via label.toString() when label is an object`); - - test(() => { - assert_throws({name: 'Error'}, () => { - console[method]({ - toString() { - throw new Error('conversion error'); - } - }); - }, `${method} must re-throw any exceptions thrown by label.toString() conversion`); - }, `console.${method}() throws exceptions generated by erroneous label.toString() conversion`); -} - -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-console-tests-historical.js b/test/parallel/test-whatwg-console-tests-historical.js deleted file mode 100644 index d4a998b07061b9..00000000000000 --- a/test/parallel/test-whatwg-console-tests-historical.js +++ /dev/null @@ -1,36 +0,0 @@ -'use strict'; - -require('../common'); - -const { test, assert_equals } = - require('../common/wpt'); - -/* eslint-disable max-len, quotes */ - -/* The following tests should not be modified as they are copied */ -/* WPT Refs: - https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/console/console-tests-historical.any.js - License: https://github.com/web-platform-tests/wpt/blob/6f0a96ed650935b17b6e5d277889cfbe0ccc103e/LICENSE.md -*/ - -/** - * These tests assert the non-existence of certain - * legacy Console methods that are not included in - * the specification: http://console.spec.whatwg.org/ - */ - -"use strict"; - -test(() => { - assert_equals(console.timeline, undefined, "console.timeline should be undefined"); -}, "'timeline' function should not exist on the console object"); - -test(() => { - assert_equals(console.timelineEnd, undefined, "console.timelineEnd should be undefined"); -}, "'timelineEnd' function should not exist on the console object"); - -test(() => { - assert_equals(console.markTimeline, undefined, "console.markTimeline should be undefined"); -}, "'markTimeline' function should not exist on the console object"); - -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-historical.js b/test/parallel/test-whatwg-url-historical.js deleted file mode 100644 index 466949cd322d37..00000000000000 --- a/test/parallel/test-whatwg-url-historical.js +++ /dev/null @@ -1,46 +0,0 @@ -'use strict'; -const common = require('../common'); -if (!common.hasIntl) { - // A handful of the tests fail when ICU is not included. - common.skip('missing Intl'); -} - -const URL = require('url').URL; -const { test, assert_equals, assert_throws } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/historical.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -// var objects = [ -// [function() { return window.location }, "location object"], -// [function() { return document.createElement("a") }, "a element"], -// [function() { return document.createElement("area") }, "area element"], -// ]; - -// objects.forEach(function(o) { -// test(function() { -// var object = o[0](); -// assert_false("searchParams" in object, -// o[1] + " should not have a searchParams attribute"); -// }, "searchParams on " + o[1]); -// }); - -test(function() { - var url = new URL("./foo", "http://www.example.org"); - assert_equals(url.href, "http://www.example.org/foo"); - assert_throws(new TypeError(), function() { - url.href = "./bar"; - }); -}, "Setting URL's href attribute and base URLs"); - -test(function() { - assert_equals(URL.domainToASCII, undefined); -}, "URL.domainToASCII should be undefined"); - -test(function() { - assert_equals(URL.domainToUnicode, undefined); -}, "URL.domainToUnicode should be undefined"); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-append.js b/test/parallel/test-whatwg-url-searchparams-append.js deleted file mode 100644 index 342cbd53357986..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-append.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-append.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams(); - params.append('a', 'b'); - assert_equals(params + '', 'a=b'); - params.append('a', 'b'); - assert_equals(params + '', 'a=b&a=b'); - params.append('a', 'c'); - assert_equals(params + '', 'a=b&a=b&a=c'); -}, 'Append same name'); -test(function() { - var params = new URLSearchParams(); - params.append('', ''); - assert_equals(params + '', '='); - params.append('', ''); - assert_equals(params + '', '=&='); -}, 'Append empty strings'); -test(function() { - var params = new URLSearchParams(); - params.append(null, null); - assert_equals(params + '', 'null=null'); - params.append(null, null); - assert_equals(params + '', 'null=null&null=null'); -}, 'Append null'); -test(function() { - var params = new URLSearchParams(); - params.append('first', 1); - params.append('second', 2); - params.append('third', ''); - params.append('first', 10); - assert_true(params.has('first'), 'Search params object has name "first"'); - assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); - assert_equals(params.get('second'), '2', 'Search params object has name "second" with value "2"'); - assert_equals(params.get('third'), '', 'Search params object has name "third" with value ""'); - params.append('first', 10); - assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); -}, 'Append multiple'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-constructor.js b/test/parallel/test-whatwg-url-searchparams-constructor.js deleted file mode 100644 index 882072ba445fcb..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-constructor.js +++ /dev/null @@ -1,191 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { - test, assert_equals, assert_true, - assert_false, assert_throws, assert_array_equals -} = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/54c3502d7b/url/urlsearchparams-constructor.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -var params; // Strict mode fix for WPT. -test(function() { - var params = new URLSearchParams(); - assert_equals(params + '', ''); - params = new URLSearchParams(''); - assert_equals(params + '', ''); - params = new URLSearchParams('a=b'); - assert_equals(params + '', 'a=b'); - params = new URLSearchParams(params); - assert_equals(params + '', 'a=b'); -}, 'Basic URLSearchParams construction'); - -test(function() { - var params = new URLSearchParams() - assert_equals(params.toString(), "") -}, "URLSearchParams constructor, no arguments") - -// test(() => { -// params = new URLSearchParams(DOMException.prototype); -// assert_equals(params.toString(), "INDEX_SIZE_ERR=1&DOMSTRING_SIZE_ERR=2&HIERARCHY_REQUEST_ERR=3&WRONG_DOCUMENT_ERR=4&INVALID_CHARACTER_ERR=5&NO_DATA_ALLOWED_ERR=6&NO_MODIFICATION_ALLOWED_ERR=7&NOT_FOUND_ERR=8&NOT_SUPPORTED_ERR=9&INUSE_ATTRIBUTE_ERR=10&INVALID_STATE_ERR=11&SYNTAX_ERR=12&INVALID_MODIFICATION_ERR=13&NAMESPACE_ERR=14&INVALID_ACCESS_ERR=15&VALIDATION_ERR=16&TYPE_MISMATCH_ERR=17&SECURITY_ERR=18&NETWORK_ERR=19&ABORT_ERR=20&URL_MISMATCH_ERR=21"A_EXCEEDED_ERR=22&TIMEOUT_ERR=23&INVALID_NODE_TYPE_ERR=24&DATA_CLONE_ERR=25") -// }, "URLSearchParams constructor, DOMException.prototype as argument") - -test(() => { - params = new URLSearchParams(''); - assert_true(params != null, 'constructor returned non-null value.'); - assert_equals(params.__proto__, URLSearchParams.prototype, 'expected URLSearchParams.prototype as prototype.'); -}, "URLSearchParams constructor, empty string as argument") - -test(() => { - params = new URLSearchParams({}); - assert_equals(params + '', ""); -}, 'URLSearchParams constructor, {} as argument'); - -test(function() { - var params = new URLSearchParams('a=b'); - assert_true(params != null, 'constructor returned non-null value.'); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_false(params.has('b'), 'Search params object has not got name "b"'); - var params = new URLSearchParams('a=b&c'); - assert_true(params != null, 'constructor returned non-null value.'); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_true(params.has('c'), 'Search params object has name "c"'); - var params = new URLSearchParams('&a&&& &&&&&a+b=& c&m%c3%b8%c3%b8'); - assert_true(params != null, 'constructor returned non-null value.'); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_true(params.has('a b'), 'Search params object has name "a b"'); - assert_true(params.has(' '), 'Search params object has name " "'); - assert_false(params.has('c'), 'Search params object did not have the name "c"'); - assert_true(params.has(' c'), 'Search params object has name " c"'); - assert_true(params.has('møø'), 'Search params object has name "møø"'); -}, 'URLSearchParams constructor, string.'); - -test(function() { - var seed = new URLSearchParams('a=b&c=d'); - var params = new URLSearchParams(seed); - assert_true(params != null, 'constructor returned non-null value.'); - assert_equals(params.get('a'), 'b'); - assert_equals(params.get('c'), 'd'); - assert_false(params.has('d')); - // The name-value pairs are copied when created; later updates - // should not be observable. - seed.append('e', 'f'); - assert_false(params.has('e')); - params.append('g', 'h'); - assert_false(seed.has('g')); -}, 'URLSearchParams constructor, object.'); - -test(function() { - var params = new URLSearchParams('a=b+c'); - assert_equals(params.get('a'), 'b c'); - params = new URLSearchParams('a+b=c'); - assert_equals(params.get('a b'), 'c'); -}, 'Parse +'); - -test(function() { - const testValue = '+15555555555'; - const params = new URLSearchParams(); - params.set('query', testValue); - var newParams = new URLSearchParams(params.toString()); - - assert_equals(params.toString(), 'query=%2B15555555555'); - assert_equals(params.get('query'), testValue); - assert_equals(newParams.get('query'), testValue); -}, 'Parse encoded +'); - -test(function() { - var params = new URLSearchParams('a=b c'); - assert_equals(params.get('a'), 'b c'); - params = new URLSearchParams('a b=c'); - assert_equals(params.get('a b'), 'c'); -}, 'Parse space'); - -test(function() { - var params = new URLSearchParams('a=b%20c'); - assert_equals(params.get('a'), 'b c'); - params = new URLSearchParams('a%20b=c'); - assert_equals(params.get('a b'), 'c'); -}, 'Parse %20'); - -test(function() { - var params = new URLSearchParams('a=b\0c'); - assert_equals(params.get('a'), 'b\0c'); - params = new URLSearchParams('a\0b=c'); - assert_equals(params.get('a\0b'), 'c'); -}, 'Parse \\0'); - -test(function() { - var params = new URLSearchParams('a=b%00c'); - assert_equals(params.get('a'), 'b\0c'); - params = new URLSearchParams('a%00b=c'); - assert_equals(params.get('a\0b'), 'c'); -}, 'Parse %00'); - -test(function() { - var params = new URLSearchParams('a=b\u2384'); - assert_equals(params.get('a'), 'b\u2384'); - params = new URLSearchParams('a\u2384b=c'); - assert_equals(params.get('a\u2384b'), 'c'); -}, 'Parse \u2384'); // Unicode Character 'COMPOSITION SYMBOL' (U+2384) - -test(function() { - var params = new URLSearchParams('a=b%e2%8e%84'); - assert_equals(params.get('a'), 'b\u2384'); - params = new URLSearchParams('a%e2%8e%84b=c'); - assert_equals(params.get('a\u2384b'), 'c'); -}, 'Parse %e2%8e%84'); // Unicode Character 'COMPOSITION SYMBOL' (U+2384) - -test(function() { - var params = new URLSearchParams('a=b\uD83D\uDCA9c'); - assert_equals(params.get('a'), 'b\uD83D\uDCA9c'); - params = new URLSearchParams('a\uD83D\uDCA9b=c'); - assert_equals(params.get('a\uD83D\uDCA9b'), 'c'); -}, 'Parse \uD83D\uDCA9'); // Unicode Character 'PILE OF POO' (U+1F4A9) - -test(function() { - var params = new URLSearchParams('a=b%f0%9f%92%a9c'); - assert_equals(params.get('a'), 'b\uD83D\uDCA9c'); - params = new URLSearchParams('a%f0%9f%92%a9b=c'); - assert_equals(params.get('a\uD83D\uDCA9b'), 'c'); -}, 'Parse %f0%9f%92%a9'); // Unicode Character 'PILE OF POO' (U+1F4A9) - -test(function() { - var params = new URLSearchParams([]); - assert_true(params != null, 'constructor returned non-null value.'); - params = new URLSearchParams([['a', 'b'], ['c', 'd']]); - assert_equals(params.get("a"), "b"); - assert_equals(params.get("c"), "d"); - assert_throws(new TypeError(), function() { new URLSearchParams([[1]]); }); - assert_throws(new TypeError(), function() { new URLSearchParams([[1,2,3]]); }); -}, "Constructor with sequence of sequences of strings"); - -[ - { "input": {"+": "%C2"}, "output": [["+", "%C2"]], "name": "object with +" }, - { "input": {c: "x", a: "?"}, "output": [["c", "x"], ["a", "?"]], "name": "object with two keys" }, - { "input": [["c", "x"], ["a", "?"]], "output": [["c", "x"], ["a", "?"]], "name": "array with two keys" }, - { "input": {"a\0b": "42", "c\uD83D": "23", "d\u1234": "foo"}, "output": [["a\0b", "42"], ["c\uFFFD", "23"], ["d\u1234", "foo"]], "name": "object with NULL, non-ASCII, and surrogate keys" } -].forEach((val) => { - test(() => { - let params = new URLSearchParams(val.input), - i = 0 - for (let param of params) { - assert_array_equals(param, val.output[i]) - i++ - } - }, "Construct with " + val.name) -}) - -test(() => { - params = new URLSearchParams() - params[Symbol.iterator] = function *() { - yield ["a", "b"] - } - let params2 = new URLSearchParams(params) - assert_equals(params2.get("a"), "b") -}, "Custom [Symbol.iterator]") -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-delete.js b/test/parallel/test-whatwg-url-searchparams-delete.js deleted file mode 100644 index cdf3332efc7807..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-delete.js +++ /dev/null @@ -1,59 +0,0 @@ -'use strict'; - -require('../common'); -const { URL, URLSearchParams } = require('url'); -const { test, assert_equals, assert_true, assert_false } = - require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/70a0898763/url/urlsearchparams-delete.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams('a=b&c=d'); - params.delete('a'); - assert_equals(params + '', 'c=d'); - params = new URLSearchParams('a=a&b=b&a=a&c=c'); - params.delete('a'); - assert_equals(params + '', 'b=b&c=c'); - params = new URLSearchParams('a=a&=&b=b&c=c'); - params.delete(''); - assert_equals(params + '', 'a=a&b=b&c=c'); - params = new URLSearchParams('a=a&null=null&b=b'); - params.delete(null); - assert_equals(params + '', 'a=a&b=b'); - params = new URLSearchParams('a=a&undefined=undefined&b=b'); - params.delete(undefined); - assert_equals(params + '', 'a=a&b=b'); -}, 'Delete basics'); - -test(function() { - var params = new URLSearchParams(); - params.append('first', 1); - assert_true(params.has('first'), 'Search params object has name "first"'); - assert_equals(params.get('first'), '1', 'Search params object has name "first" with value "1"'); - params.delete('first'); - assert_false(params.has('first'), 'Search params object has no "first" name'); - params.append('first', 1); - params.append('first', 10); - params.delete('first'); - assert_false(params.has('first'), 'Search params object has no "first" name'); -}, 'Deleting appended multiple'); - -test(function() { - var url = new URL('http://example.com/?param1¶m2'); - url.searchParams.delete('param1'); - url.searchParams.delete('param2'); - assert_equals(url.href, 'http://example.com/', 'url.href does not have ?'); - assert_equals(url.search, '', 'url.search does not have ?'); -}, 'Deleting all params removes ? from URL'); - -test(function() { - var url = new URL('http://example.com/?'); - url.searchParams.delete('param1'); - assert_equals(url.href, 'http://example.com/', 'url.href does not have ?'); - assert_equals(url.search, '', 'url.search does not have ?'); -}, 'Removing non-existent param removes ? from URL'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-foreach.js b/test/parallel/test-whatwg-url-searchparams-foreach.js deleted file mode 100644 index 833858618f8e5b..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-foreach.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -require('../common'); -const { URL, URLSearchParams } = require('url'); -const { test, assert_array_equals, assert_unreached } = - require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/a8b2b1e/url/urlsearchparams-foreach.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -var i; // Strict mode fix for WPT. -test(function() { - var params = new URLSearchParams('a=1&b=2&c=3'); - var keys = []; - var values = []; - params.forEach(function(value, key) { - keys.push(key); - values.push(value); - }); - assert_array_equals(keys, ['a', 'b', 'c']); - assert_array_equals(values, ['1', '2', '3']); -}, "ForEach Check"); - -test(function() { - let a = new URL("http://a.b/c?a=1&b=2&c=3&d=4"); - let b = a.searchParams; - var c = []; - for (i of b) { - a.search = "x=1&y=2&z=3"; - c.push(i); - } - assert_array_equals(c[0], ["a","1"]); - assert_array_equals(c[1], ["y","2"]); - assert_array_equals(c[2], ["z","3"]); -}, "For-of Check"); - -test(function() { - let a = new URL("http://a.b/c"); - let b = a.searchParams; - for (i of b) { - assert_unreached(i); - } -}, "empty"); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-get.js b/test/parallel/test-whatwg-url-searchparams-get.js deleted file mode 100644 index 94e92c18e4b218..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-get.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-get.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams('a=b&c=d'); - assert_equals(params.get('a'), 'b'); - assert_equals(params.get('c'), 'd'); - assert_equals(params.get('e'), null); - params = new URLSearchParams('a=b&c=d&a=e'); - assert_equals(params.get('a'), 'b'); - params = new URLSearchParams('=b&c=d'); - assert_equals(params.get(''), 'b'); - params = new URLSearchParams('a=&c=d&a=e'); - assert_equals(params.get('a'), ''); -}, 'Get basics'); - -test(function() { - var params = new URLSearchParams('first=second&third&&'); - assert_true(params != null, 'constructor returned non-null value.'); - assert_true(params.has('first'), 'Search params object has name "first"'); - assert_equals(params.get('first'), 'second', 'Search params object has name "first" with value "second"'); - assert_equals(params.get('third'), '', 'Search params object has name "third" with the empty value.'); - assert_equals(params.get('fourth'), null, 'Search params object has no "fourth" name and value.'); -}, 'More get() basics'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-getall.js b/test/parallel/test-whatwg-url-searchparams-getall.js deleted file mode 100644 index 06827f37d95bfe..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-getall.js +++ /dev/null @@ -1,39 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true, assert_array_equals } = - require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-getall.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams('a=b&c=d'); - assert_array_equals(params.getAll('a'), ['b']); - assert_array_equals(params.getAll('c'), ['d']); - assert_array_equals(params.getAll('e'), []); - params = new URLSearchParams('a=b&c=d&a=e'); - assert_array_equals(params.getAll('a'), ['b', 'e']); - params = new URLSearchParams('=b&c=d'); - assert_array_equals(params.getAll(''), ['b']); - params = new URLSearchParams('a=&c=d&a=e'); - assert_array_equals(params.getAll('a'), ['', 'e']); -}, 'getAll() basics'); - -test(function() { - var params = new URLSearchParams('a=1&a=2&a=3&a'); - assert_true(params.has('a'), 'Search params object has name "a"'); - var matches = params.getAll('a'); - assert_true(matches && matches.length == 4, 'Search params object has values for name "a"'); - assert_array_equals(matches, ['1', '2', '3', ''], 'Search params object has expected name "a" values'); - params.set('a', 'one'); - assert_equals(params.get('a'), 'one', 'Search params object has name "a" with value "one"'); - var matches = params.getAll('a'); - assert_true(matches && matches.length == 1, 'Search params object has values for name "a"'); - assert_array_equals(matches, ['one'], 'Search params object has expected name "a" values'); -}, 'getAll() multiples'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-has.js b/test/parallel/test-whatwg-url-searchparams-has.js deleted file mode 100644 index 95e69beb4d26ec..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-has.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_false, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-has.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams('a=b&c=d'); - assert_true(params.has('a')); - assert_true(params.has('c')); - assert_false(params.has('e')); - params = new URLSearchParams('a=b&c=d&a=e'); - assert_true(params.has('a')); - params = new URLSearchParams('=b&c=d'); - assert_true(params.has('')); - params = new URLSearchParams('null=a'); - assert_true(params.has(null)); -}, 'Has basics'); - -test(function() { - var params = new URLSearchParams('a=b&c=d&&'); - params.append('first', 1); - params.append('first', 2); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_true(params.has('c'), 'Search params object has name "c"'); - assert_true(params.has('first'), 'Search params object has name "first"'); - assert_false(params.has('d'), 'Search params object has no name "d"'); - params.delete('first'); - assert_false(params.has('first'), 'Search params object has no name "first"'); -}, 'has() following delete()'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-set.js b/test/parallel/test-whatwg-url-searchparams-set.js deleted file mode 100644 index 0d43678427c23f..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-set.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals, assert_true } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-set.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams('a=b&c=d'); - params.set('a', 'B'); - assert_equals(params + '', 'a=B&c=d'); - params = new URLSearchParams('a=b&c=d&a=e'); - params.set('a', 'B'); - assert_equals(params + '', 'a=B&c=d') - params.set('e', 'f'); - assert_equals(params + '', 'a=B&c=d&e=f') -}, 'Set basics'); - -test(function() { - var params = new URLSearchParams('a=1&a=2&a=3'); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_equals(params.get('a'), '1', 'Search params object has name "a" with value "1"'); - params.set('first', 4); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_equals(params.get('a'), '1', 'Search params object has name "a" with value "1"'); - params.set('a', 4); - assert_true(params.has('a'), 'Search params object has name "a"'); - assert_equals(params.get('a'), '4', 'Search params object has name "a" with value "4"'); -}, 'URLSearchParams.set'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-sort.js b/test/parallel/test-whatwg-url-searchparams-sort.js deleted file mode 100644 index 65dd23a6daba57..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-sort.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict'; - -require('../common'); -const { URL, URLSearchParams } = require('url'); -const { test, assert_equals, assert_array_equals } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/70a0898763/url/urlsearchparams-sort.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -[ - { - "input": "z=b&a=b&z=a&a=a", - "output": [["a", "b"], ["a", "a"], ["z", "b"], ["z", "a"]] - }, - { - "input": "\uFFFD=x&\uFFFC&\uFFFD=a", - "output": [["\uFFFC", ""], ["\uFFFD", "x"], ["\uFFFD", "a"]] - }, - { - "input": "ffi&🌈", // 🌈 > code point, but < code unit because two code units - "output": [["🌈", ""], ["ffi", ""]] - }, - { - "input": "é&e\uFFFD&e\u0301", - "output": [["e\u0301", ""], ["e\uFFFD", ""], ["é", ""]] - }, - { - "input": "z=z&a=a&z=y&a=b&z=x&a=c&z=w&a=d&z=v&a=e&z=u&a=f&z=t&a=g", - "output": [["a", "a"], ["a", "b"], ["a", "c"], ["a", "d"], ["a", "e"], ["a", "f"], ["a", "g"], ["z", "z"], ["z", "y"], ["z", "x"], ["z", "w"], ["z", "v"], ["z", "u"], ["z", "t"]] - } -].forEach((val) => { - test(() => { - let params = new URLSearchParams(val.input), - i = 0 - params.sort() - for(let param of params) { - assert_array_equals(param, val.output[i]) - i++ - } - }, `Parse and sort: ${val.input}`) - - test(() => { - let url = new URL(`?${val.input}`, "https://example/") - url.searchParams.sort() - let params = new URLSearchParams(url.search), - i = 0 - for(let param of params) { - assert_array_equals(param, val.output[i]) - i++ - } - }, `URL parse and sort: ${val.input}`) -}) - -test(function() { - const url = new URL("http://example.com/?") - url.searchParams.sort() - assert_equals(url.href, "http://example.com/") - assert_equals(url.search, "") -}, "Sorting non-existent params removes ? from URL") -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-searchparams-stringifier.js b/test/parallel/test-whatwg-url-searchparams-stringifier.js deleted file mode 100644 index e2b6faaabe85fc..00000000000000 --- a/test/parallel/test-whatwg-url-searchparams-stringifier.js +++ /dev/null @@ -1,123 +0,0 @@ -'use strict'; - -require('../common'); -const URLSearchParams = require('url').URLSearchParams; -const { test, assert_equals } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-stringifier.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(function() { - var params = new URLSearchParams(); - params.append('a', 'b c'); - assert_equals(params + '', 'a=b+c'); - params.delete('a'); - params.append('a b', 'c'); - assert_equals(params + '', 'a+b=c'); -}, 'Serialize space'); - -test(function() { - var params = new URLSearchParams(); - params.append('a', ''); - assert_equals(params + '', 'a='); - params.append('a', ''); - assert_equals(params + '', 'a=&a='); - params.append('', 'b'); - assert_equals(params + '', 'a=&a=&=b'); - params.append('', ''); - assert_equals(params + '', 'a=&a=&=b&='); - params.append('', ''); - assert_equals(params + '', 'a=&a=&=b&=&='); -}, 'Serialize empty value'); - -test(function() { - var params = new URLSearchParams(); - params.append('', 'b'); - assert_equals(params + '', '=b'); - params.append('', 'b'); - assert_equals(params + '', '=b&=b'); -}, 'Serialize empty name'); - -test(function() { - var params = new URLSearchParams(); - params.append('', ''); - assert_equals(params + '', '='); - params.append('', ''); - assert_equals(params + '', '=&='); -}, 'Serialize empty name and value'); - -test(function() { - var params = new URLSearchParams(); - params.append('a', 'b+c'); - assert_equals(params + '', 'a=b%2Bc'); - params.delete('a'); - params.append('a+b', 'c'); - assert_equals(params + '', 'a%2Bb=c'); -}, 'Serialize +'); - -test(function() { - var params = new URLSearchParams(); - params.append('=', 'a'); - assert_equals(params + '', '%3D=a'); - params.append('b', '='); - assert_equals(params + '', '%3D=a&b=%3D'); -}, 'Serialize ='); - -test(function() { - var params = new URLSearchParams(); - params.append('&', 'a'); - assert_equals(params + '', '%26=a'); - params.append('b', '&'); - assert_equals(params + '', '%26=a&b=%26'); -}, 'Serialize &'); - -test(function() { - var params = new URLSearchParams(); - params.append('a', '*-._'); - assert_equals(params + '', 'a=*-._'); - params.delete('a'); - params.append('*-._', 'c'); - assert_equals(params + '', '*-._=c'); -}, 'Serialize *-._'); - -test(function() { - var params = new URLSearchParams(); - params.append('a', 'b%c'); - assert_equals(params + '', 'a=b%25c'); - params.delete('a'); - params.append('a%b', 'c'); - assert_equals(params + '', 'a%25b=c'); -}, 'Serialize %'); - -test(function() { - var params = new URLSearchParams(); - params.append('a', 'b\0c'); - assert_equals(params + '', 'a=b%00c'); - params.delete('a'); - params.append('a\0b', 'c'); - assert_equals(params + '', 'a%00b=c'); -}, 'Serialize \\0'); - -test(function() { - var params = new URLSearchParams(); - params.append('a', 'b\uD83D\uDCA9c'); - assert_equals(params + '', 'a=b%F0%9F%92%A9c'); - params.delete('a'); - params.append('a\uD83D\uDCA9b', 'c'); - assert_equals(params + '', 'a%F0%9F%92%A9b=c'); -}, 'Serialize \uD83D\uDCA9'); // Unicode Character 'PILE OF POO' (U+1F4A9) - -test(function() { - var params; - params = new URLSearchParams('a=b&c=d&&e&&'); - assert_equals(params.toString(), 'a=b&c=d&e='); - params = new URLSearchParams('a = b &a=b&c=d%20'); - assert_equals(params.toString(), 'a+=+b+&a=b&c=d+'); - // The lone '=' _does_ survive the roundtrip. - params = new URLSearchParams('a=&a=b'); - assert_equals(params.toString(), 'a=&a=b'); -}, 'URLSearchParams.toString'); -/* eslint-enable */ diff --git a/test/parallel/test-whatwg-url-tojson.js b/test/parallel/test-whatwg-url-tojson.js deleted file mode 100644 index 8e9a30c7e017e4..00000000000000 --- a/test/parallel/test-whatwg-url-tojson.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict'; - -require('../common'); -const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/02585db/url/url-tojson.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ -test(() => { - const a = new URL("https://example.com/") - assert_equals(JSON.stringify(a), "\"https://example.com/\"") -}) -/* eslint-enable */ From c973551ecaff1229105acc004ba995f26067e9b5 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Tue, 30 Oct 2018 12:03:41 +0800 Subject: [PATCH 133/249] test: use URL fixtures under test/fixtures/wpt/url/resources Removes the following files: - test/fixtures/url-tests.js - test/fixtures/url-setter-tests.js - test/fixtures/url-toascii.js in favor of: - test/fixtures/wpt/url/resources/urltestdata.json - test/fixtures/wpt/url/resources/setters_tests.json - test/fixtures/wpt/url/resources/toascii.json Also removes dependency of `fixtures/url-tests.js` in http2 tests and use `fixtures/person-large.jpg` instead since they are just looking for a big enough file to transfer. PR-URL: https://github.com/nodejs/node/pull/24035 Refs: https://github.com/nodejs/node/issues/23192 Reviewed-By: Daijiro Wachi --- test/fixtures/url-setter-tests.js | 1874 ----- test/fixtures/url-tests.js | 6662 ----------------- test/fixtures/url-toascii.js | 157 - .../test-url-parse-conformance.js | 4 +- .../test-http2-compat-serverrequest-pipe.js | 2 +- test/parallel/test-http2-pipe-named-pipe.js | 2 +- test/parallel/test-http2-pipe.js | 2 +- test/parallel/test-icu-punycode.js | 5 +- test/parallel/test-whatwg-url-constructor.js | 4 +- .../test-whatwg-url-custom-domainto.js | 5 +- .../test-whatwg-url-custom-parsing.js | 4 +- test/parallel/test-whatwg-url-origin.js | 4 +- test/parallel/test-whatwg-url-setters.js | 4 +- test/parallel/test-whatwg-url-toascii.js | 4 +- 14 files changed, 29 insertions(+), 8704 deletions(-) delete mode 100644 test/fixtures/url-setter-tests.js delete mode 100644 test/fixtures/url-tests.js delete mode 100644 test/fixtures/url-toascii.js diff --git a/test/fixtures/url-setter-tests.js b/test/fixtures/url-setter-tests.js deleted file mode 100644 index 1e460ff2d8dd7c..00000000000000 --- a/test/fixtures/url-setter-tests.js +++ /dev/null @@ -1,1874 +0,0 @@ -'use strict'; - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/f0fe479/url/setters_tests.json - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -module.exports = -{ - "comment": [ - "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members", - "", - "This file contains a JSON object.", - "Other than 'comment', each key is an attribute of the `URL` interface", - "defined in WHATWG’s URL Standard.", - "The values are arrays of test case objects for that attribute.", - "", - "To run a test case for the attribute `attr`:", - "", - "* Create a new `URL` object with the value for the 'href' key", - " the constructor single parameter. (Without a base URL.)", - " This must not throw.", - "* Set the attribute `attr` to (invoke its setter with)", - " with the value of for 'new_value' key.", - "* The value for the 'expected' key is another object.", - " For each `key` / `value` pair of that object,", - " get the attribute `key` (invoke its getter).", - " The returned string must be equal to `value`.", - "", - "Note: the 'href' setter is already covered by urltestdata.json." - ], - "protocol": [ - { - "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.", - "href": "a://example.net", - "new_value": "", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "href": "a://example.net", - "new_value": "b", - "expected": { - "href": "b://example.net", - "protocol": "b:" - } - }, - { - "href": "javascript:alert(1)", - "new_value": "defuse", - "expected": { - "href": "defuse:alert(1)", - "protocol": "defuse:" - } - }, - { - "comment": "Upper-case ASCII is lower-cased", - "href": "a://example.net", - "new_value": "B", - "expected": { - "href": "b://example.net", - "protocol": "b:" - } - }, - { - "comment": "Non-ASCII is rejected", - "href": "a://example.net", - "new_value": "é", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "No leading digit", - "href": "a://example.net", - "new_value": "0b", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "No leading punctuation", - "href": "a://example.net", - "new_value": "+b", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "href": "a://example.net", - "new_value": "bC0+-.", - "expected": { - "href": "bc0+-.://example.net", - "protocol": "bc0+-.:" - } - }, - { - "comment": "Only some punctuation is acceptable", - "href": "a://example.net", - "new_value": "b,c", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "Non-ASCII is rejected", - "href": "a://example.net", - "new_value": "bé", - "expected": { - "href": "a://example.net", - "protocol": "a:" - } - }, - { - "comment": "Can’t switch from URL containing username/password/port to file", - "href": "http://test@example.net", - "new_value": "file", - "expected": { - "href": "http://test@example.net/", - "protocol": "http:" - } - }, - { - "href": "gopher://example.net:1234", - "new_value": "file", - "expected": { - "href": "gopher://example.net:1234/", - "protocol": "gopher:" - } - }, - { - "href": "wss://x:x@example.net:1234", - "new_value": "file", - "expected": { - "href": "wss://x:x@example.net:1234/", - "protocol": "wss:" - } - }, - { - "comment": "Can’t switch from file URL with no host", - "href": "file://localhost/", - "new_value": "http", - "expected": { - "href": "file:///", - "protocol": "file:" - } - }, - { - "href": "file:///test", - "new_value": "gopher", - "expected": { - "href": "file:///test", - "protocol": "file:" - } - }, - { - "href": "file:", - "new_value": "wss", - "expected": { - "href": "file:///", - "protocol": "file:" - } - }, - { - "comment": "Can’t switch from special scheme to non-special", - "href": "http://example.net", - "new_value": "b", - "expected": { - "href": "http://example.net/", - "protocol": "http:" - } - }, - { - "href": "file://hi/path", - "new_value": "s", - "expected": { - "href": "file://hi/path", - "protocol": "file:" - } - }, - { - "href": "https://example.net", - "new_value": "s", - "expected": { - "href": "https://example.net/", - "protocol": "https:" - } - }, - { - "href": "ftp://example.net", - "new_value": "test", - "expected": { - "href": "ftp://example.net/", - "protocol": "ftp:" - } - }, - { - "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.", - "href": "mailto:me@example.net", - "new_value": "http", - "expected": { - "href": "mailto:me@example.net", - "protocol": "mailto:" - } - }, - { - "comment": "Can’t switch from non-special scheme to special", - "href": "ssh://me@example.net", - "new_value": "http", - "expected": { - "href": "ssh://me@example.net", - "protocol": "ssh:" - } - }, - { - "href": "ssh://me@example.net", - "new_value": "gopher", - "expected": { - "href": "ssh://me@example.net", - "protocol": "ssh:" - } - }, - { - "href": "ssh://me@example.net", - "new_value": "file", - "expected": { - "href": "ssh://me@example.net", - "protocol": "ssh:" - } - }, - { - "href": "ssh://example.net", - "new_value": "file", - "expected": { - "href": "ssh://example.net", - "protocol": "ssh:" - } - }, - { - "href": "nonsense:///test", - "new_value": "https", - "expected": { - "href": "nonsense:///test", - "protocol": "nonsense:" - } - }, - { - "comment": "Stuff after the first ':' is ignored", - "href": "http://example.net", - "new_value": "https:foo : bar", - "expected": { - "href": "https://example.net/", - "protocol": "https:" - } - }, - { - "comment": "Stuff after the first ':' is ignored", - "href": "data:text/html,

Test", - "new_value": "view-source+data:foo : bar", - "expected": { - "href": "view-source+data:text/html,

Test", - "protocol": "view-source+data:" - } - }, - { - "comment": "Port is set to null if it is the default for new scheme.", - "href": "http://foo.com:443/", - "new_value": "https", - "expected": { - "href": "https://foo.com/", - "protocol": "https:", - "port": "" - } - } - ], - "username": [ - { - "comment": "No host means no username", - "href": "file:///home/you/index.html", - "new_value": "me", - "expected": { - "href": "file:///home/you/index.html", - "username": "" - } - }, - { - "comment": "No host means no username", - "href": "unix:/run/foo.socket", - "new_value": "me", - "expected": { - "href": "unix:/run/foo.socket", - "username": "" - } - }, - { - "comment": "Cannot-be-a-base means no username", - "href": "mailto:you@example.net", - "new_value": "me", - "expected": { - "href": "mailto:you@example.net", - "username": "" - } - }, - { - "href": "javascript:alert(1)", - "new_value": "wario", - "expected": { - "href": "javascript:alert(1)", - "username": "" - } - }, - { - "href": "http://example.net", - "new_value": "me", - "expected": { - "href": "http://me@example.net/", - "username": "me" - } - }, - { - "href": "http://:secret@example.net", - "new_value": "me", - "expected": { - "href": "http://me:secret@example.net/", - "username": "me" - } - }, - { - "href": "http://me@example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "username": "" - } - }, - { - "href": "http://me:secret@example.net", - "new_value": "", - "expected": { - "href": "http://:secret@example.net/", - "username": "" - } - }, - { - "comment": "UTF-8 percent encoding with the userinfo encode set.", - "href": "http://example.net", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", - "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is.", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://%c3%89t%C3%A9@example.net/", - "username": "%c3%89t%C3%A9" - } - }, - { - "href": "sc:///", - "new_value": "x", - "expected": { - "href": "sc:///", - "username": "" - } - }, - { - "href": "javascript://x/", - "new_value": "wario", - "expected": { - "href": "javascript://wario@x/", - "username": "wario" - } - }, - { - "href": "file://test/", - "new_value": "test", - "expected": { - "href": "file://test/", - "username": "" - } - } - ], - "password": [ - { - "comment": "No host means no password", - "href": "file:///home/me/index.html", - "new_value": "secret", - "expected": { - "href": "file:///home/me/index.html", - "password": "" - } - }, - { - "comment": "No host means no password", - "href": "unix:/run/foo.socket", - "new_value": "secret", - "expected": { - "href": "unix:/run/foo.socket", - "password": "" - } - }, - { - "comment": "Cannot-be-a-base means no password", - "href": "mailto:me@example.net", - "new_value": "secret", - "expected": { - "href": "mailto:me@example.net", - "password": "" - } - }, - { - "href": "http://example.net", - "new_value": "secret", - "expected": { - "href": "http://:secret@example.net/", - "password": "secret" - } - }, - { - "href": "http://me@example.net", - "new_value": "secret", - "expected": { - "href": "http://me:secret@example.net/", - "password": "secret" - } - }, - { - "href": "http://:secret@example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "password": "" - } - }, - { - "href": "http://me:secret@example.net", - "new_value": "", - "expected": { - "href": "http://me@example.net/", - "password": "" - } - }, - { - "comment": "UTF-8 percent encoding with the userinfo encode set.", - "href": "http://example.net", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", - "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is.", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://:%c3%89t%C3%A9@example.net/", - "password": "%c3%89t%C3%A9" - } - }, - { - "href": "sc:///", - "new_value": "x", - "expected": { - "href": "sc:///", - "password": "" - } - }, - { - "href": "javascript://x/", - "new_value": "bowser", - "expected": { - "href": "javascript://:bowser@x/", - "password": "bowser" - } - }, - { - "href": "file://test/", - "new_value": "test", - "expected": { - "href": "file://test/", - "password": "" - } - } - ], - "host": [ - { - "comment": "Non-special scheme", - "href": "sc://x/", - "new_value": "\u0000", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "\u0009", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000A", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000D", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": " ", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "#", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "/", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "?", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "@", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "ß", - "expected": { - "href": "sc://%C3%9F/", - "host": "%C3%9F", - "hostname": "%C3%9F" - } - }, - { - "comment": "IDNA Nontransitional_Processing", - "href": "https://x/", - "new_value": "ß", - "expected": { - "href": "https://xn--zca/", - "host": "xn--zca", - "hostname": "xn--zca" - } - }, - { - "comment": "Cannot-be-a-base means no host", - "href": "mailto:me@example.net", - "new_value": "example.com", - "expected": { - "href": "mailto:me@example.net", - "host": "" - } - }, - { - "comment": "Cannot-be-a-base means no password", - "href": "data:text/plain,Stuff", - "new_value": "example.net", - "expected": { - "href": "data:text/plain,Stuff", - "host": "" - } - }, - { - "href": "http://example.net", - "new_value": "example.com:8080", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Port number is unchanged if not specified in the new value", - "href": "http://example.net:8080", - "new_value": "example.com", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Port number is unchanged if not specified", - "href": "http://example.net:8080", - "new_value": "example.com:", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "The empty host is not valid for special schemes", - "href": "http://example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "host": "example.net" - } - }, - { - "comment": "The empty host is OK for non-special schemes", - "href": "view-source+http://example.net/foo", - "new_value": "", - "expected": { - "href": "view-source+http:///foo", - "host": "" - } - }, - { - "comment": "Path-only URLs can gain a host", - "href": "a:/foo", - "new_value": "example.net", - "expected": { - "href": "a://example.net/foo", - "host": "example.net" - } - }, - { - "comment": "IPv4 address syntax is normalized", - "href": "http://example.net", - "new_value": "0x7F000001:8080", - "expected": { - "href": "http://127.0.0.1:8080/", - "host": "127.0.0.1:8080", - "hostname": "127.0.0.1", - "port": "8080" - } - }, - { - "comment": "IPv6 address syntax is normalized", - "href": "http://example.net", - "new_value": "[::0:01]:2", - "expected": { - "href": "http://[::1]:2/", - "host": "[::1]:2", - "hostname": "[::1]", - "port": "2" - } - }, - { - "comment": "Default port number is removed", - "href": "http://example.net", - "new_value": "example.com:80", - "expected": { - "href": "http://example.com/", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Default port number is removed", - "href": "https://example.net", - "new_value": "example.com:443", - "expected": { - "href": "https://example.com/", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Default port number is only removed for the relevant scheme", - "href": "https://example.net", - "new_value": "example.com:80", - "expected": { - "href": "https://example.com:80/", - "host": "example.com:80", - "hostname": "example.com", - "port": "80" - } - }, - { - "comment": "Port number is removed if new port is scheme default and existing URL has a non-default port", - "href": "http://example.net:8080", - "new_value": "example.com:80", - "expected": { - "href": "http://example.com/", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com/stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080/stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com?stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080?stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com#stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080#stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "example.com:8080\\stuff", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", - "href": "view-source+http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "view-source+http://example.net/path", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "view-source+http://example.net/path", - "new_value": "example.com:8080stuff2", - "expected": { - "href": "view-source+http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "example.com:8080stuff2", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "example.com:8080+2", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Port numbers are 16 bit integers", - "href": "http://example.net/path", - "new_value": "example.com:65535", - "expected": { - "href": "http://example.com:65535/path", - "host": "example.com:65535", - "hostname": "example.com", - "port": "65535" - } - }, - { - "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.", - "href": "http://example.net/path", - "new_value": "example.com:65536", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Broken IPv6", - "href": "http://example.net/", - "new_value": "[google.com]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.4x]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "file://y/", - "new_value": "x:123", - "expected": { - "href": "file://y/", - "host": "y", - "hostname": "y", - "port": "" - } - }, - { - "href": "file://y/", - "new_value": "loc%41lhost", - "expected": { - "href": "file:///", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "file://hi/x", - "new_value": "", - "expected": { - "href": "file:///x", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "sc://test@test/", - "new_value": "", - "expected": { - "href": "sc://test@test/", - "host": "test", - "hostname": "test", - "username": "test" - } - }, - { - "href": "sc://test:12/", - "new_value": "", - "expected": { - "href": "sc://test:12/", - "host": "test:12", - "hostname": "test", - "port": "12" - } - } - ], - "hostname": [ - { - "comment": "Non-special scheme", - "href": "sc://x/", - "new_value": "\u0000", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "\u0009", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000A", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "\u000D", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": " ", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "href": "sc://x/", - "new_value": "#", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "/", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "?", - "expected": { - "href": "sc:///", - "host": "", - "hostname": "" - } - }, - { - "href": "sc://x/", - "new_value": "@", - "expected": { - "href": "sc://x/", - "host": "x", - "hostname": "x" - } - }, - { - "comment": "Cannot-be-a-base means no host", - "href": "mailto:me@example.net", - "new_value": "example.com", - "expected": { - "href": "mailto:me@example.net", - "host": "" - } - }, - { - "comment": "Cannot-be-a-base means no password", - "href": "data:text/plain,Stuff", - "new_value": "example.net", - "expected": { - "href": "data:text/plain,Stuff", - "host": "" - } - }, - { - "href": "http://example.net:8080", - "new_value": "example.com", - "expected": { - "href": "http://example.com:8080/", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "The empty host is not valid for special schemes", - "href": "http://example.net", - "new_value": "", - "expected": { - "href": "http://example.net/", - "host": "example.net" - } - }, - { - "comment": "The empty host is OK for non-special schemes", - "href": "view-source+http://example.net/foo", - "new_value": "", - "expected": { - "href": "view-source+http:///foo", - "host": "" - } - }, - { - "comment": "Path-only URLs can gain a host", - "href": "a:/foo", - "new_value": "example.net", - "expected": { - "href": "a://example.net/foo", - "host": "example.net" - } - }, - { - "comment": "IPv4 address syntax is normalized", - "href": "http://example.net:8080", - "new_value": "0x7F000001", - "expected": { - "href": "http://127.0.0.1:8080/", - "host": "127.0.0.1:8080", - "hostname": "127.0.0.1", - "port": "8080" - } - }, - { - "comment": "IPv6 address syntax is normalized", - "href": "http://example.net", - "new_value": "[::0:01]", - "expected": { - "href": "http://[::1]/", - "host": "[::1]", - "hostname": "[::1]", - "port": "" - } - }, - { - "comment": "Stuff after a : delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com:8080", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a : delimiter is ignored", - "href": "http://example.net:8080/path", - "new_value": "example.com:", - "expected": { - "href": "http://example.com:8080/path", - "host": "example.com:8080", - "hostname": "example.com", - "port": "8080" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com/stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com?stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "example.com#stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "http://example.com/path", - "host": "example.com", - "hostname": "example.com", - "port": "" - } - }, - { - "comment": "\\ is not a delimiter for non-special schemes, but still forbidden in hosts", - "href": "view-source+http://example.net/path", - "new_value": "example.com\\stuff", - "expected": { - "href": "view-source+http://example.net/path", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Broken IPv6", - "href": "http://example.net/", - "new_value": "[google.com]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.4x]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.3.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.2.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "http://example.net/", - "new_value": "[::1.]", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net" - } - }, - { - "href": "file://y/", - "new_value": "x:123", - "expected": { - "href": "file://y/", - "host": "y", - "hostname": "y", - "port": "" - } - }, - { - "href": "file://y/", - "new_value": "loc%41lhost", - "expected": { - "href": "file:///", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "file://hi/x", - "new_value": "", - "expected": { - "href": "file:///x", - "host": "", - "hostname": "", - "port": "" - } - }, - { - "href": "sc://test@test/", - "new_value": "", - "expected": { - "href": "sc://test@test/", - "host": "test", - "hostname": "test", - "username": "test" - } - }, - { - "href": "sc://test:12/", - "new_value": "", - "expected": { - "href": "sc://test:12/", - "host": "test:12", - "hostname": "test", - "port": "12" - } - } - ], - "port": [ - { - "href": "http://example.net", - "new_value": "8080", - "expected": { - "href": "http://example.net:8080/", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Port number is removed if empty is the new value", - "href": "http://example.net:8080", - "new_value": "", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Default port number is removed", - "href": "http://example.net:8080", - "new_value": "80", - "expected": { - "href": "http://example.net/", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Default port number is removed", - "href": "https://example.net:4433", - "new_value": "443", - "expected": { - "href": "https://example.net/", - "host": "example.net", - "hostname": "example.net", - "port": "" - } - }, - { - "comment": "Default port number is only removed for the relevant scheme", - "href": "https://example.net", - "new_value": "80", - "expected": { - "href": "https://example.net:80/", - "host": "example.net:80", - "hostname": "example.net", - "port": "80" - } - }, - { - "comment": "Stuff after a / delimiter is ignored", - "href": "http://example.net/path", - "new_value": "8080/stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a ? delimiter is ignored", - "href": "http://example.net/path", - "new_value": "8080?stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a # delimiter is ignored", - "href": "http://example.net/path", - "new_value": "8080#stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Stuff after a \\ delimiter is ignored for special schemes", - "href": "http://example.net/path", - "new_value": "8080\\stuff", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "view-source+http://example.net/path", - "new_value": "8080stuff2", - "expected": { - "href": "view-source+http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "8080stuff2", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", - "href": "http://example.net/path", - "new_value": "8080+2", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Port numbers are 16 bit integers", - "href": "http://example.net/path", - "new_value": "65535", - "expected": { - "href": "http://example.net:65535/path", - "host": "example.net:65535", - "hostname": "example.net", - "port": "65535" - } - }, - { - "comment": "Port numbers are 16 bit integers, overflowing is an error", - "href": "http://example.net:8080/path", - "new_value": "65536", - "expected": { - "href": "http://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "comment": "Port numbers are 16 bit integers, overflowing is an error", - "href": "non-special://example.net:8080/path", - "new_value": "65536", - "expected": { - "href": "non-special://example.net:8080/path", - "host": "example.net:8080", - "hostname": "example.net", - "port": "8080" - } - }, - { - "href": "file://test/", - "new_value": "12", - "expected": { - "href": "file://test/", - "port": "" - } - }, - { - "href": "file://localhost/", - "new_value": "12", - "expected": { - "href": "file:///", - "port": "" - } - }, - { - "href": "non-base:value", - "new_value": "12", - "expected": { - "href": "non-base:value", - "port": "" - } - }, - { - "href": "sc:///", - "new_value": "12", - "expected": { - "href": "sc:///", - "port": "" - } - }, - { - "href": "sc://x/", - "new_value": "12", - "expected": { - "href": "sc://x:12/", - "port": "12" - } - }, - { - "href": "javascript://x/", - "new_value": "12", - "expected": { - "href": "javascript://x:12/", - "port": "12" - } - } - ], - "pathname": [ - { - "comment": "Cannot-be-a-base don’t have a path", - "href": "mailto:me@example.net", - "new_value": "/foo", - "expected": { - "href": "mailto:me@example.net", - "pathname": "me@example.net" - } - }, - { - "href": "unix:/run/foo.socket?timeout=10", - "new_value": "/var/log/../run/bar.socket", - "expected": { - "href": "unix:/var/run/bar.socket?timeout=10", - "pathname": "/var/run/bar.socket" - } - }, - { - "href": "https://example.net#nav", - "new_value": "home", - "expected": { - "href": "https://example.net/home#nav", - "pathname": "/home" - } - }, - { - "href": "https://example.net#nav", - "new_value": "../home", - "expected": { - "href": "https://example.net/home#nav", - "pathname": "/home" - } - }, - { - "comment": "\\ is a segment delimiter for 'special' URLs", - "href": "http://example.net/home?lang=fr#nav", - "new_value": "\\a\\%2E\\b\\%2e.\\c", - "expected": { - "href": "http://example.net/a/c?lang=fr#nav", - "pathname": "/a/c" - } - }, - { - "comment": "\\ is *not* a segment delimiter for non-'special' URLs", - "href": "view-source+http://example.net/home?lang=fr#nav", - "new_value": "\\a\\%2E\\b\\%2e.\\c", - "expected": { - "href": "view-source+http://example.net/\\a\\%2E\\b\\%2e.\\c?lang=fr#nav", - "pathname": "/\\a\\%2E\\b\\%2e.\\c" - } - }, - { - "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.", - "href": "a:/", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", - "pathname": "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is, including %2E outside dotted segments.", - "href": "http://example.net", - "new_value": "%2e%2E%c3%89té", - "expected": { - "href": "http://example.net/%2e%2E%c3%89t%C3%A9", - "pathname": "/%2e%2E%c3%89t%C3%A9" - } - }, - { - "comment": "? needs to be encoded", - "href": "http://example.net", - "new_value": "?", - "expected": { - "href": "http://example.net/%3F", - "pathname": "/%3F" - } - }, - { - "comment": "# needs to be encoded", - "href": "http://example.net", - "new_value": "#", - "expected": { - "href": "http://example.net/%23", - "pathname": "/%23" - } - }, - { - "comment": "? needs to be encoded, non-special scheme", - "href": "sc://example.net", - "new_value": "?", - "expected": { - "href": "sc://example.net/%3F", - "pathname": "/%3F" - } - }, - { - "comment": "# needs to be encoded, non-special scheme", - "href": "sc://example.net", - "new_value": "#", - "expected": { - "href": "sc://example.net/%23", - "pathname": "/%23" - } - }, - { - "comment": "File URLs and (back)slashes", - "href": "file://monkey/", - "new_value": "\\\\", - "expected": { - "href": "file://monkey/", - "pathname": "/" - } - }, - { - "comment": "File URLs and (back)slashes", - "href": "file:///unicorn", - "new_value": "//\\/", - "expected": { - "href": "file:///", - "pathname": "/" - } - }, - { - "comment": "File URLs and (back)slashes", - "href": "file:///unicorn", - "new_value": "//monkey/..//", - "expected": { - "href": "file:///", - "pathname": "/" - } - } - ], - "search": [ - { - "href": "https://example.net#nav", - "new_value": "lang=fr", - "expected": { - "href": "https://example.net/?lang=fr#nav", - "search": "?lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "lang=fr", - "expected": { - "href": "https://example.net/?lang=fr#nav", - "search": "?lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "?lang=fr", - "expected": { - "href": "https://example.net/?lang=fr#nav", - "search": "?lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "??lang=fr", - "expected": { - "href": "https://example.net/??lang=fr#nav", - "search": "??lang=fr" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "?", - "expected": { - "href": "https://example.net/?#nav", - "search": "" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "", - "expected": { - "href": "https://example.net/#nav", - "search": "" - } - }, - { - "href": "https://example.net?lang=en-US", - "new_value": "", - "expected": { - "href": "https://example.net/", - "search": "" - } - }, - { - "href": "https://example.net", - "new_value": "", - "expected": { - "href": "https://example.net/", - "search": "" - } - }, - { - "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.", - "href": "a:/", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", - "search": "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://example.net/?%c3%89t%C3%A9", - "search": "?%c3%89t%C3%A9" - } - } - ], - "hash": [ - { - "href": "https://example.net", - "new_value": "main", - "expected": { - "href": "https://example.net/#main", - "hash": "#main" - } - }, - { - "href": "https://example.net#nav", - "new_value": "main", - "expected": { - "href": "https://example.net/#main", - "hash": "#main" - } - }, - { - "href": "https://example.net?lang=en-US", - "new_value": "##nav", - "expected": { - "href": "https://example.net/?lang=en-US##nav", - "hash": "##nav" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "#main", - "expected": { - "href": "https://example.net/?lang=en-US#main", - "hash": "#main" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "#", - "expected": { - "href": "https://example.net/?lang=en-US#", - "hash": "" - } - }, - { - "href": "https://example.net?lang=en-US#nav", - "new_value": "", - "expected": { - "href": "https://example.net/?lang=en-US", - "hash": "" - } - }, - { - "href": "http://example.net", - "new_value": "#foo bar", - "expected": { - "href": "http://example.net/#foo%20bar", - "hash": "#foo%20bar" - } - }, - { - "href": "http://example.net", - "new_value": "#foo\"bar", - "expected": { - "href": "http://example.net/#foo%22bar", - "hash": "#foo%22bar" - } - }, - { - "href": "http://example.net", - "new_value": "#foobar", - "expected": { - "href": "http://example.net/#foo%3Ebar", - "hash": "#foo%3Ebar" - } - }, - { - "href": "http://example.net", - "new_value": "#foo`bar", - "expected": { - "href": "http://example.net/#foo%60bar", - "hash": "#foo%60bar" - } - }, - { - "comment": "Simple percent-encoding; nuls, tabs, and newlines are removed", - "href": "a:/", - "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", - "expected": { - "href": "a:/#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", - "hash": "#%01%1F%20!%22#$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_%60az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" - } - }, - { - "comment": "Bytes already percent-encoded are left as-is", - "href": "http://example.net", - "new_value": "%c3%89té", - "expected": { - "href": "http://example.net/#%c3%89t%C3%A9", - "hash": "#%c3%89t%C3%A9" - } - }, - { - "href": "javascript:alert(1)", - "new_value": "castle", - "expected": { - "href": "javascript:alert(1)#castle", - "hash": "#castle" - } - } - ] -} diff --git a/test/fixtures/url-tests.js b/test/fixtures/url-tests.js deleted file mode 100644 index be0365edae7c72..00000000000000 --- a/test/fixtures/url-tests.js +++ /dev/null @@ -1,6662 +0,0 @@ -'use strict'; - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/web-platform-tests/wpt/blob/ba4921d054/url/resources/urltestdata.json - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -module.exports = -[ - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/segments.js", - { - "input": "http://example\t.\norg", - "base": "http://example.org/foo/bar", - "href": "http://example.org/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://user:pass@foo:21/bar;par?b#c", - "base": "http://example.org/foo/bar", - "href": "http://user:pass@foo:21/bar;par?b#c", - "origin": "http://foo:21", - "protocol": "http:", - "username": "user", - "password": "pass", - "host": "foo:21", - "hostname": "foo", - "port": "21", - "pathname": "/bar;par", - "search": "?b", - "hash": "#c" - }, - { - "input": "https://test:@test", - "base": "about:blank", - "href": "https://test@test/", - "origin": "https://test", - "protocol": "https:", - "username": "test", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://:@test", - "base": "about:blank", - "href": "https://test/", - "origin": "https://test", - "protocol": "https:", - "username": "", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://test:@test/x", - "base": "about:blank", - "href": "non-special://test@test/x", - "origin": "null", - "protocol": "non-special:", - "username": "test", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/x", - "search": "", - "hash": "" - }, - { - "input": "non-special://:@test/x", - "base": "about:blank", - "href": "non-special://test/x", - "origin": "null", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/x", - "search": "", - "hash": "" - }, - { - "input": "http:foo.com", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/foo.com", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/foo.com", - "search": "", - "hash": "" - }, - { - "input": "\t :foo.com \n", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:foo.com", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:foo.com", - "search": "", - "hash": "" - }, - { - "input": " foo.com ", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/foo.com", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/foo.com", - "search": "", - "hash": "" - }, - { - "input": "a:\t foo.com", - "base": "http://example.org/foo/bar", - "href": "a: foo.com", - "origin": "null", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": " foo.com", - "search": "", - "hash": "" - }, - { - "input": "http://f:21/ b ? d # e ", - "base": "http://example.org/foo/bar", - "href": "http://f:21/%20b%20?%20d%20#%20e", - "origin": "http://f:21", - "protocol": "http:", - "username": "", - "password": "", - "host": "f:21", - "hostname": "f", - "port": "21", - "pathname": "/%20b%20", - "search": "?%20d%20", - "hash": "#%20e" - }, - { - "input": "lolscheme:x x#x x", - "base": "about:blank", - "href": "lolscheme:x x#x%20x", - "protocol": "lolscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "x x", - "search": "", - "hash": "#x%20x" - }, - { - "input": "http://f:/c", - "base": "http://example.org/foo/bar", - "href": "http://f/c", - "origin": "http://f", - "protocol": "http:", - "username": "", - "password": "", - "host": "f", - "hostname": "f", - "port": "", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:0/c", - "base": "http://example.org/foo/bar", - "href": "http://f:0/c", - "origin": "http://f:0", - "protocol": "http:", - "username": "", - "password": "", - "host": "f:0", - "hostname": "f", - "port": "0", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:00000000000000/c", - "base": "http://example.org/foo/bar", - "href": "http://f:0/c", - "origin": "http://f:0", - "protocol": "http:", - "username": "", - "password": "", - "host": "f:0", - "hostname": "f", - "port": "0", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:00000000000000000000080/c", - "base": "http://example.org/foo/bar", - "href": "http://f/c", - "origin": "http://f", - "protocol": "http:", - "username": "", - "password": "", - "host": "f", - "hostname": "f", - "port": "", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:b/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f: /c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f:\n/c", - "base": "http://example.org/foo/bar", - "href": "http://f/c", - "origin": "http://f", - "protocol": "http:", - "username": "", - "password": "", - "host": "f", - "hostname": "f", - "port": "", - "pathname": "/c", - "search": "", - "hash": "" - }, - { - "input": "http://f:fifty-two/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f:999999/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "non-special://f:999999/c", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://f: 21 / b ? d # e ", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": " \t", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": ":foo.com/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:foo.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:foo.com/", - "search": "", - "hash": "" - }, - { - "input": ":foo.com\\", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:foo.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:foo.com/", - "search": "", - "hash": "" - }, - { - "input": ":", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:", - "search": "", - "hash": "" - }, - { - "input": ":a", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:a", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:a", - "search": "", - "hash": "" - }, - { - "input": ":/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:/", - "search": "", - "hash": "" - }, - { - "input": ":\\", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:/", - "search": "", - "hash": "" - }, - { - "input": ":#", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:#", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:", - "search": "", - "hash": "" - }, - { - "input": "#", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "#/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#/" - }, - { - "input": "#\\", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#\\", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#\\" - }, - { - "input": "#;?", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#;?", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#;?" - }, - { - "input": "?", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar?", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": ":23", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:23", - "search": "", - "hash": "" - }, - { - "input": "/:23", - "base": "http://example.org/foo/bar", - "href": "http://example.org/:23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/:23", - "search": "", - "hash": "" - }, - { - "input": "::", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/::", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/::", - "search": "", - "hash": "" - }, - { - "input": "::23", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/::23", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/::23", - "search": "", - "hash": "" - }, - { - "input": "foo://", - "base": "http://example.org/foo/bar", - "href": "foo://", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "http://a:b@c:29/d", - "base": "http://example.org/foo/bar", - "href": "http://a:b@c:29/d", - "origin": "http://c:29", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "c:29", - "hostname": "c", - "port": "29", - "pathname": "/d", - "search": "", - "hash": "" - }, - { - "input": "http::@c:29", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/:@c:29", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/:@c:29", - "search": "", - "hash": "" - }, - { - "input": "http://&a:foo(b]c@d:2/", - "base": "http://example.org/foo/bar", - "href": "http://&a:foo(b%5Dc@d:2/", - "origin": "http://d:2", - "protocol": "http:", - "username": "&a", - "password": "foo(b%5Dc", - "host": "d:2", - "hostname": "d", - "port": "2", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://::@c@d:2", - "base": "http://example.org/foo/bar", - "href": "http://:%3A%40c@d:2/", - "origin": "http://d:2", - "protocol": "http:", - "username": "", - "password": "%3A%40c", - "host": "d:2", - "hostname": "d", - "port": "2", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo.com:b@d/", - "base": "http://example.org/foo/bar", - "href": "http://foo.com:b@d/", - "origin": "http://d", - "protocol": "http:", - "username": "foo.com", - "password": "b", - "host": "d", - "hostname": "d", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo.com/\\@", - "base": "http://example.org/foo/bar", - "href": "http://foo.com//@", - "origin": "http://foo.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.com", - "hostname": "foo.com", - "port": "", - "pathname": "//@", - "search": "", - "hash": "" - }, - { - "input": "http:\\\\foo.com\\", - "base": "http://example.org/foo/bar", - "href": "http://foo.com/", - "origin": "http://foo.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.com", - "hostname": "foo.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:\\\\a\\b:c\\d@foo.com\\", - "base": "http://example.org/foo/bar", - "href": "http://a/b:c/d@foo.com/", - "origin": "http://a", - "protocol": "http:", - "username": "", - "password": "", - "host": "a", - "hostname": "a", - "port": "", - "pathname": "/b:c/d@foo.com/", - "search": "", - "hash": "" - }, - { - "input": "foo:/", - "base": "http://example.org/foo/bar", - "href": "foo:/", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "foo:/bar.com/", - "base": "http://example.org/foo/bar", - "href": "foo:/bar.com/", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/bar.com/", - "search": "", - "hash": "" - }, - { - "input": "foo://///////", - "base": "http://example.org/foo/bar", - "href": "foo://///////", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "///////", - "search": "", - "hash": "" - }, - { - "input": "foo://///////bar.com/", - "base": "http://example.org/foo/bar", - "href": "foo://///////bar.com/", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "///////bar.com/", - "search": "", - "hash": "" - }, - { - "input": "foo:////://///", - "base": "http://example.org/foo/bar", - "href": "foo:////://///", - "origin": "null", - "protocol": "foo:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//://///", - "search": "", - "hash": "" - }, - { - "input": "c:/foo", - "base": "http://example.org/foo/bar", - "href": "c:/foo", - "origin": "null", - "protocol": "c:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "//foo/bar", - "base": "http://example.org/foo/bar", - "href": "http://foo/bar", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/bar", - "search": "", - "hash": "" - }, - { - "input": "http://foo/path;a??e#f#g", - "base": "http://example.org/foo/bar", - "href": "http://foo/path;a??e#f#g", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/path;a", - "search": "??e", - "hash": "#f#g" - }, - { - "input": "http://foo/abcd?efgh?ijkl", - "base": "http://example.org/foo/bar", - "href": "http://foo/abcd?efgh?ijkl", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/abcd", - "search": "?efgh?ijkl", - "hash": "" - }, - { - "input": "http://foo/abcd#foo?bar", - "base": "http://example.org/foo/bar", - "href": "http://foo/abcd#foo?bar", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/abcd", - "search": "", - "hash": "#foo?bar" - }, - { - "input": "[61:24:74]:98", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/[61:24:74]:98", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/[61:24:74]:98", - "search": "", - "hash": "" - }, - { - "input": "http:[61:27]/:foo", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/[61:27]/:foo", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/[61:27]/:foo", - "search": "", - "hash": "" - }, - { - "input": "http://[1::2]:3:4", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://2001::1", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://2001::1]", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://2001::1]:80", - "base": "http://example.org/foo/bar", - "failure": true - }, - { - "input": "http://[2001::1]", - "base": "http://example.org/foo/bar", - "href": "http://[2001::1]/", - "origin": "http://[2001::1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[2001::1]", - "hostname": "[2001::1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[::127.0.0.1]", - "base": "http://example.org/foo/bar", - "href": "http://[::7f00:1]/", - "origin": "http://[::7f00:1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[::7f00:1]", - "hostname": "[::7f00:1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[0:0:0:0:0:0:13.1.68.3]", - "base": "http://example.org/foo/bar", - "href": "http://[::d01:4403]/", - "origin": "http://[::d01:4403]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[::d01:4403]", - "hostname": "[::d01:4403]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[2001::1]:80", - "base": "http://example.org/foo/bar", - "href": "http://[2001::1]/", - "origin": "http://[2001::1]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[2001::1]", - "hostname": "[2001::1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/example.com/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/example.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftp:/example.com/", - "base": "http://example.org/foo/bar", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:/example.com/", - "base": "http://example.org/foo/bar", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:/example.com/", - "base": "http://example.org/foo/bar", - "href": "madeupscheme:/example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "file:/example.com/", - "base": "http://example.org/foo/bar", - "href": "file:///example.com/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "file://example:1/", - "base": "about:blank", - "failure": true - }, - { - "input": "file://example:test/", - "base": "about:blank", - "failure": true - }, - { - "input": "file://example%/", - "base": "about:blank", - "failure": true - }, - { - "input": "file://[example]/", - "base": "about:blank", - "failure": true - }, - { - "input": "ftps:/example.com/", - "base": "http://example.org/foo/bar", - "href": "ftps:/example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:/example.com/", - "base": "http://example.org/foo/bar", - "href": "gopher://example.com/", - "origin": "gopher://example.com", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws:/example.com/", - "base": "http://example.org/foo/bar", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:/example.com/", - "base": "http://example.org/foo/bar", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:/example.com/", - "base": "http://example.org/foo/bar", - "href": "data:/example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:/example.com/", - "base": "http://example.org/foo/bar", - "href": "javascript:/example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:/example.com/", - "base": "http://example.org/foo/bar", - "href": "mailto:/example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "http:example.com/", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/example.com/", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftp:example.com/", - "base": "http://example.org/foo/bar", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:example.com/", - "base": "http://example.org/foo/bar", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:example.com/", - "base": "http://example.org/foo/bar", - "href": "madeupscheme:example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftps:example.com/", - "base": "http://example.org/foo/bar", - "href": "ftps:example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:example.com/", - "base": "http://example.org/foo/bar", - "href": "gopher://example.com/", - "origin": "gopher://example.com", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws:example.com/", - "base": "http://example.org/foo/bar", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:example.com/", - "base": "http://example.org/foo/bar", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:example.com/", - "base": "http://example.org/foo/bar", - "href": "data:example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:example.com/", - "base": "http://example.org/foo/bar", - "href": "javascript:example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:example.com/", - "base": "http://example.org/foo/bar", - "href": "mailto:example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "/a/b/c", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a/b/c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a/b/c", - "search": "", - "hash": "" - }, - { - "input": "/a/ /c", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a/%20/c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a/%20/c", - "search": "", - "hash": "" - }, - { - "input": "/a%2fc", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a%2fc", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a%2fc", - "search": "", - "hash": "" - }, - { - "input": "/a/%2f/c", - "base": "http://example.org/foo/bar", - "href": "http://example.org/a/%2f/c", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/a/%2f/c", - "search": "", - "hash": "" - }, - { - "input": "#β", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar#%CE%B2", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "#%CE%B2" - }, - { - "input": "data:text/html,test#test", - "base": "http://example.org/foo/bar", - "href": "data:text/html,test#test", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "text/html,test", - "search": "", - "hash": "#test" - }, - { - "input": "tel:1234567890", - "base": "http://example.org/foo/bar", - "href": "tel:1234567890", - "origin": "null", - "protocol": "tel:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "1234567890", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/file.html", - { - "input": "file:c:\\foo\\bar.html", - "base": "file:///tmp/mock/path", - "href": "file:///c:/foo/bar.html", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:/foo/bar.html", - "search": "", - "hash": "" - }, - { - "input": " File:c|////foo\\bar.html", - "base": "file:///tmp/mock/path", - "href": "file:///c:////foo/bar.html", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:////foo/bar.html", - "search": "", - "hash": "" - }, - { - "input": "C|/foo/bar", - "base": "file:///tmp/mock/path", - "href": "file:///C:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "/C|\\foo\\bar", - "base": "file:///tmp/mock/path", - "href": "file:///C:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "//C|/foo/bar", - "base": "file:///tmp/mock/path", - "href": "file:///C:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "//server/file", - "base": "file:///tmp/mock/path", - "href": "file://server/file", - "protocol": "file:", - "username": "", - "password": "", - "host": "server", - "hostname": "server", - "port": "", - "pathname": "/file", - "search": "", - "hash": "" - }, - { - "input": "\\\\server\\file", - "base": "file:///tmp/mock/path", - "href": "file://server/file", - "protocol": "file:", - "username": "", - "password": "", - "host": "server", - "hostname": "server", - "port": "", - "pathname": "/file", - "search": "", - "hash": "" - }, - { - "input": "/\\server/file", - "base": "file:///tmp/mock/path", - "href": "file://server/file", - "protocol": "file:", - "username": "", - "password": "", - "host": "server", - "hostname": "server", - "port": "", - "pathname": "/file", - "search": "", - "hash": "" - }, - { - "input": "file:///foo/bar.txt", - "base": "file:///tmp/mock/path", - "href": "file:///foo/bar.txt", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/foo/bar.txt", - "search": "", - "hash": "" - }, - { - "input": "file:///home/me", - "base": "file:///tmp/mock/path", - "href": "file:///home/me", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/home/me", - "search": "", - "hash": "" - }, - { - "input": "//", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "///", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "///test", - "base": "file:///tmp/mock/path", - "href": "file:///test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "", - "hash": "" - }, - { - "input": "file://test", - "base": "file:///tmp/mock/path", - "href": "file://test/", - "protocol": "file:", - "username": "", - "password": "", - "host": "test", - "hostname": "test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file://localhost", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file://localhost/", - "base": "file:///tmp/mock/path", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file://localhost/test", - "base": "file:///tmp/mock/path", - "href": "file:///test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "", - "hash": "" - }, - { - "input": "test", - "base": "file:///tmp/mock/path", - "href": "file:///tmp/mock/test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/tmp/mock/test", - "search": "", - "hash": "" - }, - { - "input": "file:test", - "base": "file:///tmp/mock/path", - "href": "file:///tmp/mock/test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/tmp/mock/test", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/path.js", - { - "input": "http://example.com/././foo", - "base": "about:blank", - "href": "http://example.com/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/./.foo", - "base": "about:blank", - "href": "http://example.com/.foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/.foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/.", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/./", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/..", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/../", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/..bar", - "base": "about:blank", - "href": "http://example.com/foo/..bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/..bar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/../ton", - "base": "about:blank", - "href": "http://example.com/foo/ton", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/ton", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar/../ton/../../a", - "base": "about:blank", - "href": "http://example.com/a", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/a", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/../../..", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/../../../ton", - "base": "about:blank", - "href": "http://example.com/ton", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/ton", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/%2e", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/%2e%2", - "base": "about:blank", - "href": "http://example.com/foo/%2e%2", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/%2e%2", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/%2e./%2e%2e/.%2e/%2e.bar", - "base": "about:blank", - "href": "http://example.com/%2e.bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%2e.bar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com////../..", - "base": "about:blank", - "href": "http://example.com//", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar//../..", - "base": "about:blank", - "href": "http://example.com/foo/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo/bar//..", - "base": "about:blank", - "href": "http://example.com/foo/bar/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo/bar/", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo", - "base": "about:blank", - "href": "http://example.com/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/%20foo", - "base": "about:blank", - "href": "http://example.com/%20foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%20foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%", - "base": "about:blank", - "href": "http://example.com/foo%", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%2", - "base": "about:blank", - "href": "http://example.com/foo%2", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%2", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%2zbar", - "base": "about:blank", - "href": "http://example.com/foo%2zbar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%2zbar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%2©zbar", - "base": "about:blank", - "href": "http://example.com/foo%2%C3%82%C2%A9zbar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%2%C3%82%C2%A9zbar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%41%7a", - "base": "about:blank", - "href": "http://example.com/foo%41%7a", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%41%7a", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo\t\u0091%91", - "base": "about:blank", - "href": "http://example.com/foo%C2%91%91", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%C2%91%91", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo%00%51", - "base": "about:blank", - "href": "http://example.com/foo%00%51", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foo%00%51", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/(%28:%3A%29)", - "base": "about:blank", - "href": "http://example.com/(%28:%3A%29)", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/(%28:%3A%29)", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/%3A%3a%3C%3c", - "base": "about:blank", - "href": "http://example.com/%3A%3a%3C%3c", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%3A%3a%3C%3c", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/foo\tbar", - "base": "about:blank", - "href": "http://example.com/foobar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/foobar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com\\\\foo\\\\bar", - "base": "about:blank", - "href": "http://example.com//foo//bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "//foo//bar", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", - "base": "about:blank", - "href": "http://example.com/%7Ffp3%3Eju%3Dduvgw%3Dd", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%7Ffp3%3Eju%3Dduvgw%3Dd", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/@asdf%40", - "base": "about:blank", - "href": "http://example.com/@asdf%40", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/@asdf%40", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/你好你好", - "base": "about:blank", - "href": "http://example.com/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%E4%BD%A0%E5%A5%BD%E4%BD%A0%E5%A5%BD", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/‥/foo", - "base": "about:blank", - "href": "http://example.com/%E2%80%A5/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%E2%80%A5/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com//foo", - "base": "about:blank", - "href": "http://example.com/%EF%BB%BF/foo", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%EF%BB%BF/foo", - "search": "", - "hash": "" - }, - { - "input": "http://example.com/‮/foo/‭/bar", - "base": "about:blank", - "href": "http://example.com/%E2%80%AE/foo/%E2%80%AD/bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/%E2%80%AE/foo/%E2%80%AD/bar", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/script-tests/relative.js", - { - "input": "http://www.google.com/foo?bar=baz#", - "base": "about:blank", - "href": "http://www.google.com/foo?bar=baz#", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/foo", - "search": "?bar=baz", - "hash": "" - }, - { - "input": "http://www.google.com/foo?bar=baz# »", - "base": "about:blank", - "href": "http://www.google.com/foo?bar=baz#%20%C2%BB", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/foo", - "search": "?bar=baz", - "hash": "#%20%C2%BB" - }, - { - "input": "data:test# »", - "base": "about:blank", - "href": "data:test#%20%C2%BB", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "test", - "search": "", - "hash": "#%20%C2%BB" - }, - { - "input": "http://www.google.com", - "base": "about:blank", - "href": "http://www.google.com/", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://192.0x00A80001", - "base": "about:blank", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://www/foo%2Ehtml", - "base": "about:blank", - "href": "http://www/foo%2Ehtml", - "origin": "http://www", - "protocol": "http:", - "username": "", - "password": "", - "host": "www", - "hostname": "www", - "port": "", - "pathname": "/foo%2Ehtml", - "search": "", - "hash": "" - }, - { - "input": "http://www/foo/%2E/html", - "base": "about:blank", - "href": "http://www/foo/html", - "origin": "http://www", - "protocol": "http:", - "username": "", - "password": "", - "host": "www", - "hostname": "www", - "port": "", - "pathname": "/foo/html", - "search": "", - "hash": "" - }, - { - "input": "http://user:pass@/", - "base": "about:blank", - "failure": true - }, - { - "input": "http://%25DOMAIN:foobar@foodomain.com/", - "base": "about:blank", - "href": "http://%25DOMAIN:foobar@foodomain.com/", - "origin": "http://foodomain.com", - "protocol": "http:", - "username": "%25DOMAIN", - "password": "foobar", - "host": "foodomain.com", - "hostname": "foodomain.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:\\\\www.google.com\\foo", - "base": "about:blank", - "href": "http://www.google.com/foo", - "origin": "http://www.google.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.google.com", - "hostname": "www.google.com", - "port": "", - "pathname": "/foo", - "search": "", - "hash": "" - }, - { - "input": "http://foo:80/", - "base": "about:blank", - "href": "http://foo/", - "origin": "http://foo", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo:81/", - "base": "about:blank", - "href": "http://foo:81/", - "origin": "http://foo:81", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo:81", - "hostname": "foo", - "port": "81", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "httpa://foo:80/", - "base": "about:blank", - "href": "httpa://foo:80/", - "origin": "null", - "protocol": "httpa:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://foo:-80/", - "base": "about:blank", - "failure": true - }, - { - "input": "https://foo:443/", - "base": "about:blank", - "href": "https://foo/", - "origin": "https://foo", - "protocol": "https:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://foo:80/", - "base": "about:blank", - "href": "https://foo:80/", - "origin": "https://foo:80", - "protocol": "https:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp://foo:21/", - "base": "about:blank", - "href": "ftp://foo/", - "origin": "ftp://foo", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp://foo:80/", - "base": "about:blank", - "href": "ftp://foo:80/", - "origin": "ftp://foo:80", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "gopher://foo:70/", - "base": "about:blank", - "href": "gopher://foo/", - "origin": "gopher://foo", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "gopher://foo:443/", - "base": "about:blank", - "href": "gopher://foo:443/", - "origin": "gopher://foo:443", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "foo:443", - "hostname": "foo", - "port": "443", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:80/", - "base": "about:blank", - "href": "ws://foo/", - "origin": "ws://foo", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:81/", - "base": "about:blank", - "href": "ws://foo:81/", - "origin": "ws://foo:81", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo:81", - "hostname": "foo", - "port": "81", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:443/", - "base": "about:blank", - "href": "ws://foo:443/", - "origin": "ws://foo:443", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo:443", - "hostname": "foo", - "port": "443", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws://foo:815/", - "base": "about:blank", - "href": "ws://foo:815/", - "origin": "ws://foo:815", - "protocol": "ws:", - "username": "", - "password": "", - "host": "foo:815", - "hostname": "foo", - "port": "815", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:80/", - "base": "about:blank", - "href": "wss://foo:80/", - "origin": "wss://foo:80", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo:80", - "hostname": "foo", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:81/", - "base": "about:blank", - "href": "wss://foo:81/", - "origin": "wss://foo:81", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo:81", - "hostname": "foo", - "port": "81", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:443/", - "base": "about:blank", - "href": "wss://foo/", - "origin": "wss://foo", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo", - "hostname": "foo", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss://foo:815/", - "base": "about:blank", - "href": "wss://foo:815/", - "origin": "wss://foo:815", - "protocol": "wss:", - "username": "", - "password": "", - "host": "foo:815", - "hostname": "foo", - "port": "815", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/example.com/", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp:/example.com/", - "base": "about:blank", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:/example.com/", - "base": "about:blank", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:/example.com/", - "base": "about:blank", - "href": "madeupscheme:/example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "file:/example.com/", - "base": "about:blank", - "href": "file:///example.com/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftps:/example.com/", - "base": "about:blank", - "href": "ftps:/example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:/example.com/", - "base": "about:blank", - "href": "gopher://example.com/", - "origin": "gopher://example.com", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws:/example.com/", - "base": "about:blank", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:/example.com/", - "base": "about:blank", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:/example.com/", - "base": "about:blank", - "href": "data:/example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:/example.com/", - "base": "about:blank", - "href": "javascript:/example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:/example.com/", - "base": "about:blank", - "href": "mailto:/example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/example.com/", - "search": "", - "hash": "" - }, - { - "input": "http:example.com/", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ftp:example.com/", - "base": "about:blank", - "href": "ftp://example.com/", - "origin": "ftp://example.com", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https:example.com/", - "base": "about:blank", - "href": "https://example.com/", - "origin": "https://example.com", - "protocol": "https:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "madeupscheme:example.com/", - "base": "about:blank", - "href": "madeupscheme:example.com/", - "origin": "null", - "protocol": "madeupscheme:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "ftps:example.com/", - "base": "about:blank", - "href": "ftps:example.com/", - "origin": "null", - "protocol": "ftps:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "gopher:example.com/", - "base": "about:blank", - "href": "gopher://example.com/", - "origin": "gopher://example.com", - "protocol": "gopher:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ws:example.com/", - "base": "about:blank", - "href": "ws://example.com/", - "origin": "ws://example.com", - "protocol": "ws:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "wss:example.com/", - "base": "about:blank", - "href": "wss://example.com/", - "origin": "wss://example.com", - "protocol": "wss:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:example.com/", - "base": "about:blank", - "href": "data:example.com/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "javascript:example.com/", - "base": "about:blank", - "href": "javascript:example.com/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - { - "input": "mailto:example.com/", - "base": "about:blank", - "href": "mailto:example.com/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "example.com/", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/segments-userinfo-vs-host.html", - { - "input": "http:@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:a:b@www.example.com", - "base": "about:blank", - "href": "http://a:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/a:b@www.example.com", - "base": "about:blank", - "href": "http://a:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://a:b@www.example.com", - "base": "about:blank", - "href": "http://a:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://@pple.com", - "base": "about:blank", - "href": "http://pple.com/", - "origin": "http://pple.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "pple.com", - "hostname": "pple.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http::b@www.example.com", - "base": "about:blank", - "href": "http://:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/:b@www.example.com", - "base": "about:blank", - "href": "http://:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://:b@www.example.com", - "base": "about:blank", - "href": "http://:b@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "b", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/:@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://user@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:/@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "https:@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:a:b@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:/a:b@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://a:b@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http::@/www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:a:@www.example.com", - "base": "about:blank", - "href": "http://a@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:/a:@www.example.com", - "base": "about:blank", - "href": "http://a@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://a:@www.example.com", - "base": "about:blank", - "href": "http://a@www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "a", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://www.@pple.com", - "base": "about:blank", - "href": "http://www.@pple.com/", - "origin": "http://pple.com", - "protocol": "http:", - "username": "www.", - "password": "", - "host": "pple.com", - "hostname": "pple.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http:@:www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http:/@:www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://@:www.example.com", - "base": "about:blank", - "failure": true - }, - { - "input": "http://:@www.example.com", - "base": "about:blank", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# Others", - { - "input": "/", - "base": "http://www.example.com/test", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "/test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": ".", - "base": "http://www.example.com/test", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "http://www.example.com/test", - "href": "http://www.example.com/", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "./test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "../test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "../aaa/test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/aaa/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/aaa/test.txt", - "search": "", - "hash": "" - }, - { - "input": "../../test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/test.txt", - "search": "", - "hash": "" - }, - { - "input": "中/test.txt", - "base": "http://www.example.com/test", - "href": "http://www.example.com/%E4%B8%AD/test.txt", - "origin": "http://www.example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example.com", - "hostname": "www.example.com", - "port": "", - "pathname": "/%E4%B8%AD/test.txt", - "search": "", - "hash": "" - }, - { - "input": "http://www.example2.com", - "base": "http://www.example.com/test", - "href": "http://www.example2.com/", - "origin": "http://www.example2.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example2.com", - "hostname": "www.example2.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "//www.example2.com", - "base": "http://www.example.com/test", - "href": "http://www.example2.com/", - "origin": "http://www.example2.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.example2.com", - "hostname": "www.example2.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:...", - "base": "http://www.example.com/test", - "href": "file:///...", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/...", - "search": "", - "hash": "" - }, - { - "input": "file:..", - "base": "http://www.example.com/test", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:a", - "base": "http://www.example.com/test", - "href": "file:///a", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/a", - "search": "", - "hash": "" - }, - "# Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/url/host.html", - "Basic canonicalization, uppercase should be converted to lowercase", - { - "input": "http://ExAmPlE.CoM", - "base": "http://other.com/", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://example example.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://Goo%20 goo%7C|.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[:]", - "base": "http://other.com/", - "failure": true - }, - "U+3000 is mapped to U+0020 (space) which is disallowed", - { - "input": "http://GOO\u00a0\u3000goo.com", - "base": "http://other.com/", - "failure": true - }, - "Other types of space (no-break, zero-width, zero-width-no-break) are name-prepped away to nothing. U+200B, U+2060, and U+FEFF, are ignored", - { - "input": "http://GOO\u200b\u2060\ufeffgoo.com", - "base": "http://other.com/", - "href": "http://googoo.com/", - "origin": "http://googoo.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "googoo.com", - "hostname": "googoo.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Leading and trailing C0 control or space", - { - "input": "\u0000\u001b\u0004\u0012 http://example.com/\u001f \u000d ", - "base": "about:blank", - "href": "http://example.com/", - "origin": "http://example.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Ideographic full stop (full-width period for Chinese, etc.) should be treated as a dot. U+3002 is mapped to U+002E (dot)", - { - "input": "http://www.foo。bar.com", - "base": "http://other.com/", - "href": "http://www.foo.bar.com/", - "origin": "http://www.foo.bar.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "www.foo.bar.com", - "hostname": "www.foo.bar.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Invalid unicode characters should fail... U+FDD0 is disallowed; %ef%b7%90 is U+FDD0", - { - "input": "http://\ufdd0zyx.com", - "base": "http://other.com/", - "failure": true - }, - "This is the same as previous but escaped", - { - "input": "http://%ef%b7%90zyx.com", - "base": "http://other.com/", - "failure": true - }, - "U+FFFD", - { - "input": "https://\ufffd", - "base": "about:blank", - "failure": true - }, - { - "input": "https://%EF%BF%BD", - "base": "about:blank", - "failure": true - }, - { - "input": "https://x/\ufffd?\ufffd#\ufffd", - "base": "about:blank", - "href": "https://x/%EF%BF%BD?%EF%BF%BD#%EF%BF%BD", - "origin": "https://x", - "protocol": "https:", - "username": "", - "password": "", - "host": "x", - "hostname": "x", - "port": "", - "pathname": "/%EF%BF%BD", - "search": "?%EF%BF%BD", - "hash": "#%EF%BF%BD" - }, - "Test name prepping, fullwidth input should be converted to ASCII and NOT IDN-ized. This is 'Go' in fullwidth UTF-8/UTF-16.", - { - "input": "http://Go.com", - "base": "http://other.com/", - "href": "http://go.com/", - "origin": "http://go.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "go.com", - "hostname": "go.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "URL spec forbids the following. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24257", - { - "input": "http://%41.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://%ef%bc%85%ef%bc%94%ef%bc%91.com", - "base": "http://other.com/", - "failure": true - }, - "...%00 in fullwidth should fail (also as escaped UTF-8 input)", - { - "input": "http://%00.com", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://%ef%bc%85%ef%bc%90%ef%bc%90.com", - "base": "http://other.com/", - "failure": true - }, - "Basic IDN support, UTF-8 and UTF-16 input should be converted to IDN", - { - "input": "http://你好你好", - "base": "http://other.com/", - "href": "http://xn--6qqa088eba/", - "origin": "http://xn--6qqa088eba", - "protocol": "http:", - "username": "", - "password": "", - "host": "xn--6qqa088eba", - "hostname": "xn--6qqa088eba", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://faß.ExAmPlE/", - "base": "about:blank", - "href": "https://xn--fa-hia.example/", - "origin": "https://xn--fa-hia.example", - "protocol": "https:", - "username": "", - "password": "", - "host": "xn--fa-hia.example", - "hostname": "xn--fa-hia.example", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://faß.ExAmPlE/", - "base": "about:blank", - "href": "sc://fa%C3%9F.ExAmPlE/", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "fa%C3%9F.ExAmPlE", - "hostname": "fa%C3%9F.ExAmPlE", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191", - { - "input": "http://%zz%66%a.com", - "base": "http://other.com/", - "failure": true - }, - "If we get an invalid character that has been escaped.", - { - "input": "http://%25", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://hello%00", - "base": "http://other.com/", - "failure": true - }, - "Escaped numbers should be treated like IP addresses if they are.", - { - "input": "http://%30%78%63%30%2e%30%32%35%30.01", - "base": "http://other.com/", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://%30%78%63%30%2e%30%32%35%30.01%2e", - "base": "http://other.com/", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://192.168.0.257", - "base": "http://other.com/", - "failure": true - }, - "Invalid escaping in hosts causes failure", - { - "input": "http://%3g%78%63%30%2e%30%32%35%30%2E.01", - "base": "http://other.com/", - "failure": true - }, - "A space in a host causes failure", - { - "input": "http://192.168.0.1 hello", - "base": "http://other.com/", - "failure": true - }, - { - "input": "https://x x:12", - "base": "about:blank", - "failure": true - }, - "Fullwidth and escaped UTF-8 fullwidth should still be treated as IP", - { - "input": "http://0Xc0.0250.01", - "base": "http://other.com/", - "href": "http://192.168.0.1/", - "origin": "http://192.168.0.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.0.1", - "hostname": "192.168.0.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Domains with empty labels", - { - "input": "http://./", - "base": "about:blank", - "href": "http://./", - "origin": "http://.", - "protocol": "http:", - "username": "", - "password": "", - "host": ".", - "hostname": ".", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://../", - "base": "about:blank", - "href": "http://../", - "origin": "http://..", - "protocol": "http:", - "username": "", - "password": "", - "host": "..", - "hostname": "..", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://0..0x300/", - "base": "about:blank", - "href": "http://0..0x300/", - "origin": "http://0..0x300", - "protocol": "http:", - "username": "", - "password": "", - "host": "0..0x300", - "hostname": "0..0x300", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Broken IPv6", - { - "input": "http://[www.google.com]/", - "base": "about:blank", - "failure": true - }, - { - "input": "http://[google.com]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.2.3.4x]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.2.3.]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.2.]", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://[::1.]", - "base": "http://other.com/", - "failure": true - }, - "Misc Unicode", - { - "input": "http://foo:💩@example.com/bar", - "base": "http://other.com/", - "href": "http://foo:%F0%9F%92%A9@example.com/bar", - "origin": "http://example.com", - "protocol": "http:", - "username": "foo", - "password": "%F0%9F%92%A9", - "host": "example.com", - "hostname": "example.com", - "port": "", - "pathname": "/bar", - "search": "", - "hash": "" - }, - "# resolving a fragment against any scheme succeeds", - { - "input": "#", - "base": "test:test", - "href": "test:test#", - "origin": "null", - "protocol": "test:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "test", - "search": "", - "hash": "" - }, - { - "input": "#x", - "base": "mailto:x@x.com", - "href": "mailto:x@x.com#x", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "x@x.com", - "search": "", - "hash": "#x" - }, - { - "input": "#x", - "base": "data:,", - "href": "data:,#x", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": ",", - "search": "", - "hash": "#x" - }, - { - "input": "#x", - "base": "about:blank", - "href": "about:blank#x", - "origin": "null", - "protocol": "about:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "blank", - "search": "", - "hash": "#x" - }, - { - "input": "#", - "base": "test:test?test", - "href": "test:test?test#", - "origin": "null", - "protocol": "test:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "test", - "search": "?test", - "hash": "" - }, - "# multiple @ in authority state", - { - "input": "https://@test@test@example:800/", - "base": "http://doesnotmatter/", - "href": "https://%40test%40test@example:800/", - "origin": "https://example:800", - "protocol": "https:", - "username": "%40test%40test", - "password": "", - "host": "example:800", - "hostname": "example", - "port": "800", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://@@@example", - "base": "http://doesnotmatter/", - "href": "https://%40%40@example/", - "origin": "https://example", - "protocol": "https:", - "username": "%40%40", - "password": "", - "host": "example", - "hostname": "example", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "non-az-09 characters", - { - "input": "http://`{}:`{}@h/`{}?`{}", - "base": "http://doesnotmatter/", - "href": "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}", - "origin": "http://h", - "protocol": "http:", - "username": "%60%7B%7D", - "password": "%60%7B%7D", - "host": "h", - "hostname": "h", - "port": "", - "pathname": "/%60%7B%7D", - "search": "?`{}", - "hash": "" - }, - "byte is ' and url is special", - { - "input": "http://host/?'", - "base": "about:blank", - "href": "http://host/?%27", - "origin": "http://host", - "protocol": "http:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/", - "search": "?%27", - "hash": "" - }, - { - "input": "notspecial://host/?'", - "base": "about:blank", - "href": "notspecial://host/?'", - "origin": "null", - "protocol": "notspecial:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/", - "search": "?'", - "hash": "" - }, - "# Credentials in base", - { - "input": "/some/path", - "base": "http://user@example.org/smth", - "href": "http://user@example.org/some/path", - "origin": "http://example.org", - "protocol": "http:", - "username": "user", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/some/path", - "search": "", - "hash": "" - }, - { - "input": "", - "base": "http://user:pass@example.org:21/smth", - "href": "http://user:pass@example.org:21/smth", - "origin": "http://example.org:21", - "protocol": "http:", - "username": "user", - "password": "pass", - "host": "example.org:21", - "hostname": "example.org", - "port": "21", - "pathname": "/smth", - "search": "", - "hash": "" - }, - { - "input": "/some/path", - "base": "http://user:pass@example.org:21/smth", - "href": "http://user:pass@example.org:21/some/path", - "origin": "http://example.org:21", - "protocol": "http:", - "username": "user", - "password": "pass", - "host": "example.org:21", - "hostname": "example.org", - "port": "21", - "pathname": "/some/path", - "search": "", - "hash": "" - }, - "# a set of tests designed by zcorpan for relative URLs with unknown schemes", - { - "input": "i", - "base": "sc:sd", - "failure": true - }, - { - "input": "i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "i", - "base": "sc:/pa/pa", - "href": "sc:/pa/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/i", - "search": "", - "hash": "" - }, - { - "input": "i", - "base": "sc://ho/pa", - "href": "sc://ho/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "i", - "base": "sc:///pa/pa", - "href": "sc:///pa/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/i", - "search": "", - "hash": "" - }, - { - "input": "../i", - "base": "sc:sd", - "failure": true - }, - { - "input": "../i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "../i", - "base": "sc:/pa/pa", - "href": "sc:/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "../i", - "base": "sc://ho/pa", - "href": "sc://ho/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "../i", - "base": "sc:///pa/pa", - "href": "sc:///i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "/i", - "base": "sc:sd", - "failure": true - }, - { - "input": "/i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "/i", - "base": "sc:/pa/pa", - "href": "sc:/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "/i", - "base": "sc://ho/pa", - "href": "sc://ho/i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "/i", - "base": "sc:///pa/pa", - "href": "sc:///i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/i", - "search": "", - "hash": "" - }, - { - "input": "?i", - "base": "sc:sd", - "failure": true - }, - { - "input": "?i", - "base": "sc:sd/sd", - "failure": true - }, - { - "input": "?i", - "base": "sc:/pa/pa", - "href": "sc:/pa/pa?i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "?i", - "hash": "" - }, - { - "input": "?i", - "base": "sc://ho/pa", - "href": "sc://ho/pa?i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/pa", - "search": "?i", - "hash": "" - }, - { - "input": "?i", - "base": "sc:///pa/pa", - "href": "sc:///pa/pa?i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "?i", - "hash": "" - }, - { - "input": "#i", - "base": "sc:sd", - "href": "sc:sd#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "sd", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc:sd/sd", - "href": "sc:sd/sd#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "sd/sd", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc:/pa/pa", - "href": "sc:/pa/pa#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc://ho/pa", - "href": "sc://ho/pa#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "ho", - "hostname": "ho", - "port": "", - "pathname": "/pa", - "search": "", - "hash": "#i" - }, - { - "input": "#i", - "base": "sc:///pa/pa", - "href": "sc:///pa/pa#i", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pa/pa", - "search": "", - "hash": "#i" - }, - "# make sure that relative URL logic works on known typically non-relative schemes too", - { - "input": "about:/../", - "base": "about:blank", - "href": "about:/", - "origin": "null", - "protocol": "about:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "data:/../", - "base": "about:blank", - "href": "data:/", - "origin": "null", - "protocol": "data:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "javascript:/../", - "base": "about:blank", - "href": "javascript:/", - "origin": "null", - "protocol": "javascript:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "mailto:/../", - "base": "about:blank", - "href": "mailto:/", - "origin": "null", - "protocol": "mailto:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# unknown schemes and their hosts", - { - "input": "sc://ñ.test/", - "base": "about:blank", - "href": "sc://%C3%B1.test/", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1.test", - "hostname": "%C3%B1.test", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://\u001F!\"$&'()*+,-.;<=>^_`{|}~/", - "base": "about:blank", - "href": "sc://%1F!\"$&'()*+,-.;<=>^_`{|}~/", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%1F!\"$&'()*+,-.;<=>^_`{|}~", - "hostname": "%1F!\"$&'()*+,-.;<=>^_`{|}~", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://\u0000/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc:// /", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://%/", - "base": "about:blank", - "href": "sc://%/", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%", - "hostname": "%", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "sc://@/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://te@s:t@/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://:/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://:12/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://[/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://\\/", - "base": "about:blank", - "failure": true - }, - { - "input": "sc://]/", - "base": "about:blank", - "failure": true - }, - { - "input": "x", - "base": "sc://ñ", - "href": "sc://%C3%B1/x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "/x", - "search": "", - "hash": "" - }, - "# unknown schemes and backslashes", - { - "input": "sc:\\../", - "base": "about:blank", - "href": "sc:\\../", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "\\../", - "search": "", - "hash": "" - }, - "# unknown scheme with path looking like a password", - { - "input": "sc::a@example.net", - "base": "about:blank", - "href": "sc::a@example.net", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": ":a@example.net", - "search": "", - "hash": "" - }, - "# unknown scheme with bogus percent-encoding", - { - "input": "wow:%NBD", - "base": "about:blank", - "href": "wow:%NBD", - "origin": "null", - "protocol": "wow:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "%NBD", - "search": "", - "hash": "" - }, - { - "input": "wow:%1G", - "base": "about:blank", - "href": "wow:%1G", - "origin": "null", - "protocol": "wow:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "%1G", - "search": "", - "hash": "" - }, - "# Hosts and percent-encoding", - { - "input": "ftp://example.com%80/", - "base": "about:blank", - "failure": true - }, - { - "input": "ftp://example.com%A0/", - "base": "about:blank", - "failure": true - }, - { - "input": "https://example.com%80/", - "base": "about:blank", - "failure": true - }, - { - "input": "https://example.com%A0/", - "base": "about:blank", - "failure": true - }, - { - "input": "ftp://%e2%98%83", - "base": "about:blank", - "href": "ftp://xn--n3h/", - "origin": "ftp://xn--n3h", - "protocol": "ftp:", - "username": "", - "password": "", - "host": "xn--n3h", - "hostname": "xn--n3h", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://%e2%98%83", - "base": "about:blank", - "href": "https://xn--n3h/", - "origin": "https://xn--n3h", - "protocol": "https:", - "username": "", - "password": "", - "host": "xn--n3h", - "hostname": "xn--n3h", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# tests from jsdom/whatwg-url designed for code coverage", - { - "input": "http://127.0.0.1:10100/relative_import.html", - "base": "about:blank", - "href": "http://127.0.0.1:10100/relative_import.html", - "origin": "http://127.0.0.1:10100", - "protocol": "http:", - "username": "", - "password": "", - "host": "127.0.0.1:10100", - "hostname": "127.0.0.1", - "port": "10100", - "pathname": "/relative_import.html", - "search": "", - "hash": "" - }, - { - "input": "http://facebook.com/?foo=%7B%22abc%22", - "base": "about:blank", - "href": "http://facebook.com/?foo=%7B%22abc%22", - "origin": "http://facebook.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "facebook.com", - "hostname": "facebook.com", - "port": "", - "pathname": "/", - "search": "?foo=%7B%22abc%22", - "hash": "" - }, - { - "input": "https://localhost:3000/jqueryui@1.2.3", - "base": "about:blank", - "href": "https://localhost:3000/jqueryui@1.2.3", - "origin": "https://localhost:3000", - "protocol": "https:", - "username": "", - "password": "", - "host": "localhost:3000", - "hostname": "localhost", - "port": "3000", - "pathname": "/jqueryui@1.2.3", - "search": "", - "hash": "" - }, - "# tab/LF/CR", - { - "input": "h\tt\nt\rp://h\to\ns\rt:9\t0\n0\r0/p\ta\nt\rh?q\tu\ne\rry#f\tr\na\rg", - "base": "about:blank", - "href": "http://host:9000/path?query#frag", - "origin": "http://host:9000", - "protocol": "http:", - "username": "", - "password": "", - "host": "host:9000", - "hostname": "host", - "port": "9000", - "pathname": "/path", - "search": "?query", - "hash": "#frag" - }, - "# Stringification of URL.searchParams", - { - "input": "?a=b&c=d", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar?a=b&c=d", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "?a=b&c=d", - "searchParams": "a=b&c=d", - "hash": "" - }, - { - "input": "??a=b&c=d", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar??a=b&c=d", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "??a=b&c=d", - "searchParams": "%3Fa=b&c=d", - "hash": "" - }, - "# Scheme only", - { - "input": "http:", - "base": "http://example.org/foo/bar", - "href": "http://example.org/foo/bar", - "origin": "http://example.org", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/foo/bar", - "search": "", - "searchParams": "", - "hash": "" - }, - { - "input": "http:", - "base": "https://example.org/foo/bar", - "failure": true - }, - { - "input": "sc:", - "base": "https://example.org/foo/bar", - "href": "sc:", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "searchParams": "", - "hash": "" - }, - "# Percent encoding of fragments", - { - "input": "http://foo.bar/baz?qux#foo\bbar", - "base": "about:blank", - "href": "http://foo.bar/baz?qux#foo%08bar", - "origin": "http://foo.bar", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.bar", - "hostname": "foo.bar", - "port": "", - "pathname": "/baz", - "search": "?qux", - "searchParams": "qux=", - "hash": "#foo%08bar" - }, - { - "input": "http://foo.bar/baz?qux#foo\"bar", - "base": "about:blank", - "href": "http://foo.bar/baz?qux#foo%22bar", - "origin": "http://foo.bar", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.bar", - "hostname": "foo.bar", - "port": "", - "pathname": "/baz", - "search": "?qux", - "searchParams": "qux=", - "hash": "#foo%22bar" - }, - { - "input": "http://foo.bar/baz?qux#foobar", - "base": "about:blank", - "href": "http://foo.bar/baz?qux#foo%3Ebar", - "origin": "http://foo.bar", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.bar", - "hostname": "foo.bar", - "port": "", - "pathname": "/baz", - "search": "?qux", - "searchParams": "qux=", - "hash": "#foo%3Ebar" - }, - { - "input": "http://foo.bar/baz?qux#foo`bar", - "base": "about:blank", - "href": "http://foo.bar/baz?qux#foo%60bar", - "origin": "http://foo.bar", - "protocol": "http:", - "username": "", - "password": "", - "host": "foo.bar", - "hostname": "foo.bar", - "port": "", - "pathname": "/baz", - "search": "?qux", - "searchParams": "qux=", - "hash": "#foo%60bar" - }, - "# IPv4 parsing (via https://github.com/nodejs/node/pull/10317)", - { - "input": "http://192.168.257", - "base": "http://other.com/", - "href": "http://192.168.1.1/", - "origin": "http://192.168.1.1", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.1.1", - "hostname": "192.168.1.1", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://192.168.257.com", - "base": "http://other.com/", - "href": "http://192.168.257.com/", - "origin": "http://192.168.257.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "192.168.257.com", - "hostname": "192.168.257.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://256", - "base": "http://other.com/", - "href": "http://0.0.1.0/", - "origin": "http://0.0.1.0", - "protocol": "http:", - "username": "", - "password": "", - "host": "0.0.1.0", - "hostname": "0.0.1.0", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://256.com", - "base": "http://other.com/", - "href": "http://256.com/", - "origin": "http://256.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "256.com", - "hostname": "256.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://999999999", - "base": "http://other.com/", - "href": "http://59.154.201.255/", - "origin": "http://59.154.201.255", - "protocol": "http:", - "username": "", - "password": "", - "host": "59.154.201.255", - "hostname": "59.154.201.255", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://999999999.com", - "base": "http://other.com/", - "href": "http://999999999.com/", - "origin": "http://999999999.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "999999999.com", - "hostname": "999999999.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://10000000000", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://10000000000.com", - "base": "http://other.com/", - "href": "http://10000000000.com/", - "origin": "http://10000000000.com", - "protocol": "http:", - "username": "", - "password": "", - "host": "10000000000.com", - "hostname": "10000000000.com", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://4294967295", - "base": "http://other.com/", - "href": "http://255.255.255.255/", - "origin": "http://255.255.255.255", - "protocol": "http:", - "username": "", - "password": "", - "host": "255.255.255.255", - "hostname": "255.255.255.255", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://4294967296", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://0xffffffff", - "base": "http://other.com/", - "href": "http://255.255.255.255/", - "origin": "http://255.255.255.255", - "protocol": "http:", - "username": "", - "password": "", - "host": "255.255.255.255", - "hostname": "255.255.255.255", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://0xffffffff1", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://256.256.256.256", - "base": "http://other.com/", - "failure": true - }, - { - "input": "http://256.256.256.256.256", - "base": "http://other.com/", - "href": "http://256.256.256.256.256/", - "origin": "http://256.256.256.256.256", - "protocol": "http:", - "username": "", - "password": "", - "host": "256.256.256.256.256", - "hostname": "256.256.256.256.256", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "https://0x.0x.0", - "base": "about:blank", - "href": "https://0.0.0.0/", - "origin": "https://0.0.0.0", - "protocol": "https:", - "username": "", - "password": "", - "host": "0.0.0.0", - "hostname": "0.0.0.0", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "More IPv4 parsing (via https://github.com/jsdom/whatwg-url/issues/92)", - { - "input": "https://0x100000000/test", - "base": "about:blank", - "failure": true - }, - { - "input": "https://256.0.0.1/test", - "base": "about:blank", - "failure": true - }, - "# file URLs containing percent-encoded Windows drive letters (shouldn't work)", - { - "input": "file:///C%3A/", - "base": "about:blank", - "href": "file:///C%3A/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C%3A/", - "search": "", - "hash": "" - }, - { - "input": "file:///C%7C/", - "base": "about:blank", - "href": "file:///C%7C/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C%7C/", - "search": "", - "hash": "" - }, - "# file URLs relative to other file URLs (via https://github.com/jsdom/whatwg-url/pull/60)", - { - "input": "pix/submit.gif", - "base": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/anchor.html", - "href": "file:///C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/Users/Domenic/Dropbox/GitHub/tmpvar/jsdom/test/level2/html/files/pix/submit.gif", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///C:/", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# More file URL tests by zcorpan and annevk", - { - "input": "/", - "base": "file:///C:/a/b", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "//d:", - "base": "file:///C:/a/b", - "href": "file:///d:", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/d:", - "search": "", - "hash": "" - }, - { - "input": "//d:/..", - "base": "file:///C:/a/b", - "href": "file:///d:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/d:/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///ab:/", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "..", - "base": "file:///1:/", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "", - "base": "file:///test?test#test", - "href": "file:///test?test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "" - }, - { - "input": "file:", - "base": "file:///test?test#test", - "href": "file:///test?test", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "" - }, - { - "input": "?x", - "base": "file:///test?test#test", - "href": "file:///test?x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?x", - "hash": "" - }, - { - "input": "file:?x", - "base": "file:///test?test#test", - "href": "file:///test?x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?x", - "hash": "" - }, - { - "input": "#x", - "base": "file:///test?test#test", - "href": "file:///test?test#x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "#x" - }, - { - "input": "file:#x", - "base": "file:///test?test#test", - "href": "file:///test?test#x", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test", - "search": "?test", - "hash": "#x" - }, - "# File URLs and many (back)slashes", - { - "input": "file:\\\\//", - "base": "about:blank", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:\\\\\\\\", - "base": "about:blank", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:\\\\\\\\?fox", - "base": "about:blank", - "href": "file:///?fox", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "?fox", - "hash": "" - }, - { - "input": "file:\\\\\\\\#guppy", - "base": "about:blank", - "href": "file:///#guppy", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "#guppy" - }, - { - "input": "file://spider///", - "base": "about:blank", - "href": "file://spider/", - "protocol": "file:", - "username": "", - "password": "", - "host": "spider", - "hostname": "spider", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:\\\\localhost//", - "base": "about:blank", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:///localhost//cat", - "base": "about:blank", - "href": "file:///localhost//cat", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/localhost//cat", - "search": "", - "hash": "" - }, - { - "input": "file://\\/localhost//cat", - "base": "about:blank", - "href": "file:///localhost//cat", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/localhost//cat", - "search": "", - "hash": "" - }, - { - "input": "file://localhost//a//../..//", - "base": "about:blank", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "/////mouse", - "base": "file:///elephant", - "href": "file:///mouse", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/mouse", - "search": "", - "hash": "" - }, - { - "input": "\\//pig", - "base": "file://lion/", - "href": "file:///pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pig", - "search": "", - "hash": "" - }, - { - "input": "\\/localhost//pig", - "base": "file://lion/", - "href": "file:///pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pig", - "search": "", - "hash": "" - }, - { - "input": "//localhost//pig", - "base": "file://lion/", - "href": "file:///pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/pig", - "search": "", - "hash": "" - }, - { - "input": "/..//localhost//pig", - "base": "file://lion/", - "href": "file://lion/localhost//pig", - "protocol": "file:", - "username": "", - "password": "", - "host": "lion", - "hostname": "lion", - "port": "", - "pathname": "/localhost//pig", - "search": "", - "hash": "" - }, - { - "input": "file://", - "base": "file://ape/", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "# File URLs with non-empty hosts", - { - "input": "/rooibos", - "base": "file://tea/", - "href": "file://tea/rooibos", - "protocol": "file:", - "username": "", - "password": "", - "host": "tea", - "hostname": "tea", - "port": "", - "pathname": "/rooibos", - "search": "", - "hash": "" - }, - { - "input": "/?chai", - "base": "file://tea/", - "href": "file://tea/?chai", - "protocol": "file:", - "username": "", - "password": "", - "host": "tea", - "hostname": "tea", - "port": "", - "pathname": "/", - "search": "?chai", - "hash": "" - }, - "# Windows drive letter handling with the 'file:' base URL", - { - "input": "C|", - "base": "file://host/dir/file", - "href": "file:///C:", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:", - "search": "", - "hash": "" - }, - { - "input": "C|#", - "base": "file://host/dir/file", - "href": "file:///C:#", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:", - "search": "", - "hash": "" - }, - { - "input": "C|?", - "base": "file://host/dir/file", - "href": "file:///C:?", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:", - "search": "", - "hash": "" - }, - { - "input": "C|/", - "base": "file://host/dir/file", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C|\n/", - "base": "file://host/dir/file", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C|\\", - "base": "file://host/dir/file", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "C", - "base": "file://host/dir/file", - "href": "file://host/dir/C", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/dir/C", - "search": "", - "hash": "" - }, - { - "input": "C|a", - "base": "file://host/dir/file", - "href": "file://host/dir/C|a", - "protocol": "file:", - "username": "", - "password": "", - "host": "host", - "hostname": "host", - "port": "", - "pathname": "/dir/C|a", - "search": "", - "hash": "" - }, - "# Windows drive letter quirk in the file slash state", - { - "input": "/c:/foo/bar", - "base": "file:///c:/baz/qux", - "href": "file:///c:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "/c|/foo/bar", - "base": "file:///c:/baz/qux", - "href": "file:///c:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "file:\\c:\\foo\\bar", - "base": "file:///c:/baz/qux", - "href": "file:///c:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "/c:/foo/bar", - "base": "file://host/path", - "href": "file:///c:/foo/bar", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/c:/foo/bar", - "search": "", - "hash": "" - }, - "# Windows drive letter quirk with not empty host", - { - "input": "file://example.net/C:/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "file://1.2.3.4/C:/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "file://[1::8]/C:/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - "# Windows drive letter quirk (no host)", - { - "input": "file:/C|/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - { - "input": "file://C|/", - "base": "about:blank", - "href": "file:///C:/", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/C:/", - "search": "", - "hash": "" - }, - "# file URLs without base URL by Rimas Misevičius", - { - "input": "file:", - "base": "about:blank", - "href": "file:///", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "file:?q=v", - "base": "about:blank", - "href": "file:///?q=v", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "?q=v", - "hash": "" - }, - { - "input": "file:#frag", - "base": "about:blank", - "href": "file:///#frag", - "protocol": "file:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "#frag" - }, - "# IPv6 tests", - { - "input": "http://[1:0::]", - "base": "http://example.net/", - "href": "http://[1::]/", - "origin": "http://[1::]", - "protocol": "http:", - "username": "", - "password": "", - "host": "[1::]", - "hostname": "[1::]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[0:1:2:3:4:5:6:7:8]", - "base": "http://example.net/", - "failure": true - }, - { - "input": "https://[0::0::0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:.0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:0:]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1:2:3:4:5:6:7.0.0.0.1]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1.00.0.0.0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1.290.0.0.0]", - "base": "about:blank", - "failure": true - }, - { - "input": "https://[0:1.23.23]", - "base": "about:blank", - "failure": true - }, - "# Empty host", - { - "input": "http://?", - "base": "about:blank", - "failure": true - }, - { - "input": "http://#", - "base": "about:blank", - "failure": true - }, - "Port overflow (2^32 + 81)", - { - "input": "http://f:4294967377/c", - "base": "http://example.org/", - "failure": true - }, - "Port overflow (2^64 + 81)", - { - "input": "http://f:18446744073709551697/c", - "base": "http://example.org/", - "failure": true - }, - "Port overflow (2^128 + 81)", - { - "input": "http://f:340282366920938463463374607431768211537/c", - "base": "http://example.org/", - "failure": true - }, - "# Non-special-URL path tests", - { - "input": "sc://ñ", - "base": "about:blank", - "href": "sc://%C3%B1", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "sc://ñ?x", - "base": "about:blank", - "href": "sc://%C3%B1?x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "?x", - "hash": "" - }, - { - "input": "sc://ñ#x", - "base": "about:blank", - "href": "sc://%C3%B1#x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "", - "hash": "#x" - }, - { - "input": "#x", - "base": "sc://ñ", - "href": "sc://%C3%B1#x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "", - "hash": "#x" - }, - { - "input": "?x", - "base": "sc://ñ", - "href": "sc://%C3%B1?x", - "origin": "null", - "protocol": "sc:", - "username": "", - "password": "", - "host": "%C3%B1", - "hostname": "%C3%B1", - "port": "", - "pathname": "", - "search": "?x", - "hash": "" - }, - { - "input": "sc://?", - "base": "about:blank", - "href": "sc://?", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "sc://#", - "base": "about:blank", - "href": "sc://#", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "", - "search": "", - "hash": "" - }, - { - "input": "///", - "base": "sc://x/", - "href": "sc:///", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "////", - "base": "sc://x/", - "href": "sc:////", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//", - "search": "", - "hash": "" - }, - { - "input": "////x/", - "base": "sc://x/", - "href": "sc:////x/", - "protocol": "sc:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "//x/", - "search": "", - "hash": "" - }, - { - "input": "tftp://foobar.com/someconfig;mode=netascii", - "base": "about:blank", - "href": "tftp://foobar.com/someconfig;mode=netascii", - "origin": "null", - "protocol": "tftp:", - "username": "", - "password": "", - "host": "foobar.com", - "hostname": "foobar.com", - "port": "", - "pathname": "/someconfig;mode=netascii", - "search": "", - "hash": "" - }, - { - "input": "telnet://user:pass@foobar.com:23/", - "base": "about:blank", - "href": "telnet://user:pass@foobar.com:23/", - "origin": "null", - "protocol": "telnet:", - "username": "user", - "password": "pass", - "host": "foobar.com:23", - "hostname": "foobar.com", - "port": "23", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "ut2004://10.10.10.10:7777/Index.ut2", - "base": "about:blank", - "href": "ut2004://10.10.10.10:7777/Index.ut2", - "origin": "null", - "protocol": "ut2004:", - "username": "", - "password": "", - "host": "10.10.10.10:7777", - "hostname": "10.10.10.10", - "port": "7777", - "pathname": "/Index.ut2", - "search": "", - "hash": "" - }, - { - "input": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", - "base": "about:blank", - "href": "redis://foo:bar@somehost:6379/0?baz=bam&qux=baz", - "origin": "null", - "protocol": "redis:", - "username": "foo", - "password": "bar", - "host": "somehost:6379", - "hostname": "somehost", - "port": "6379", - "pathname": "/0", - "search": "?baz=bam&qux=baz", - "hash": "" - }, - { - "input": "rsync://foo@host:911/sup", - "base": "about:blank", - "href": "rsync://foo@host:911/sup", - "origin": "null", - "protocol": "rsync:", - "username": "foo", - "password": "", - "host": "host:911", - "hostname": "host", - "port": "911", - "pathname": "/sup", - "search": "", - "hash": "" - }, - { - "input": "git://github.com/foo/bar.git", - "base": "about:blank", - "href": "git://github.com/foo/bar.git", - "origin": "null", - "protocol": "git:", - "username": "", - "password": "", - "host": "github.com", - "hostname": "github.com", - "port": "", - "pathname": "/foo/bar.git", - "search": "", - "hash": "" - }, - { - "input": "irc://myserver.com:6999/channel?passwd", - "base": "about:blank", - "href": "irc://myserver.com:6999/channel?passwd", - "origin": "null", - "protocol": "irc:", - "username": "", - "password": "", - "host": "myserver.com:6999", - "hostname": "myserver.com", - "port": "6999", - "pathname": "/channel", - "search": "?passwd", - "hash": "" - }, - { - "input": "dns://fw.example.org:9999/foo.bar.org?type=TXT", - "base": "about:blank", - "href": "dns://fw.example.org:9999/foo.bar.org?type=TXT", - "origin": "null", - "protocol": "dns:", - "username": "", - "password": "", - "host": "fw.example.org:9999", - "hostname": "fw.example.org", - "port": "9999", - "pathname": "/foo.bar.org", - "search": "?type=TXT", - "hash": "" - }, - { - "input": "ldap://localhost:389/ou=People,o=JNDITutorial", - "base": "about:blank", - "href": "ldap://localhost:389/ou=People,o=JNDITutorial", - "origin": "null", - "protocol": "ldap:", - "username": "", - "password": "", - "host": "localhost:389", - "hostname": "localhost", - "port": "389", - "pathname": "/ou=People,o=JNDITutorial", - "search": "", - "hash": "" - }, - { - "input": "git+https://github.com/foo/bar", - "base": "about:blank", - "href": "git+https://github.com/foo/bar", - "origin": "null", - "protocol": "git+https:", - "username": "", - "password": "", - "host": "github.com", - "hostname": "github.com", - "port": "", - "pathname": "/foo/bar", - "search": "", - "hash": "" - }, - { - "input": "urn:ietf:rfc:2648", - "base": "about:blank", - "href": "urn:ietf:rfc:2648", - "origin": "null", - "protocol": "urn:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "ietf:rfc:2648", - "search": "", - "hash": "" - }, - { - "input": "tag:joe@example.org,2001:foo/bar", - "base": "about:blank", - "href": "tag:joe@example.org,2001:foo/bar", - "origin": "null", - "protocol": "tag:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "joe@example.org,2001:foo/bar", - "search": "", - "hash": "" - }, - "# percent encoded hosts in non-special-URLs", - { - "input": "non-special://%E2%80%A0/", - "base": "about:blank", - "href": "non-special://%E2%80%A0/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "%E2%80%A0", - "hostname": "%E2%80%A0", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://H%4fSt/path", - "base": "about:blank", - "href": "non-special://H%4fSt/path", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "H%4fSt", - "hostname": "H%4fSt", - "port": "", - "pathname": "/path", - "search": "", - "hash": "" - }, - "# IPv6 in non-special-URLs", - { - "input": "non-special://[1:2:0:0:5:0:0:0]/", - "base": "about:blank", - "href": "non-special://[1:2:0:0:5::]/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "[1:2:0:0:5::]", - "hostname": "[1:2:0:0:5::]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://[1:2:0:0:0:0:0:3]/", - "base": "about:blank", - "href": "non-special://[1:2::3]/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "[1:2::3]", - "hostname": "[1:2::3]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://[1:2::3]:80/", - "base": "about:blank", - "href": "non-special://[1:2::3]:80/", - "protocol": "non-special:", - "username": "", - "password": "", - "host": "[1:2::3]:80", - "hostname": "[1:2::3]", - "port": "80", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "non-special://[:80/", - "base": "about:blank", - "failure": true - }, - { - "input": "blob:https://example.com:443/", - "base": "about:blank", - "href": "blob:https://example.com:443/", - "protocol": "blob:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "https://example.com:443/", - "search": "", - "hash": "" - }, - { - "input": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", - "base": "about:blank", - "href": "blob:d3958f5c-0777-0845-9dcf-2cb28783acaf", - "protocol": "blob:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "d3958f5c-0777-0845-9dcf-2cb28783acaf", - "search": "", - "hash": "" - }, - "Invalid IPv4 radix digits", - { - "input": "http://0177.0.0.0189", - "base": "about:blank", - "href": "http://0177.0.0.0189/", - "protocol": "http:", - "username": "", - "password": "", - "host": "0177.0.0.0189", - "hostname": "0177.0.0.0189", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://0x7f.0.0.0x7g", - "base": "about:blank", - "href": "http://0x7f.0.0.0x7g/", - "protocol": "http:", - "username": "", - "password": "", - "host": "0x7f.0.0.0x7g", - "hostname": "0x7f.0.0.0x7g", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://0X7F.0.0.0X7G", - "base": "about:blank", - "href": "http://0x7f.0.0.0x7g/", - "protocol": "http:", - "username": "", - "password": "", - "host": "0x7f.0.0.0x7g", - "hostname": "0x7f.0.0.0x7g", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Invalid IPv4 portion of IPv6 address", - { - "input": "http://[::127.0.0.0.1]", - "base": "about:blank", - "failure": true - }, - "Uncompressed IPv6 addresses with 0", - { - "input": "http://[0:1:0:1:0:1:0:1]", - "base": "about:blank", - "href": "http://[0:1:0:1:0:1:0:1]/", - "protocol": "http:", - "username": "", - "password": "", - "host": "[0:1:0:1:0:1:0:1]", - "hostname": "[0:1:0:1:0:1:0:1]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - { - "input": "http://[1:0:1:0:1:0:1:0]", - "base": "about:blank", - "href": "http://[1:0:1:0:1:0:1:0]/", - "protocol": "http:", - "username": "", - "password": "", - "host": "[1:0:1:0:1:0:1:0]", - "hostname": "[1:0:1:0:1:0:1:0]", - "port": "", - "pathname": "/", - "search": "", - "hash": "" - }, - "Percent-encoded query and fragment", - { - "input": "http://example.org/test?\u0022", - "base": "about:blank", - "href": "http://example.org/test?%22", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%22", - "hash": "" - }, - { - "input": "http://example.org/test?\u0023", - "base": "about:blank", - "href": "http://example.org/test?#", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "", - "hash": "" - }, - { - "input": "http://example.org/test?\u003C", - "base": "about:blank", - "href": "http://example.org/test?%3C", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%3C", - "hash": "" - }, - { - "input": "http://example.org/test?\u003E", - "base": "about:blank", - "href": "http://example.org/test?%3E", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%3E", - "hash": "" - }, - { - "input": "http://example.org/test?\u2323", - "base": "about:blank", - "href": "http://example.org/test?%E2%8C%A3", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%E2%8C%A3", - "hash": "" - }, - { - "input": "http://example.org/test?%23%23", - "base": "about:blank", - "href": "http://example.org/test?%23%23", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%23%23", - "hash": "" - }, - { - "input": "http://example.org/test?%GH", - "base": "about:blank", - "href": "http://example.org/test?%GH", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?%GH", - "hash": "" - }, - { - "input": "http://example.org/test?a#%EF", - "base": "about:blank", - "href": "http://example.org/test?a#%EF", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?a", - "hash": "#%EF" - }, - { - "input": "http://example.org/test?a#%GH", - "base": "about:blank", - "href": "http://example.org/test?a#%GH", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?a", - "hash": "#%GH" - }, - "URLs that require a non-about:blank base. (Also serve as invalid base tests.)", - { - "input": "a", - "base": "about:blank", - "failure": true - }, - { - "input": "a/", - "base": "about:blank", - "failure": true - }, - { - "input": "a//", - "base": "about:blank", - "failure": true - }, - "Bases that don't fail to parse but fail to be bases", - { - "input": "test-a-colon.html", - "base": "a:", - "failure": true - }, - { - "input": "test-a-colon-b.html", - "base": "a:b", - "failure": true - }, - "Other base URL tests, that must succeed", - { - "input": "test-a-colon-slash.html", - "base": "a:/", - "href": "a:/test-a-colon-slash.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test-a-colon-slash.html", - "search": "", - "hash": "" - }, - { - "input": "test-a-colon-slash-slash.html", - "base": "a://", - "href": "a:///test-a-colon-slash-slash.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test-a-colon-slash-slash.html", - "search": "", - "hash": "" - }, - { - "input": "test-a-colon-slash-b.html", - "base": "a:/b", - "href": "a:/test-a-colon-slash-b.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "", - "hostname": "", - "port": "", - "pathname": "/test-a-colon-slash-b.html", - "search": "", - "hash": "" - }, - { - "input": "test-a-colon-slash-slash-b.html", - "base": "a://b", - "href": "a://b/test-a-colon-slash-slash-b.html", - "protocol": "a:", - "username": "", - "password": "", - "host": "b", - "hostname": "b", - "port": "", - "pathname": "/test-a-colon-slash-slash-b.html", - "search": "", - "hash": "" - }, - "Null code point in fragment", - { - "input": "http://example.org/test?a#b\u0000c", - "base": "about:blank", - "href": "http://example.org/test?a#bc", - "protocol": "http:", - "username": "", - "password": "", - "host": "example.org", - "hostname": "example.org", - "port": "", - "pathname": "/test", - "search": "?a", - "hash": "#bc" - } -] diff --git a/test/fixtures/url-toascii.js b/test/fixtures/url-toascii.js deleted file mode 100644 index 59b76330f867f2..00000000000000 --- a/test/fixtures/url-toascii.js +++ /dev/null @@ -1,157 +0,0 @@ -'use strict'; - -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/4839a0a804/url/toascii.json - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -module.exports = -[ - "This resource is focused on highlighting issues with UTS #46 ToASCII", - { - "comment": "Label with hyphens in 3rd and 4th position", - "input": "aa--", - "output": "aa--" - }, - { - "input": "a†--", - "output": "xn--a---kp0a" - }, - { - "input": "ab--c", - "output": "ab--c" - }, - { - "comment": "Label with leading hyphen", - "input": "-x", - "output": "-x" - }, - { - "input": "-†", - "output": "xn----xhn" - }, - { - "input": "-x.xn--nxa", - "output": "-x.xn--nxa" - }, - { - "input": "-x.β", - "output": "-x.xn--nxa" - }, - { - "comment": "Label with trailing hyphen", - "input": "x-.xn--nxa", - "output": "x-.xn--nxa" - }, - { - "input": "x-.β", - "output": "x-.xn--nxa" - }, - { - "comment": "Empty labels", - "input": "x..xn--nxa", - "output": "x..xn--nxa" - }, - { - "input": "x..β", - "output": "x..xn--nxa" - }, - { - "comment": "Invalid Punycode", - "input": "xn--a", - "output": null - }, - { - "input": "xn--a.xn--nxa", - "output": null - }, - { - "input": "xn--a.β", - "output": null - }, - { - "comment": "Valid Punycode", - "input": "xn--nxa.xn--nxa", - "output": "xn--nxa.xn--nxa" - }, - { - "comment": "Mixed", - "input": "xn--nxa.β", - "output": "xn--nxa.xn--nxa" - }, - { - "input": "ab--c.xn--nxa", - "output": "ab--c.xn--nxa" - }, - { - "input": "ab--c.β", - "output": "ab--c.xn--nxa" - }, - { - "comment": "CheckJoiners is true", - "input": "\u200D.example", - "output": null - }, - { - "input": "xn--1ug.example", - "output": null - }, - { - "comment": "CheckBidi is true", - "input": "يa", - "output": null - }, - { - "input": "xn--a-yoc", - "output": null - }, - { - "comment": "processing_option is Nontransitional_Processing", - "input": "ශ්‍රී", - "output": "xn--10cl1a0b660p" - }, - { - "input": "نامه‌ای", - "output": "xn--mgba3gch31f060k" - }, - { - "comment": "U+FFFD", - "input": "\uFFFD.com", - "output": null - }, - { - "comment": "U+FFFD character encoded in Punycode", - "input": "xn--zn7c.com", - "output": null - }, - { - "comment": "Label longer than 63 code points", - "input": "x01234567890123456789012345678901234567890123456789012345678901x", - "output": "x01234567890123456789012345678901234567890123456789012345678901x" - }, - { - "input": "x01234567890123456789012345678901234567890123456789012345678901†", - "output": "xn--x01234567890123456789012345678901234567890123456789012345678901-6963b" - }, - { - "input": "x01234567890123456789012345678901234567890123456789012345678901x.xn--nxa", - "output": "x01234567890123456789012345678901234567890123456789012345678901x.xn--nxa" - }, - { - "input": "x01234567890123456789012345678901234567890123456789012345678901x.β", - "output": "x01234567890123456789012345678901234567890123456789012345678901x.xn--nxa" - }, - { - "comment": "Domain excluding TLD longer than 253 code points", - "input": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x", - "output": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.x" - }, - { - "input": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--nxa", - "output": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--nxa" - }, - { - "input": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.β", - "output": "01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.01234567890123456789012345678901234567890123456789.0123456789012345678901234567890123456789012345678.xn--nxa" - } -] diff --git a/test/known_issues/test-url-parse-conformance.js b/test/known_issues/test-url-parse-conformance.js index fe3aa718eaf891..7be8c16099df59 100644 --- a/test/known_issues/test-url-parse-conformance.js +++ b/test/known_issues/test-url-parse-conformance.js @@ -5,7 +5,9 @@ require('../common'); const url = require('url'); const assert = require('assert'); const fixtures = require('../common/fixtures'); -const tests = require(fixtures.path('url-tests')); +const tests = require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') +); let failed = 0; let attempted = 0; diff --git a/test/parallel/test-http2-compat-serverrequest-pipe.js b/test/parallel/test-http2-compat-serverrequest-pipe.js index 53e54cdf913b0e..f5889073060b44 100644 --- a/test/parallel/test-http2-compat-serverrequest-pipe.js +++ b/test/parallel/test-http2-compat-serverrequest-pipe.js @@ -13,7 +13,7 @@ const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const loc = fixtures.path('url-tests.js'); +const loc = fixtures.path('person-large.jpg'); const fn = path.join(tmpdir.path, 'http2-url-tests.js'); const server = http2.createServer(); diff --git a/test/parallel/test-http2-pipe-named-pipe.js b/test/parallel/test-http2-pipe-named-pipe.js index 49fc142961d919..7882f79657f701 100644 --- a/test/parallel/test-http2-pipe-named-pipe.js +++ b/test/parallel/test-http2-pipe-named-pipe.js @@ -14,7 +14,7 @@ const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const loc = fixtures.path('url-tests.js'); +const loc = fixtures.path('person-large.jpg'); const fn = path.join(tmpdir.path, 'http2-url-tests.js'); const server = http2.createServer(); diff --git a/test/parallel/test-http2-pipe.js b/test/parallel/test-http2-pipe.js index d7dd99df91edb5..2e564d3e329dbc 100644 --- a/test/parallel/test-http2-pipe.js +++ b/test/parallel/test-http2-pipe.js @@ -13,7 +13,7 @@ const path = require('path'); const tmpdir = require('../common/tmpdir'); tmpdir.refresh(); -const loc = fixtures.path('url-tests.js'); +const loc = fixtures.path('person-large.jpg'); const fn = path.join(tmpdir.path, 'http2-url-tests.js'); const server = http2.createServer(); diff --git a/test/parallel/test-icu-punycode.js b/test/parallel/test-icu-punycode.js index 3744891ee098de..2501b1d86e7b88 100644 --- a/test/parallel/test-icu-punycode.js +++ b/test/parallel/test-icu-punycode.js @@ -10,7 +10,10 @@ const icu = internalBinding('icu'); const assert = require('assert'); const tests = require('../fixtures/url-idna.js'); -const wptToASCIITests = require('../fixtures/url-toascii.js'); +const fixtures = require('../common/fixtures'); +const wptToASCIITests = require( + fixtures.path('wpt', 'url', 'resources', 'toascii.json') +); { for (const [i, { ascii, unicode }] of tests.entries()) { diff --git a/test/parallel/test-whatwg-url-constructor.js b/test/parallel/test-whatwg-url-constructor.js index 16bcac74cc6bcd..6570e36b0fd94e 100644 --- a/test/parallel/test-whatwg-url-constructor.js +++ b/test/parallel/test-whatwg-url-constructor.js @@ -11,7 +11,9 @@ const { test, assert_equals, assert_true, assert_throws } = require('../common/wpt'); const request = { - response: require(fixtures.path('url-tests')) + response: require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') + ) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-custom-domainto.js b/test/parallel/test-whatwg-url-custom-domainto.js index 556a3ff8410b73..9677d84286ebe4 100644 --- a/test/parallel/test-whatwg-url-custom-domainto.js +++ b/test/parallel/test-whatwg-url-custom-domainto.js @@ -11,7 +11,10 @@ const assert = require('assert'); const { domainToASCII, domainToUnicode } = require('url'); const tests = require('../fixtures/url-idna'); -const wptToASCIITests = require('../fixtures/url-toascii'); +const fixtures = require('../common/fixtures'); +const wptToASCIITests = require( + fixtures.path('wpt', 'url', 'resources', 'toascii.json') +); { const expectedError = common.expectsError( diff --git a/test/parallel/test-whatwg-url-custom-parsing.js b/test/parallel/test-whatwg-url-custom-parsing.js index 252e35c8d3552c..34d9062087eb10 100644 --- a/test/parallel/test-whatwg-url-custom-parsing.js +++ b/test/parallel/test-whatwg-url-custom-parsing.js @@ -12,7 +12,9 @@ const URL = require('url').URL; const assert = require('assert'); const fixtures = require('../common/fixtures'); -const tests = require(fixtures.path('url-tests')); +const tests = require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') +); const originalFailures = tests.filter((test) => test.failure); diff --git a/test/parallel/test-whatwg-url-origin.js b/test/parallel/test-whatwg-url-origin.js index 8a5ad6d3154f8f..0ce19c28218779 100644 --- a/test/parallel/test-whatwg-url-origin.js +++ b/test/parallel/test-whatwg-url-origin.js @@ -10,7 +10,9 @@ const URL = require('url').URL; const { test, assert_equals } = require('../common/wpt'); const request = { - response: require(fixtures.path('url-tests')) + response: require( + fixtures.path('wpt', 'url', 'resources', 'urltestdata.json') + ) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-setters.js b/test/parallel/test-whatwg-url-setters.js index a04b6c93eccf3d..a5d59f761c1a13 100644 --- a/test/parallel/test-whatwg-url-setters.js +++ b/test/parallel/test-whatwg-url-setters.js @@ -11,7 +11,9 @@ const { test, assert_equals } = require('../common/wpt'); const fixtures = require('../common/fixtures'); const request = { - response: require(fixtures.path('url-setter-tests')) + response: require(fixtures.path( + 'wpt', 'url', 'resources', 'setters_tests.json' + )) }; /* The following tests are copied from WPT. Modifications to them should be diff --git a/test/parallel/test-whatwg-url-toascii.js b/test/parallel/test-whatwg-url-toascii.js index c85b092c1d250c..74ce1fe6c2f281 100644 --- a/test/parallel/test-whatwg-url-toascii.js +++ b/test/parallel/test-whatwg-url-toascii.js @@ -10,7 +10,9 @@ const { URL } = require('url'); const { test, assert_equals, assert_throws } = require('../common/wpt'); const request = { - response: require(fixtures.path('url-toascii')) + response: require( + fixtures.path('wpt', 'url', 'resources', 'toascii.json') + ) }; /* The following tests are copied from WPT. Modifications to them should be From b68734b66a6d9db2201b7efed3856552494343fd Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 16 Sep 2018 15:00:40 +0800 Subject: [PATCH 134/249] test: initialize test/wpt to run URL and console .js tests This patch: - Creates a new test suite `wpt` that can be used to run a subset of Web Platform Tests - Adds a `WPTRunner` in `test/common/wpt.js` that can run the WPT subset in `test/fixtures/wpt` with a vm and the WPT harness while taking the status file in `test/wpt/status` into account. Here we use a new format of status file (in JSON) to handle specific requirements (like ICU requirements) in the tests and to handle expected failures and TODOs. - Adds documentation on how the runner and the update automation works - Runs the WHATWG URL tests and the console tests with the new test runner. With this patch we eliminates the need of copy-pasting with manual modifications to update a large chunk of our WPT subset previously maintained in `test/parallel`. Now the tests run in `test/wpt` can be automatically updated with `git node wpt` without modifications by the actual WPT harness instead of our home-grown mock. There are still a few URL tests left that need to be migrated in the upstream to be placed in .js instead of .html - we currently still use the legacy harness mock in the test files. PR-URL: https://github.com/nodejs/node/pull/24035 Refs: https://github.com/nodejs/node/issues/23192 Reviewed-By: Daijiro Wachi --- Makefile | 3 + test/common/README.md | 21 +- test/common/wpt.js | 427 +++++++++++++++++- test/parallel/test-whatwg-url-constructor.js | 2 +- ...est-whatwg-url-custom-searchparams-sort.js | 9 +- .../test-whatwg-url-custom-setters.js | 3 +- test/parallel/test-whatwg-url-origin.js | 2 +- test/parallel/test-whatwg-url-setters.js | 2 +- test/parallel/test-whatwg-url-toascii.js | 2 +- test/wpt/README.md | 171 +++++++ test/wpt/status/console.json | 8 + test/wpt/status/url.json | 15 + test/wpt/test-whatwg-console.js | 13 + test/wpt/test-whatwg-url.js | 19 + test/wpt/testcfg.py | 6 + test/wpt/wpt.status | 21 + 16 files changed, 710 insertions(+), 14 deletions(-) create mode 100644 test/wpt/README.md create mode 100644 test/wpt/status/console.json create mode 100644 test/wpt/status/url.json create mode 100644 test/wpt/test-whatwg-console.js create mode 100644 test/wpt/test-whatwg-url.js create mode 100644 test/wpt/testcfg.py create mode 100644 test/wpt/wpt.status diff --git a/Makefile b/Makefile index cc6fcd888f4cde..e003341f70cf51 100644 --- a/Makefile +++ b/Makefile @@ -496,6 +496,9 @@ test-debug: test-build test-message: test-build $(PYTHON) tools/test.py $(PARALLEL_ARGS) message +test-wpt: all + $(PYTHON) tools/test.py $(PARALLEL_ARGS) wpt + test-simple: | cctest bench-addons-build # Depends on 'all'. $(PYTHON) tools/test.py $(PARALLEL_ARGS) parallel sequential diff --git a/test/common/README.md b/test/common/README.md index f0bcced82e6149..356c8531ec0c38 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -772,12 +772,19 @@ Deletes and recreates the testing temporary directory. ## WPT Module -The wpt.js module is a port of parts of -[W3C testharness.js](https://github.com/w3c/testharness.js) for testing the -Node.js -[WHATWG URL API](https://nodejs.org/api/url.html#url_the_whatwg_url_api) -implementation with tests from -[W3C Web Platform Tests](https://github.com/w3c/web-platform-tests). +### harness + +A legacy port of [Web Platform Tests][] harness. + +See the source code for definitions. Please avoid using it in new +code - the current usage of this port in tests is being migrated to +the original WPT harness, see [the WPT tests README][]. + +### Class: WPTRunner + +A driver class for running WPT with the WPT harness in a vm. + +See [the WPT tests README][] for details. [<Array>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array @@ -792,3 +799,5 @@ implementation with tests from [`hijackstdio.hijackStdErr()`]: #hijackstderrlistener [`hijackstdio.hijackStdOut()`]: #hijackstdoutlistener [internationalization]: https://github.com/nodejs/node/wiki/Intl +[Web Platform Tests]: https://github.com/web-platform-tests/wpt +[the WPT tests README]: ../wpt/README.md diff --git a/test/common/wpt.js b/test/common/wpt.js index 7cd644dc88c097..59dbe26d2abdcb 100644 --- a/test/common/wpt.js +++ b/test/common/wpt.js @@ -2,9 +2,17 @@ 'use strict'; const assert = require('assert'); +const common = require('../common'); +const fixtures = require('../common/fixtures'); +const fs = require('fs'); +const fsPromises = fs.promises; +const path = require('path'); +const vm = require('vm'); // https://github.com/w3c/testharness.js/blob/master/testharness.js -module.exports = { +// TODO: get rid of this half-baked harness in favor of the one +// pulled from WPT +const harnessMock = { test: (fn, desc) => { try { fn(); @@ -28,3 +36,420 @@ module.exports = { assert.fail(`Reached unreachable code: ${desc}`); } }; + +class ResourceLoader { + constructor(path) { + this.path = path; + } + + fetch(url, asPromise = true) { + // We need to patch this to load the WebIDL parser + url = url.replace( + '/resources/WebIDLParser.js', + '/resources/webidl2/lib/webidl2.js' + ); + const file = url.startsWith('/') ? + fixtures.path('wpt', url) : + fixtures.path('wpt', this.path, url); + if (asPromise) { + return fsPromises.readFile(file) + .then((data) => { + return { + ok: true, + json() { return JSON.parse(data.toString()); }, + text() { return data.toString(); } + }; + }); + } else { + return fs.readFileSync(file, 'utf8'); + } + } +} + +class WPTTest { + /** + * @param {string} mod + * @param {string} filename + * @param {string[]} requires + * @param {string | undefined} failReason + * @param {string | undefined} skipReason + */ + constructor(mod, filename, requires, failReason, skipReason) { + this.module = mod; // name of the WPT module, e.g. 'url' + this.filename = filename; // name of the test file + this.requires = requires; + this.failReason = failReason; + this.skipReason = skipReason; + } + + getAbsolutePath() { + return fixtures.path('wpt', this.module, this.filename); + } + + getContent() { + return fs.readFileSync(this.getAbsolutePath(), 'utf8'); + } + + shouldSkip() { + return this.failReason || this.skipReason; + } + + requireIntl() { + return this.requires.includes('intl'); + } +} + +class StatusLoader { + constructor(path) { + this.path = path; + this.loaded = false; + this.status = null; + /** @type {WPTTest[]} */ + this.tests = []; + } + + loadTest(file) { + let requires = []; + let failReason; + let skipReason; + if (this.status[file]) { + requires = this.status[file].requires || []; + failReason = this.status[file].fail; + skipReason = this.status[file].skip; + } + return new WPTTest(this.path, file, requires, + failReason, skipReason); + } + + load() { + const dir = path.join(__dirname, '..', 'wpt'); + const statusFile = path.join(dir, 'status', `${this.path}.json`); + const result = JSON.parse(fs.readFileSync(statusFile, 'utf8')); + this.status = result; + + const list = fs.readdirSync(fixtures.path('wpt', this.path)); + + for (const file of list) { + this.tests.push(this.loadTest(file)); + } + this.loaded = true; + } + + get jsTests() { + return this.tests.filter((test) => test.filename.endsWith('.js')); + } +} + +const PASSED = 1; +const FAILED = 2; +const SKIPPED = 3; + +class WPTRunner { + constructor(path) { + this.path = path; + this.resource = new ResourceLoader(path); + this.sandbox = null; + this.context = null; + + this.globals = new Map(); + + this.status = new StatusLoader(path); + this.status.load(); + this.tests = new Map( + this.status.jsTests.map((item) => [item.filename, item]) + ); + + this.results = new Map(); + this.inProgress = new Set(); + } + + /** + * Specify that certain global descriptors from the object + * should be defined in the vm + * @param {object} obj + * @param {string[]} names + */ + copyGlobalsFromObject(obj, names) { + for (const name of names) { + const desc = Object.getOwnPropertyDescriptor(global, name); + this.globals.set(name, desc); + } + } + + /** + * Specify that certain global descriptors should be defined in the vm + * @param {string} name + * @param {object} descriptor + */ + defineGlobal(name, descriptor) { + this.globals.set(name, descriptor); + } + + // TODO(joyeecheung): work with the upstream to port more tests in .html + // to .js. + runJsTests() { + // TODO(joyeecheung): it's still under discussion whether we should leave + // err.name alone. See https://github.com/nodejs/node/issues/20253 + const internalErrors = require('internal/errors'); + internalErrors.useOriginalName = true; + + let queue = []; + + // If the tests are run as `node test/wpt/test-something.js subset.any.js`, + // only `subset.any.js` will be run by the runner. + if (process.argv[2]) { + const filename = process.argv[2]; + if (!this.tests.has(filename)) { + throw new Error(`${filename} not found!`); + } + queue.push(this.tests.get(filename)); + } else { + queue = this.buildQueue(); + } + + this.inProgress = new Set(queue.map((item) => item.filename)); + + for (const test of queue) { + const filename = test.filename; + const content = test.getContent(); + const meta = test.title = this.getMeta(content); + + const absolutePath = test.getAbsolutePath(); + const context = this.generateContext(test.filename); + const code = this.mergeScripts(meta, content); + try { + vm.runInContext(code, context, { + filename: absolutePath + }); + } catch (err) { + this.fail(filename, { + name: '', + message: err.message, + stack: err.stack + }, 'UNCAUGHT'); + this.inProgress.delete(filename); + } + } + this.tryFinish(); + } + + mock() { + const resource = this.resource; + const result = { + // This is a mock, because at the moment fetch is not implemented + // in Node.js, but some tests and harness depend on this to pull + // resources. + fetch(file) { + return resource.fetch(file); + }, + location: {}, + GLOBAL: { + isWindow() { return false; } + }, + Object + }; + + return result; + } + + // Note: this is how our global space for the WPT test should look like + getSandbox() { + const result = this.mock(); + for (const [name, desc] of this.globals) { + Object.defineProperty(result, name, desc); + } + return result; + } + + generateContext(filename) { + const sandbox = this.sandbox = this.getSandbox(); + const context = this.context = vm.createContext(sandbox); + + const harnessPath = fixtures.path('wpt', 'resources', 'testharness.js'); + const harness = fs.readFileSync(harnessPath, 'utf8'); + vm.runInContext(harness, context, { + filename: harnessPath + }); + + sandbox.add_result_callback( + this.resultCallback.bind(this, filename) + ); + sandbox.add_completion_callback( + this.completionCallback.bind(this, filename) + ); + sandbox.self = sandbox; + // TODO(joyeecheung): we are not a window - work with the upstream to + // add a new scope for us. + sandbox.document = {}; // Pretend we are Window + return context; + } + + resultCallback(filename, test) { + switch (test.status) { + case 1: + this.fail(filename, test, 'FAILURE'); + break; + case 2: + this.fail(filename, test, 'TIMEOUT'); + break; + case 3: + this.fail(filename, test, 'INCOMPLETE'); + break; + default: + this.succeed(filename, test); + } + } + + completionCallback(filename, tests, harnessStatus) { + if (harnessStatus.status === 2) { + assert.fail(`test harness timed out in ${filename}`); + } + this.inProgress.delete(filename); + this.tryFinish(); + } + + tryFinish() { + if (this.inProgress.size > 0) { + return; + } + + this.reportResults(); + } + + reportResults() { + const unexpectedFailures = []; + for (const [filename, items] of this.results) { + const test = this.tests.get(filename); + let title = test.meta && test.meta.title; + title = title ? `${filename} : ${title}` : filename; + console.log(`---- ${title} ----`); + for (const item of items) { + switch (item.type) { + case FAILED: { + if (test.failReason) { + console.log(`[EXPECTED_FAILURE] ${item.test.name}`); + } else { + console.log(`[UNEXPECTED_FAILURE] ${item.test.name}`); + unexpectedFailures.push([title, filename, item]); + } + break; + } + case PASSED: { + console.log(`[PASSED] ${item.test.name}`); + break; + } + case SKIPPED: { + console.log(`[SKIPPED] ${item.reason}`); + break; + } + } + } + } + + if (unexpectedFailures.length > 0) { + for (const [title, filename, item] of unexpectedFailures) { + console.log(`---- ${title} ----`); + console.log(`[${item.reason}] ${item.test.name}`); + console.log(item.test.message); + console.log(item.test.stack); + const command = `${process.execPath} ${process.execArgv}` + + ` ${require.main.filename} ${filename}`; + console.log(`Command: ${command}\n`); + } + assert.fail(`${unexpectedFailures.length} unexpected failures found`); + } + } + + addResult(filename, item) { + const result = this.results.get(filename); + if (result) { + result.push(item); + } else { + this.results.set(filename, [item]); + } + } + + succeed(filename, test) { + this.addResult(filename, { + type: PASSED, + test + }); + } + + fail(filename, test, reason) { + this.addResult(filename, { + type: FAILED, + test, + reason + }); + } + + skip(filename, reason) { + this.addResult(filename, { + type: SKIPPED, + reason + }); + } + + getMeta(code) { + const matches = code.match(/\/\/ META: .+/g); + if (!matches) { + return {}; + } else { + const result = {}; + for (const match of matches) { + const parts = match.match(/\/\/ META: ([^=]+?)=(.+)/); + const key = parts[1]; + const value = parts[2]; + if (key === 'script') { + if (result[key]) { + result[key].push(value); + } else { + result[key] = [value]; + } + } else { + result[key] = value; + } + } + return result; + } + } + + mergeScripts(meta, content) { + if (!meta.script) { + return content; + } + + // only one script + let result = ''; + for (const script of meta.script) { + result += this.resource.fetch(script, false); + } + + return result + content; + } + + buildQueue() { + const queue = []; + for (const test of this.tests.values()) { + const filename = test.filename; + if (test.skipReason) { + this.skip(filename, test.skipReason); + continue; + } + + if (!common.hasIntl && test.requireIntl()) { + this.skip(filename, 'missing Intl'); + continue; + } + + queue.push(test); + } + return queue; + } +} + +module.exports = { + harness: harnessMock, + WPTRunner +}; diff --git a/test/parallel/test-whatwg-url-constructor.js b/test/parallel/test-whatwg-url-constructor.js index 6570e36b0fd94e..282679d7797f2a 100644 --- a/test/parallel/test-whatwg-url-constructor.js +++ b/test/parallel/test-whatwg-url-constructor.js @@ -8,7 +8,7 @@ if (!common.hasIntl) { const fixtures = require('../common/fixtures'); const { URL, URLSearchParams } = require('url'); const { test, assert_equals, assert_true, assert_throws } = - require('../common/wpt'); + require('../common/wpt').harness; const request = { response: require( diff --git a/test/parallel/test-whatwg-url-custom-searchparams-sort.js b/test/parallel/test-whatwg-url-custom-searchparams-sort.js index f8884a7e7092a3..49c3b065f957c6 100644 --- a/test/parallel/test-whatwg-url-custom-searchparams-sort.js +++ b/test/parallel/test-whatwg-url-custom-searchparams-sort.js @@ -4,9 +4,14 @@ require('../common'); const { URL, URLSearchParams } = require('url'); -const { test, assert_array_equals } = require('../common/wpt'); +const { test, assert_array_equals } = require('../common/wpt').harness; -// Test bottom-up iterative stable merge sort +// TODO(joyeecheung): upstream this to WPT, if possible - even +// just as a test for large inputs. Other implementations may +// have a similar cutoff anyway. + +// Test bottom-up iterative stable merge sort because we only use that +// algorithm to sort > 100 search params. const tests = [{ input: '', output: [] }]; const pairs = []; for (let i = 10; i < 100; i++) { diff --git a/test/parallel/test-whatwg-url-custom-setters.js b/test/parallel/test-whatwg-url-custom-setters.js index 99b4361831fd3b..e10ebb9fe66968 100644 --- a/test/parallel/test-whatwg-url-custom-setters.js +++ b/test/parallel/test-whatwg-url-custom-setters.js @@ -10,9 +10,10 @@ if (!common.hasIntl) { const assert = require('assert'); const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); +const { test, assert_equals } = require('../common/wpt').harness; const fixtures = require('../common/fixtures'); +// TODO(joyeecheung): we should submit these to the upstream const additionalTestCases = require(fixtures.path('url-setter-tests-additional.js')); diff --git a/test/parallel/test-whatwg-url-origin.js b/test/parallel/test-whatwg-url-origin.js index 0ce19c28218779..5b1aa14cd07642 100644 --- a/test/parallel/test-whatwg-url-origin.js +++ b/test/parallel/test-whatwg-url-origin.js @@ -7,7 +7,7 @@ if (!common.hasIntl) { const fixtures = require('../common/fixtures'); const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); +const { test, assert_equals } = require('../common/wpt').harness; const request = { response: require( diff --git a/test/parallel/test-whatwg-url-setters.js b/test/parallel/test-whatwg-url-setters.js index a5d59f761c1a13..13422bd77690ed 100644 --- a/test/parallel/test-whatwg-url-setters.js +++ b/test/parallel/test-whatwg-url-setters.js @@ -7,7 +7,7 @@ if (!common.hasIntl) { } const URL = require('url').URL; -const { test, assert_equals } = require('../common/wpt'); +const { test, assert_equals } = require('../common/wpt').harness; const fixtures = require('../common/fixtures'); const request = { diff --git a/test/parallel/test-whatwg-url-toascii.js b/test/parallel/test-whatwg-url-toascii.js index 74ce1fe6c2f281..4869ab3f1d3bd1 100644 --- a/test/parallel/test-whatwg-url-toascii.js +++ b/test/parallel/test-whatwg-url-toascii.js @@ -7,7 +7,7 @@ if (!common.hasIntl) { const fixtures = require('../common/fixtures'); const { URL } = require('url'); -const { test, assert_equals, assert_throws } = require('../common/wpt'); +const { test, assert_equals, assert_throws } = require('../common/wpt').harness; const request = { response: require( diff --git a/test/wpt/README.md b/test/wpt/README.md new file mode 100644 index 00000000000000..1810a98c8dc982 --- /dev/null +++ b/test/wpt/README.md @@ -0,0 +1,171 @@ +# Web Platform Tests + +The tests here are drivers for running the [Web Platform Tests][]. + +See [`test/fixtures/wpt/README.md`][] for a hash of the last +updated WPT commit for each module being covered here. + +See the json files in [the `status` folder](./status) for prerequisites, +expected failures, and support status for specific tests in each module. + +Currently there are still some Web Platform Tests titled `test-whatwg-*` +under `test/parallel` that have not been migrated to be run with the +WPT harness and have automatic updates. There are also a few +`test-whatwg-*-custom-*` tests that may need to be upstreamed. +This folder covers the tests that have been migrated. + + +## How to add tests for a new module + +### 1. Create a status file + +For example, to add the URL tests, add a `test/wpt/status/url.json` file. + +In the beginning, it's fine to leave an empty object `{}` in the file if +it's not yet clear how compliant the implementation is, +the requirements and expected failures can be figured out in a later step +when the tests are run for the first time. + +See [Format of a status JSON file](#status-format) for details. + +### 2. Pull the WPT files + +Use the [git node wpt][] command to download the WPT files into +`test/fixtures/wpt`. For example, to add URL tests: + +```text +$ cd /path/to/node/project +$ git node wpt url +``` + +### 3. Create the test driver + +For example, for the URL tests, add a file `test/wpt/test-whatwg-url.js`: + +```js +'use strict'; + +// This flag is required by the WPT Runner to patch the internals +// for the tests to run in a vm. +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('url'); + +// Copy global descriptors from the global object +runner.copyGlobalsFromObject(global, ['URL', 'URLSearchParams']); +// Define any additional globals with descriptors +runner.defineGlobal('DOMException', { + get() { + return require('internal/domexception'); + } +}); + +runner.runJsTests(); +``` + +This driver is capable of running the tests located in `test/fixtures/wpt/url` +with the WPT harness while taking the status file into account. + +### 4. Run the tests + +Run the test using `tools/test.py` and see if there are any failures. +For example, to run all the URL tests under `test/fixtures/wpt/url`: + +```text +$ tools/test.py wpt/test-whatwg-url +``` + +To run a specific test in WPT, for example, `url/url-searchparams.any.js`, +pass the file name as argument to the corresponding test driver: + +```text +node --expose-internals test/wpt/test-whatwg-url.js url-searchparams.any.js +``` + +If there are any failures, update the corresponding status file +(in this case, `test/wpt/status/url.json`) to make the test pass. + +For example, to mark `url/url-searchparams.any.js` as expected to fail, +add this to `test/wpt/status/url.json`: + +```json + "url-searchparams.any.js": { + "fail": "explain why the test fails, ideally with links" + } +``` + +See [Format of a status JSON file](#status-format) for details. + +### 5. Commit the changes and submit a Pull Request + +See [the contributing guide](../../CONTRIBUTING.md). + +## How to update tests for a module + +The tests can be updated in a way similar to how they are added. +Run Step 2 and Step 4 of [adding tests for a new module](#add-tests). + +The [git node wpt][] command maintains the status of the local +WPT subset, if no files are updated after running it for a module, +the local subset is up to date and there is no need to update them +until they are changed in the upstream. + +## How it works + +Note: currently this test suite only supports `.js` tests. There is +ongoing work in the upstream to properly split out the tests into files +that can be run in a shell environment like Node.js. + +### Getting the original test files and harness from WPT + +The original files and harness from WPT are downloaded and stored in +`test/fixtures/wpt`. + +The [git node wpt][] command automate this process while maintaining a map +containing the hash of the last updated commit for each module in +`test/fixtures/wpt/versions.json` and [`test/fixtures/wpt/README.md`][]. +It also maintains the LICENSE file in `test/fixtures/wpt`. + +### Loading and running the tests + +Given a module, the `WPTRunner` class in [`test/common/wpt`](../common/wpt.js) +loads: + +- `.js` test files (for example, `test/common/wpt/url/*.js` for `url`) +- Status file (for example, `test/wpt/status/url.json` for `url`) +- The WPT harness + +Then, for each test, it creates a vm with the globals and mocks, +sets up the harness result hooks, loads the metadata in the test (including +loading extra resources), and runs all the tests in that vm, +skipping tests that cannot be run because of lack of dependency or +expected failures. + + +## Format of a status JSON file + +```text +{ + "something.scope.js": { // the file name + // Optional: If the requirement is not met, this test will be skipped + "requires": ["intl"], // currently only intl is supported + + // Optional: the test will be skipped with the reason printed + "skip": "explain why we cannot run a test that's supposed to pass", + + // Optional: the test will be skipped with the reason printed + "fail": "explain why we the test is expected to fail" + } +} +``` + +A test may have to be skipped because it depends on another irrelevant +Web API, or certain harness has not been ported in our test runner yet. +In that case it needs to be marked with `skip` instead of `fail`. + +[Web Platform Tests]: https://github.com/web-platform-tests/wpt +[git node wpt]: https://github.com/nodejs/node-core-utils/blob/master/docs/git-node.md#git-node-wpt +[`test/fixtures/wpt/README.md`]: ../fixtures/wpt/README.md diff --git a/test/wpt/status/console.json b/test/wpt/status/console.json new file mode 100644 index 00000000000000..3874ed148d8610 --- /dev/null +++ b/test/wpt/status/console.json @@ -0,0 +1,8 @@ +{ + "idlharness.any.js": { + "fail": ".table, .dir and .timeLog parameter lengths are wrong" + }, + "console-is-a-namespace.any.js": { + "fail": "The [[Prototype]]'s [[Prototype]] must be %ObjectPrototype%" + } +} diff --git a/test/wpt/status/url.json b/test/wpt/status/url.json new file mode 100644 index 00000000000000..42b5f6fb1a1146 --- /dev/null +++ b/test/wpt/status/url.json @@ -0,0 +1,15 @@ +{ + "toascii.window.js": { + "requires": ["intl"], + "skip": "TODO: port from .window.js" + }, + "historical.any.js": { + "requires": ["intl"] + }, + "urlencoded-parser.any.js": { + "fail": "missing Request and Response" + }, + "idlharness.any.js": { + "fail": "getter/setter names are wrong, etc." + } +} \ No newline at end of file diff --git a/test/wpt/test-whatwg-console.js b/test/wpt/test-whatwg-console.js new file mode 100644 index 00000000000000..7b23fe8d3e619d --- /dev/null +++ b/test/wpt/test-whatwg-console.js @@ -0,0 +1,13 @@ +'use strict'; + +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('console'); + +// Copy global descriptors from the global object +runner.copyGlobalsFromObject(global, ['console']); + +runner.runJsTests(); diff --git a/test/wpt/test-whatwg-url.js b/test/wpt/test-whatwg-url.js new file mode 100644 index 00000000000000..8734452940e84e --- /dev/null +++ b/test/wpt/test-whatwg-url.js @@ -0,0 +1,19 @@ +'use strict'; + +// Flags: --expose-internals + +require('../common'); +const { WPTRunner } = require('../common/wpt'); + +const runner = new WPTRunner('url'); + +// Copy global descriptors from the global object +runner.copyGlobalsFromObject(global, ['URL', 'URLSearchParams']); +// Needed by urlsearchparams-constructor.any.js +runner.defineGlobal('DOMException', { + get() { + return require('internal/domexception'); + } +}); + +runner.runJsTests(); diff --git a/test/wpt/testcfg.py b/test/wpt/testcfg.py new file mode 100644 index 00000000000000..db235699ddfe57 --- /dev/null +++ b/test/wpt/testcfg.py @@ -0,0 +1,6 @@ +import sys, os +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +import testpy + +def GetConfiguration(context, root): + return testpy.ParallelTestConfiguration(context, root, 'wpt') diff --git a/test/wpt/wpt.status b/test/wpt/wpt.status new file mode 100644 index 00000000000000..de3b3024627a1b --- /dev/null +++ b/test/wpt/wpt.status @@ -0,0 +1,21 @@ +prefix wpt + +# To mark a test as flaky, list the test name in the appropriate section +# below, without ".js", followed by ": PASS,FLAKY". Example: +# sample-test : PASS,FLAKY + +[true] # This section applies to all platforms + +[$system==win32] + +[$system==linux] + +[$system==macos] + +[$arch==arm || $arch==arm64] + +[$system==solaris] # Also applies to SmartOS + +[$system==freebsd] + +[$system==aix] From 7bcc4ccd8e83ca650ac9980110ba9db8058980af Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Fri, 2 Nov 2018 18:04:39 +0800 Subject: [PATCH 135/249] doc: remove legacy WPT integration guide Point to the new guide in test/wpt/README.md instead. PR-URL: https://github.com/nodejs/node/pull/24035 Refs: https://github.com/nodejs/node/issues/23192 Reviewed-By: Daijiro Wachi --- doc/guides/writing-tests.md | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md index 4d0c0307bbd765..260dfa236fa615 100644 --- a/doc/guides/writing-tests.md +++ b/doc/guides/writing-tests.md @@ -310,27 +310,7 @@ functions worked correctly with the `beforeExit` event, then it might be named ### Web Platform Tests -Some of the tests for the WHATWG URL implementation (named -`test-whatwg-url-*.js`) are imported from the [Web Platform Tests Project][]. -These imported tests will be wrapped like this: - -```js -/* The following tests are copied from WPT. Modifications to them should be - upstreamed first. Refs: - https://github.com/w3c/web-platform-tests/blob/8791bed/url/urlsearchparams-stringifier.html - License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html -*/ -/* eslint-disable */ - -// Test code - -/* eslint-enable */ -``` - -To improve tests that have been imported this way, please send -a PR to the upstream project first. When the proposed change is merged in -the upstream project, send another PR here to update Node.js accordingly. -Be sure to update the hash in the URL following `WPT Refs:`. +See [`test/wpt`](../../test/wpt/README.md) for more information. ## C++ Unit test @@ -418,7 +398,6 @@ To generate a test coverage report, see the [ASCII]: http://man7.org/linux/man-pages/man7/ascii.7.html [Google Test]: https://github.com/google/googletest -[Web Platform Tests Project]: https://github.com/w3c/web-platform-tests/tree/master/url [`common` module]: https://github.com/nodejs/node/blob/master/test/common/README.md [all maintained branches]: https://github.com/nodejs/lts [node.green]: http://node.green/ From 989c2aaf830c974dc87a0f080834ff08bfd831ab Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 8 Nov 2018 10:03:30 -0800 Subject: [PATCH 136/249] test: fix flaky test-vm-timeout-escape-nexttick MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the VM timeout. If it is too small, the VM does not exit before the code has a chance to create the problematic condition that causes the timeout to be ignored. Fixes: https://github.com/nodejs/node/issues/24120 PR-URL: https://github.com/nodejs/node/pull/24251 Reviewed-By: Refael Ackermann Reviewed-By: Richard Lau Reviewed-By: Michaël Zasso --- test/known_issues/test-vm-timeout-escape-nexttick.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/known_issues/test-vm-timeout-escape-nexttick.js b/test/known_issues/test-vm-timeout-escape-nexttick.js index 814da178fb2f78..40937c96d91a69 100644 --- a/test/known_issues/test-vm-timeout-escape-nexttick.js +++ b/test/known_issues/test-vm-timeout-escape-nexttick.js @@ -35,7 +35,7 @@ assert.throws(() => { nextTick, loop }, - { timeout: common.platformTimeout(5) } + { timeout: common.platformTimeout(10) } ); }, { code: 'ERR_SCRIPT_EXECUTION_TIMEOUT' From 6076ccf90d4a56ba3d0c745699f3a38a5559b4a4 Mon Sep 17 00:00:00 2001 From: reineke-fox Date: Tue, 6 Nov 2018 15:24:56 +0000 Subject: [PATCH 137/249] test: fix order of arguments in test-delayed-require assertion Fix order of arguments in equality assertion in test-delayed-require. PR-URL: https://github.com/nodejs/node/pull/24165 Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater --- test/parallel/test-delayed-require.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-delayed-require.js b/test/parallel/test-delayed-require.js index 8aecb354698185..355d503d2650d2 100644 --- a/test/parallel/test-delayed-require.js +++ b/test/parallel/test-delayed-require.js @@ -26,7 +26,7 @@ const fixtures = require('../common/fixtures'); setTimeout(common.mustCall(function() { const a = require(fixtures.path('a')); - assert.strictEqual(true, 'A' in a); - assert.strictEqual('A', a.A()); - assert.strictEqual('D', a.D()); + assert.strictEqual('A' in a, true); + assert.strictEqual(a.A(), 'A'); + assert.strictEqual(a.D(), 'D'); }), 50); From e46b8edb58058b2be107640b5c813988867be761 Mon Sep 17 00:00:00 2001 From: Mark Arranz Date: Tue, 6 Nov 2018 21:25:30 -0800 Subject: [PATCH 138/249] test: add error code tests in dgram test Improve error validation in test-dgram-send-bad-arguments. PR-URL: https://github.com/nodejs/node/pull/24215 Reviewed-By: Luigi Pinca Reviewed-By: Rich Trott Reviewed-By: Colin Ihrig --- .../parallel/test-dgram-send-bad-arguments.js | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-dgram-send-bad-arguments.js b/test/parallel/test-dgram-send-bad-arguments.js index 4eb7dca7a38e5d..20356ba50c477a 100644 --- a/test/parallel/test-dgram-send-bad-arguments.js +++ b/test/parallel/test-dgram-send-bad-arguments.js @@ -20,7 +20,7 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const dgram = require('dgram'); @@ -28,9 +28,16 @@ const buf = Buffer.from('test'); const host = '127.0.0.1'; const sock = dgram.createSocket('udp4'); -assert.throws(() => { - sock.send(); -}, TypeError); // First argument should be a buffer. +// First argument should be a buffer. +common.expectsError( + () => { sock.send(); }, + { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "buffer" argument must be one of type ' + + 'Buffer, Uint8Array, or string. Received type undefined' + } +); // send(buf, offset, length, port, host) assert.throws(() => { sock.send(buf, 1, 1, -1, host); }, RangeError); @@ -38,7 +45,23 @@ assert.throws(() => { sock.send(buf, 1, 1, 0, host); }, RangeError); assert.throws(() => { sock.send(buf, 1, 1, 65536, host); }, RangeError); // send(buf, port, host) -assert.throws(() => { sock.send(23, 12345, host); }, TypeError); +common.expectsError( + () => { sock.send(23, 12345, host); }, + { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "buffer" argument must be one of type ' + + 'Buffer, Uint8Array, or string. Received type number' + } +); // send([buf1, ..], port, host) -assert.throws(() => { sock.send([buf, 23], 12345, host); }, TypeError); +common.expectsError( + () => { sock.send([buf, 23], 12345, host); }, + { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError, + message: 'The "buffer list arguments" argument must be one of type ' + + 'Buffer or string. Received type object' + } +); From 0063448b04e79ed62eb16b9720c24c42bd2d9b89 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 7 Nov 2018 15:58:51 +0800 Subject: [PATCH 139/249] url: make the context non-enumerable At the moment we expose the context as a normal property on the prototype chain of URL or take them from the base URL which makes them enumerable and considered by assert libraries even though the context carries path-dependent information that do not affect the equivalence of these objects. This patch fixes it in a minimal manner by marking the context non-enumerable as making it full private would require more refactoring and can be done in a bigger patch later. PR-URL: https://github.com/nodejs/node/pull/24218 Refs: https://github.com/nodejs/node/issues/24211 Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: Daijiro Wachi --- lib/internal/url.js | 15 +++++++++++++-- ...est-whatwg-url-custom-no-enumerable-context.js | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-whatwg-url-custom-no-enumerable-context.js diff --git a/lib/internal/url.js b/lib/internal/url.js index 518c745b41e760..693f082aed6137 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -245,7 +245,14 @@ function onParseError(flags, input) { // Reused by URL constructor and URL#href setter. function parse(url, input, base) { const base_context = base ? base[context] : undefined; - url[context] = new URLContext(); + // In the URL#href setter + if (!url[context]) { + Object.defineProperty(url, context, { + enumerable: false, + configurable: false, + value: new URLContext() + }); + } _parse(input.trim(), -1, base_context, undefined, onParseComplete.bind(url), onParseError); } @@ -1437,7 +1444,11 @@ function toPathIfFileURL(fileURLOrPath) { } function NativeURL(ctx) { - this[context] = ctx; + Object.defineProperty(this, context, { + enumerable: false, + configurable: false, + value: ctx + }); } NativeURL.prototype = URL.prototype; diff --git a/test/parallel/test-whatwg-url-custom-no-enumerable-context.js b/test/parallel/test-whatwg-url-custom-no-enumerable-context.js new file mode 100644 index 00000000000000..f24a47b6d5c8f0 --- /dev/null +++ b/test/parallel/test-whatwg-url-custom-no-enumerable-context.js @@ -0,0 +1,14 @@ +'use strict'; +// This tests that the context of URL objects are not +// enumerable and thus considered by assert libraries. +// See https://github.com/nodejs/node/issues/24211 + +// Tests below are not from WPT. + +require('../common'); +const assert = require('assert'); + +assert.deepStrictEqual( + new URL('./foo', 'https://example.com/'), + new URL('https://example.com/foo') +); From ad5c9b44637b06b879e8b5e4f981776e22f0e915 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 7 Nov 2018 04:28:50 +0800 Subject: [PATCH 140/249] benchmark: support more options in startup benchmark 1. Add options to benchmark the startup performance of a node "instance" after running a script. By default there are two options: `test/fixtures/semicolon` which is basically an empty file, and `benchmark/fixtures/require-cachable` which require all the cachable modules before exiting. This allows us to measure the overhead of bootstrap in more scenarios. 2. Add options to benchmark the overhead of spinning node through a process and through a worker. PR-URL: https://github.com/nodejs/node/pull/24220 Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau --- benchmark/fixtures/require-cachable.js | 13 ++++ benchmark/misc/startup.js | 88 +++++++++++++++++++------- test/parallel/test-benchmark-misc.js | 2 + 3 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 benchmark/fixtures/require-cachable.js diff --git a/benchmark/fixtures/require-cachable.js b/benchmark/fixtures/require-cachable.js new file mode 100644 index 00000000000000..f651728dc78f35 --- /dev/null +++ b/benchmark/fixtures/require-cachable.js @@ -0,0 +1,13 @@ +'use strict'; + +const list = require('internal/bootstrap/cache'); +const { + isMainThread +} = require('worker_threads'); + +for (const key of list.cachableBuiltins) { + if (!isMainThread && key === 'trace_events') { + continue; + } + require(key); +} diff --git a/benchmark/misc/startup.js b/benchmark/misc/startup.js index 703146f081b3c6..1350cd291e2b18 100644 --- a/benchmark/misc/startup.js +++ b/benchmark/misc/startup.js @@ -1,36 +1,76 @@ 'use strict'; const common = require('../common.js'); -const spawn = require('child_process').spawn; +const { spawn } = require('child_process'); const path = require('path'); -const emptyJsFile = path.resolve(__dirname, '../../test/fixtures/semicolon.js'); -const bench = common.createBenchmark(startNode, { - dur: [1] +let Worker; // Lazy loaded in main + +const bench = common.createBenchmark(main, { + dur: [1], + script: ['benchmark/fixtures/require-cachable', 'test/fixtures/semicolon'], + mode: ['process', 'worker'] +}, { + flags: ['--expose-internals', '--experimental-worker'] // for workers }); -function startNode({ dur }) { - var go = true; - var starts = 0; +function spawnProcess(script) { + const cmd = process.execPath || process.argv[0]; + const argv = ['--expose-internals', script]; + return spawn(cmd, argv); +} + +function spawnWorker(script) { + return new Worker(script, { stderr: true, stdout: true }); +} + +function start(state, script, bench, getNode) { + const node = getNode(script); + let stdout = ''; + let stderr = ''; + + node.stdout.on('data', (data) => { + stdout += data; + }); + + node.stderr.on('data', (data) => { + stderr += data; + }); + + node.on('exit', (code) => { + if (code !== 0) { + console.error('------ stdout ------'); + console.error(stdout); + console.error('------ stderr ------'); + console.error(stderr); + throw new Error(`Error during node startup, exit code ${code}`); + } + state.throughput++; + + if (state.go) { + start(state, script, bench, getNode); + } else { + bench.end(state.throughput); + } + }); +} + +function main({ dur, script, mode }) { + const state = { + go: true, + throughput: 0 + }; setTimeout(function() { - go = false; + state.go = false; }, dur * 1000); - bench.start(); - start(); - - function start() { - const node = spawn(process.execPath || process.argv[0], [emptyJsFile]); - node.on('exit', function(exitCode) { - if (exitCode !== 0) { - throw new Error('Error during node startup'); - } - starts++; - - if (go) - start(); - else - bench.end(starts); - }); + script = path.resolve(__dirname, '../../', `${script}.js`); + if (mode === 'worker') { + Worker = require('worker_threads').Worker; + bench.start(); + start(state, script, bench, spawnWorker); + } else { + bench.start(); + start(state, script, bench, spawnProcess); } } diff --git a/test/parallel/test-benchmark-misc.js b/test/parallel/test-benchmark-misc.js index fc7e340a80d0bb..b88415280833bc 100644 --- a/test/parallel/test-benchmark-misc.js +++ b/test/parallel/test-benchmark-misc.js @@ -11,4 +11,6 @@ runBenchmark('misc', [ 'n=1', 'type=', 'val=magyarország.icom.museum', + 'script=test/fixtures/semicolon', + 'mode=worker' ], { NODEJS_BENCHMARK_ZERO_ALLOWED: 1 }); From 104b076d3d02d681ccb59594dad0fea471c65b18 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Wed, 7 Nov 2018 12:27:47 -0800 Subject: [PATCH 141/249] doc: clarify allowed encoding parameter types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the incorrect enumerations of their possible values, which weren't up to date with the values actually supported. Also renamed two arguments that used "format" when they meant "encoding". PR-URL: https://github.com/nodejs/node/pull/24230 Reviewed-By: Tobias Nießen Reviewed-By: Refael Ackermann Reviewed-By: Vse Mozhet Byt --- doc/api/crypto.md | 185 ++++++++++++++++++++++------------------------ doc/api/errors.md | 2 +- 2 files changed, 91 insertions(+), 96 deletions(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 81706157e62cac..f592f36e241f6c 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -72,7 +72,7 @@ console.log(challenge.toString('utf8')); added: v9.0.0 --> * `spkac` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `spkac` string. * Returns: {Buffer} The public key component of the `spkac` data structure, which includes a public key and a challenge. @@ -231,9 +231,9 @@ console.log(encrypted); -* `outputEncoding` {string} +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Any remaining enciphered contents. - If `outputEncoding` is one of `'latin1'`, `'base64'` or `'hex'`, a string is + If `outputEncoding` is specified, a string is returned. If an `outputEncoding` is not provided, a [`Buffer`][] is returned. Once the `cipher.final()` method has been called, the `Cipher` object can no @@ -299,19 +299,19 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the data. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Updates the cipher with `data`. If the `inputEncoding` argument is given, -its value must be one of `'utf8'`, `'ascii'`, or `'latin1'` and the `data` +the `data` argument is a string using the specified encoding. If the `inputEncoding` argument is not given, `data` must be a [`Buffer`][], `TypedArray`, or `DataView`. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. The `outputEncoding` specifies the output format of the enciphered -data, and can be `'latin1'`, `'base64'` or `'hex'`. If the `outputEncoding` +data. If the `outputEncoding` is specified, a string using the specified encoding is returned. If no `outputEncoding` is provided, a [`Buffer`][] is returned. @@ -390,9 +390,9 @@ console.log(decrypted); -* `outputEncoding` {string} +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Any remaining deciphered contents. - If `outputEncoding` is one of `'latin1'`, `'ascii'` or `'utf8'`, a string is + If `outputEncoding` is specified, a string is returned. If an `outputEncoding` is not provided, a [`Buffer`][] is returned. Once the `decipher.final()` method has been called, the `Decipher` object can @@ -473,18 +473,18 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Updates the decipher with `data`. If the `inputEncoding` argument is given, -its value must be one of `'latin1'`, `'base64'`, or `'hex'` and the `data` +the `data` argument is a string using the specified encoding. If the `inputEncoding` argument is not given, `data` must be a [`Buffer`][]. If `data` is a [`Buffer`][] then `inputEncoding` is ignored. The `outputEncoding` specifies the output format of the enciphered -data, and can be `'latin1'`, `'ascii'` or `'utf8'`. If the `outputEncoding` +data. If the `outputEncoding` is specified, a string using the specified encoding is returned. If no `outputEncoding` is provided, a [`Buffer`][] is returned. @@ -528,15 +528,15 @@ assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); added: v0.5.0 --> * `otherPublicKey` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of an `otherPublicKey` string. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Computes the shared secret using `otherPublicKey` as the other party's public key and returns the computed shared secret. The supplied key is interpreted using the specified `inputEncoding`, and secret is -encoded using specified `outputEncoding`. Encodings can be -`'latin1'`, `'hex'`, or `'base64'`. If the `inputEncoding` is not +encoded using specified `outputEncoding`. +If the `inputEncoding` is not provided, `otherPublicKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -547,57 +547,57 @@ If `outputEncoding` is given a string is returned; otherwise, a -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Generates private and public Diffie-Hellman key values, and returns the public key in the specified `encoding`. This key should be -transferred to the other party. Encoding can be `'latin1'`, `'hex'`, -or `'base64'`. If `encoding` is provided a string is returned; otherwise a +transferred to the other party. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getGenerator([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman generator in the specified `encoding`, which can -be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is +Returns the Diffie-Hellman generator in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPrime([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman prime in the specified `encoding`, which can -be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a string is +Returns the Diffie-Hellman prime in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPrivateKey([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman private key in the specified `encoding`, -which can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a +Returns the Diffie-Hellman private key in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.getPublicKey([encoding]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} -Returns the Diffie-Hellman public key in the specified `encoding`, which -can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` is provided a +Returns the Diffie-Hellman public key in the specified `encoding`. +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### diffieHellman.setPrivateKey(privateKey[, encoding]) @@ -605,10 +605,10 @@ string is returned; otherwise a [`Buffer`][] is returned. added: v0.5.0 --> * `privateKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `privateKey` string. -Sets the Diffie-Hellman private key. If the `encoding` argument is provided -and is either `'latin1'`, `'hex'`, or `'base64'`, `privateKey` is expected +Sets the Diffie-Hellman private key. If the `encoding` argument is provided, +`privateKey` is expected to be a string. If no `encoding` is provided, `privateKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -617,10 +617,10 @@ to be a [`Buffer`][], `TypedArray`, or `DataView`. added: v0.5.0 --> * `publicKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `publicKey` string. -Sets the Diffie-Hellman public key. If the `encoding` argument is provided -and is either `'latin1'`, `'hex'` or `'base64'`, `publicKey` is expected +Sets the Diffie-Hellman public key. If the `encoding` argument is provided, +`publicKey` is expected to be a string. If no `encoding` is provided, `publicKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -678,8 +678,8 @@ added: v10.0.0 * `key` {string | Buffer | TypedArray | DataView} * `curve` {string} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `key` string. +* `outputEncoding` {string} The [encoding][] of the return value. * `format` {string} **Default:** `'uncompressed'` * Returns: {Buffer | string} @@ -687,8 +687,7 @@ Converts the EC Diffie-Hellman public key specified by `key` and `curve` to the format specified by `format`. The `format` argument specifies point encoding and can be `'compressed'`, `'uncompressed'` or `'hybrid'`. The supplied key is interpreted using the specified `inputEncoding`, and the returned key is encoded -using the specified `outputEncoding`. Encodings can be `'latin1'`, `'hex'`, -or `'base64'`. +using the specified `outputEncoding`. Use [`crypto.getCurves()`][] to obtain a list of available curve names. On recent OpenSSL releases, `openssl ecparam -list_curves` will also display @@ -733,15 +732,15 @@ changes: error --> * `otherPublicKey` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} -* `outputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `otherPublicKey` string. +* `outputEncoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Computes the shared secret using `otherPublicKey` as the other party's public key and returns the computed shared secret. The supplied key is interpreted using specified `inputEncoding`, and the returned secret -is encoded using the specified `outputEncoding`. Encodings can be -`'latin1'`, `'hex'`, or `'base64'`. If the `inputEncoding` is not +is encoded using the specified `outputEncoding`. +If the `inputEncoding` is not provided, `otherPublicKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -758,7 +757,7 @@ its recommended for developers to handle this exception accordingly. -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * `format` {string} **Default:** `'uncompressed'` * Returns: {Buffer | string} @@ -770,24 +769,24 @@ The `format` argument specifies point encoding and can be `'compressed'` or `'uncompressed'`. If `format` is not specified, the point will be returned in `'uncompressed'` format. -The `encoding` argument can be `'latin1'`, `'hex'`, or `'base64'`. If -`encoding` is provided a string is returned; otherwise a [`Buffer`][] +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned. ### ecdh.getPrivateKey([encoding]) -* `encoding` {string} -* Returns: {Buffer | string} The EC Diffie-Hellman private key in the specified - `encoding`, which can be `'latin1'`, `'hex'`, or `'base64'`. If `encoding` - is provided a string is returned; otherwise a [`Buffer`][] is returned. +* `encoding` {string} The [encoding][] of the return value. +* Returns: {Buffer | string} The EC Diffie-Hellman in the specified `encoding`. + +If `encoding` is specified, a string is returned; otherwise a [`Buffer`][] is +returned. ### ecdh.getPublicKey([encoding][, format]) -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * `format` {string} **Default:** `'uncompressed'` * Returns: {Buffer | string} The EC Diffie-Hellman public key in the specified `encoding` and `format`. @@ -796,8 +795,7 @@ The `format` argument specifies point encoding and can be `'compressed'` or `'uncompressed'`. If `format` is not specified the point will be returned in `'uncompressed'` format. -The `encoding` argument can be `'latin1'`, `'hex'`, or `'base64'`. If -`encoding` is specified, a string is returned; otherwise a [`Buffer`][] is +If `encoding` is specified, a string is returned; otherwise a [`Buffer`][] is returned. ### ecdh.setPrivateKey(privateKey[, encoding]) @@ -805,10 +803,10 @@ returned. added: v0.11.14 --> * `privateKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `privateKey` string. -Sets the EC Diffie-Hellman private key. The `encoding` can be `'latin1'`, -`'hex'` or `'base64'`. If `encoding` is provided, `privateKey` is expected +Sets the EC Diffie-Hellman private key. +If `encoding` is provided, `privateKey` is expected to be a string; otherwise `privateKey` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -825,10 +823,10 @@ deprecated: v5.2.0 > Stability: 0 - Deprecated * `publicKey` {string | Buffer | TypedArray | DataView} -* `encoding` {string} +* `encoding` {string} The [encoding][] of the `publicKey` string. -Sets the EC Diffie-Hellman public key. Key encoding can be `'latin1'`, -`'hex'` or `'base64'`. If `encoding` is provided `publicKey` is expected to +Sets the EC Diffie-Hellman public key. +If `encoding` is provided `publicKey` is expected to be a string; otherwise a [`Buffer`][], `TypedArray`, or `DataView` is expected. Note that there is not normally a reason to call this method because `ECDH` @@ -925,12 +923,12 @@ console.log(hash.digest('hex')); -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Calculates the digest of all of the data passed to be hashed (using the -[`hash.update()`][] method). The `encoding` can be `'hex'`, `'latin1'` or -`'base64'`. If `encoding` is provided a string will be returned; otherwise +[`hash.update()`][] method). +If `encoding` is provided a string will be returned; otherwise a [`Buffer`][] is returned. The `Hash` object can not be used again after `hash.digest()` method has been @@ -945,11 +943,11 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the hash content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `encoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. @@ -1017,11 +1015,11 @@ console.log(hmac.digest('hex')); -* `encoding` {string} +* `encoding` {string} The [encoding][] of the return value. * Returns: {Buffer | string} Calculates the HMAC digest of all of the data passed using [`hmac.update()`][]. -The `encoding` can be `'hex'`, `'latin1'` or `'base64'`. If `encoding` is +If `encoding` is provided a string is returned; otherwise a [`Buffer`][] is returned; The `Hmac` object can not be used again after `hmac.digest()` has been @@ -1036,11 +1034,11 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the `Hmac` content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `encoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. @@ -1110,7 +1108,7 @@ console.log(sign.sign(privateKey, 'hex')); // Prints: the calculated signature ``` -### sign.sign(privateKey[, outputFormat]) +### sign.sign(privateKey[, outputEncoding]) * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the `Sign` content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `encoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. @@ -1227,17 +1224,17 @@ changes: description: The default `inputEncoding` changed from `binary` to `utf8`. --> * `data` {string | Buffer | TypedArray | DataView} -* `inputEncoding` {string} +* `inputEncoding` {string} The [encoding][] of the `data` string. Updates the `Verify` content with the given `data`, the encoding of which -is given in `inputEncoding` and can be `'utf8'`, `'ascii'` or -`'latin1'`. If `encoding` is not provided, and the `data` is a string, an +is given in `inputEncoding`. +If `inputEncoding` is not provided, and the `data` is a string, an encoding of `'utf8'` is enforced. If `data` is a [`Buffer`][], `TypedArray`, or `DataView`, then `inputEncoding` is ignored. This can be called many times with new data as it is streamed. -### verify.verify(object, signature[, signatureFormat]) +### verify.verify(object, signature[, signatureEncoding]) * `object` {string | Object} * `signature` {string | Buffer | TypedArray | DataView} -* `signatureFormat` {string} +* `signatureEncoding` {string} The [encoding][] of the `signature` string. * Returns: {boolean} `true` or `false` depending on the validity of the signature for the data and public key. @@ -1270,8 +1267,8 @@ or an object with one or more of the following properties: determined automatically. The `signature` argument is the previously calculated signature for the data, in -the `signatureFormat` which can be `'latin1'`, `'hex'` or `'base64'`. -If a `signatureFormat` is specified, the `signature` is expected to be a +the `signatureEncoding`. +If a `signatureEncoding` is specified, the `signature` is expected to be a string; otherwise `signature` is expected to be a [`Buffer`][], `TypedArray`, or `DataView`. @@ -1535,10 +1532,10 @@ changes: from `binary` to `utf8`. --> * `prime` {string | Buffer | TypedArray | DataView} -* `primeEncoding` {string} +* `primeEncoding` {string} The [encoding][] of the `prime` string. * `generator` {number | string | Buffer | TypedArray | DataView} **Default:** `2` -* `generatorEncoding` {string} +* `generatorEncoding` {string} The [encoding][] of the `generator` string. * Returns: {DiffieHellman} Creates a `DiffieHellman` key exchange object using the supplied `prime` and an @@ -1547,9 +1544,6 @@ optional specific `generator`. The `generator` argument can be a number, string, or [`Buffer`][]. If `generator` is not specified, the value `2` is used. -The `primeEncoding` and `generatorEncoding` arguments can be `'latin1'`, -`'hex'`, or `'base64'`. - If `primeEncoding` is specified, `prime` is expected to be a string; otherwise a [`Buffer`][], `TypedArray`, or `DataView` is expected. @@ -2894,13 +2888,13 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. [`hash.update()`]: #crypto_hash_update_data_inputencoding [`hmac.digest()`]: #crypto_hmac_digest_encoding [`hmac.update()`]: #crypto_hmac_update_data_inputencoding -[`sign.sign()`]: #crypto_sign_sign_privatekey_outputformat +[`sign.sign()`]: #crypto_sign_sign_privatekey_outputencoding [`sign.update()`]: #crypto_sign_update_data_inputencoding [`stream.transform` options]: stream.html#stream_new_stream_transform_options [`stream.Writable` options]: stream.html#stream_constructor_new_stream_writable_options [`util.promisify()`]: util.html#util_util_promisify_original [`verify.update()`]: #crypto_verify_update_data_inputencoding -[`verify.verify()`]: #crypto_verify_verify_object_signature_signatureformat +[`verify.verify()`]: #crypto_verify_verify_object_signature_signatureencoding [AEAD algorithms]: https://en.wikipedia.org/wiki/Authenticated_encryption [Caveats]: #crypto_support_for_weak_or_compromised_algorithms [CCM mode]: #crypto_ccm_mode @@ -2916,6 +2910,7 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. [RFC 3526]: https://www.rfc-editor.org/rfc/rfc3526.txt [RFC 3610]: https://www.rfc-editor.org/rfc/rfc3610.txt [RFC 4055]: https://www.rfc-editor.org/rfc/rfc4055.txt +[encoding]: buffer.html#buffer_buffers_and_character_encodings [initialization vector]: https://en.wikipedia.org/wiki/Initialization_vector [scrypt]: https://en.wikipedia.org/wiki/Scrypt [stream-writable-write]: stream.html#stream_writable_write_chunk_encoding_callback diff --git a/doc/api/errors.md b/doc/api/errors.md index 82c4e790e6b84b..500fb7801b61fd 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2159,7 +2159,7 @@ such as `process.stdout.on('data')`. [`require()`]: modules.html#modules_require [`server.close()`]: net.html#net_server_close_callback [`server.listen()`]: net.html#net_server_listen -[`sign.sign()`]: crypto.html#crypto_sign_sign_privatekey_outputformat +[`sign.sign()`]: crypto.html#crypto_sign_sign_privatekey_outputencoding [`stream.pipe()`]: stream.html#stream_readable_pipe_destination_options [`stream.push()`]: stream.html#stream_readable_push_chunk_encoding [`stream.unshift()`]: stream.html#stream_readable_unshift_chunk From 1b81b348a351278b254fff1a4cf3e41ddc2c0bd0 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Wed, 7 Nov 2018 13:25:52 -0800 Subject: [PATCH 142/249] doc: describe what tls servername is for Docs should describe the purpose of the option. PR-URL: https://github.com/nodejs/node/pull/24236 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- doc/api/tls.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/api/tls.md b/doc/api/tls.md index ec36b4e57128ec..b562c11b368544 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -906,7 +906,10 @@ changes: protocol name. Passing an array is usually much simpler, e.g. `['hello', 'world']`. * `servername`: {string} Server name for the SNI (Server Name Indication) TLS - extension. It must be a host name, and not an IP address. + extension. It is the name of the host being connected to, and must be a host + name, and not an IP address. It can be used by a multi-homed server to + choose the correct certificate to present to the client, see the + `SNICallback` option to [`tls.createServer()`][]. * `checkServerIdentity(servername, cert)` {Function} A callback function to be used (instead of the builtin `tls.checkServerIdentity()` function) when checking the server's hostname (or the provided `servername` when From 81f4fb2b3b8cdc37e8228b1c75f5b7adb590bc2d Mon Sep 17 00:00:00 2001 From: alyssaq Date: Tue, 6 Nov 2018 14:34:52 +0000 Subject: [PATCH 143/249] src: reuse std::make_unique Ref: https://github.com/nodejs/node/commit/283a967e356311a467113eea450a81827d43c969 PR-URL: https://github.com/nodejs/node/pull/24132 Refs: https://github.com/nodejs/node/commit/283a967e356311a467113eea450a81827d43c969 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Eugene Ostroukhov --- src/inspector_agent.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index e22e8ee9592921..e0ee24a7f0c215 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -475,11 +475,9 @@ class NodeInspectorClient : public V8InspectorClient { bool prevent_shutdown) { events_dispatched_ = true; int session_id = next_session_id_++; - // TODO(addaleax): Revert back to using make_unique once we get issues - // with CI resolved (i.e. revert the patch that added this comment). - channels_[session_id].reset( - new ChannelImpl(env_, client_, getWorkerManager(), - std::move(delegate), prevent_shutdown)); + channels_[session_id] = + std::make_unique(env_, client_, getWorkerManager(), + std::move(delegate), prevent_shutdown); return session_id; } From 5510bec3cceed0aede64b675a1161a10a42347c4 Mon Sep 17 00:00:00 2001 From: Manish Poddar Date: Tue, 6 Nov 2018 15:40:01 +0000 Subject: [PATCH 144/249] test: fix assert argument order PR-URL: https://github.com/nodejs/node/pull/24160 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater --- test/parallel/test-child-process-stdio.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-child-process-stdio.js b/test/parallel/test-child-process-stdio.js index 5ca3875f5600f6..a5e5f952259cee 100644 --- a/test/parallel/test-child-process-stdio.js +++ b/test/parallel/test-child-process-stdio.js @@ -60,8 +60,8 @@ const { spawn } = require('child_process'); })); child.on('close', common.mustCall(function() { - assert.strictEqual(true, output.length > 1); - assert.strictEqual('\n', output[output.length - 1]); + assert.strictEqual(output.length > 1, true); + assert.strictEqual(output[output.length - 1], '\n'); })); } From a1f5179e0912d9bde00e9b2f5169180b696c44f4 Mon Sep 17 00:00:00 2001 From: szabolcsit Date: Tue, 6 Nov 2018 15:33:38 +0100 Subject: [PATCH 145/249] test: fix arguments order in assert.strictEqual In the test test/parallel/test-http-client-upload.js test the actual and expected arguments in assert.strictEqual() calls were in the wrong order. Switched them around so the returned value by the function is the first argument and the literal value is the second argument. PR-URL: https://github.com/nodejs/node/pull/24143 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- test/parallel/test-http-client-upload.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-http-client-upload.js b/test/parallel/test-http-client-upload.js index 000bf1d58424a3..830c37da8ef567 100644 --- a/test/parallel/test-http-client-upload.js +++ b/test/parallel/test-http-client-upload.js @@ -25,7 +25,7 @@ const assert = require('assert'); const http = require('http'); const server = http.createServer(common.mustCall(function(req, res) { - assert.strictEqual('POST', req.method); + assert.strictEqual(req.method, 'POST'); req.setEncoding('utf8'); let sent_body = ''; @@ -36,7 +36,7 @@ const server = http.createServer(common.mustCall(function(req, res) { }); req.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', sent_body); + assert.strictEqual(sent_body, '1\n2\n3\n'); console.log('request complete from server'); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('hello\n'); From be40fd1e50190482bec194049e9178c3814a7712 Mon Sep 17 00:00:00 2001 From: Kevin Seidel Date: Tue, 6 Nov 2018 17:06:28 +0100 Subject: [PATCH 146/249] test: fix order in assert.strictEqual to actual, expected PR-URL: https://github.com/nodejs/node/pull/24184 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil --- test/addons-napi/test_make_callback/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/addons-napi/test_make_callback/test.js b/test/addons-napi/test_make_callback/test.js index 3f51acb6c07ac6..f409bbc9d127d6 100644 --- a/test/addons-napi/test_make_callback/test.js +++ b/test/addons-napi/test_make_callback/test.js @@ -14,7 +14,7 @@ function myMultiArgFunc(arg1, arg2, arg3) { } assert.strictEqual(makeCallback(process, common.mustCall(function() { - assert.strictEqual(0, arguments.length); + assert.strictEqual(arguments.length, 0); assert.strictEqual(this, process); return 42; })), 42); From 4245cbbf496a854508c832db75421c0bd4fa2c88 Mon Sep 17 00:00:00 2001 From: mzucker Date: Wed, 7 Nov 2018 15:14:13 +0000 Subject: [PATCH 147/249] test: fix the arguments order in `assert.strictEqual` This change was initiated from the NodeConfEU session. PR-URL: https://github.com/nodejs/node/pull/24226 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig --- test/parallel/test-fs-read-stream-fd-leak.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-fs-read-stream-fd-leak.js b/test/parallel/test-fs-read-stream-fd-leak.js index 5bf0157ff4e7ae..81712def761340 100644 --- a/test/parallel/test-fs-read-stream-fd-leak.js +++ b/test/parallel/test-fs-read-stream-fd-leak.js @@ -37,8 +37,8 @@ function testLeak(endFn, callback) { } assert.strictEqual( - 0, openCount, + 0, `no leaked file descriptors using ${endFn}() (got ${openCount})` ); From c8d8e5cf2cbdca1c5cf18795fb335361d095ccba Mon Sep 17 00:00:00 2001 From: mzucker Date: Wed, 7 Nov 2018 15:21:37 +0000 Subject: [PATCH 148/249] test: fix the arguments order in `assert.strictEqual` This change was initiated from the NodeConfEU session. PR-URL: https://github.com/nodejs/node/pull/24227 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig --- test/parallel/test-fs-link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-fs-link.js b/test/parallel/test-fs-link.js index d007f4e985b2d5..9b95fc3e026140 100644 --- a/test/parallel/test-fs-link.js +++ b/test/parallel/test-fs-link.js @@ -15,7 +15,7 @@ fs.writeFileSync(srcPath, 'hello world'); function callback(err) { assert.ifError(err); const dstContent = fs.readFileSync(dstPath, 'utf8'); - assert.strictEqual('hello world', dstContent); + assert.strictEqual(dstContent, 'hello world'); } fs.link(srcPath, dstPath, common.mustCall(callback)); From 6ab46b5c47cbdce18c7655eab9f6c8344269bf18 Mon Sep 17 00:00:00 2001 From: Sam Roberts Date: Tue, 6 Nov 2018 09:58:42 -0800 Subject: [PATCH 149/249] doc: fix some inconsistent use of hostname host names are DNS names, host addresses are IP addresses, and `host` arguments and options can be either. PR-URL: https://github.com/nodejs/node/pull/24199 Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- doc/api/async_hooks.md | 2 +- doc/api/http.md | 14 +++++++------- doc/api/tls.md | 5 +++-- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index b99c5fee718865..06343aaf7f716c 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -296,7 +296,7 @@ of propagating what resource is responsible for the new resource's existence. been initialized. This can contain useful information that can vary based on the value of `type`. For instance, for the `GETADDRINFOREQWRAP` resource type, `resource` provides the hostname used when looking up the IP address for the -hostname in `net.Server.listen()`. The API for accessing this information is +host in `net.Server.listen()`. The API for accessing this information is currently not considered public, but using the Embedder API, users can provide and document their own resource objects. For example, such a resource object could contain the SQL query being executed. diff --git a/doc/api/http.md b/doc/api/http.md index ff948cd9f5d6a6..4f526b36aaea8e 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -368,7 +368,7 @@ proxy.listen(1337, '127.0.0.1', () => { // make a request to a tunneling proxy const options = { port: 1337, - hostname: '127.0.0.1', + host: '127.0.0.1', method: 'CONNECT', path: 'www.google.com:80' }; @@ -415,7 +415,7 @@ event is emitted with a callback containing an object with a status code. const http = require('http'); const options = { - hostname: '127.0.0.1', + host: '127.0.0.1', port: 8080, path: '/length_request' }; @@ -502,7 +502,7 @@ srv.listen(1337, '127.0.0.1', () => { // make a request const options = { port: 1337, - hostname: '127.0.0.1', + host: '127.0.0.1', headers: { 'Connection': 'Upgrade', 'Upgrade': 'websocket' @@ -1898,14 +1898,14 @@ changes: * `host` {string} A domain name or IP address of the server to issue the request to. **Default:** `'localhost'`. * `hostname` {string} Alias for `host`. To support [`url.parse()`][], - `hostname` is preferred over `host`. - * `family` {number} IP address family to use when resolving `host` and + `hostname` will be used if both `host` and `hostname` are specified. + * `family` {number} IP address family to use when resolving `host` or `hostname`. Valid values are `4` or `6`. When unspecified, both IP v4 and v6 will be used. * `port` {number} Port of remote server. **Default:** `80`. * `localAddress` {string} Local interface to bind for network connections. - * `socketPath` {string} Unix Domain Socket (use one of `host:port` or - `socketPath`). + * `socketPath` {string} Unix Domain Socket (cannot be used if one of `host` + or `port` is specified, those specify a TCP Socket). * `method` {string} A string specifying the HTTP request method. **Default:** `'GET'`. * `path` {string} Request path. Should include query string if any. diff --git a/doc/api/tls.md b/doc/api/tls.md index b562c11b368544..31ad74a6ce8d1f 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -811,14 +811,15 @@ decrease overall server throughput. added: v0.8.4 --> -* `hostname` {string} The hostname to verify the certificate against +* `hostname` {string} The host name or IP address to verify the certificate + against. * `cert` {Object} An object representing the peer's certificate. The returned object has some properties corresponding to the fields of the certificate. * Returns: {Error|undefined} Verifies the certificate `cert` is issued to `hostname`. -Returns {Error} object, populating it with the reason, host, and cert on +Returns {Error} object, populating it with `reason`, `host`, and `cert` on failure. On success, returns {undefined}. This function can be overwritten by providing alternative function as part of From 2baa59b8973eedc9a12fb0f3dc15d08183323c53 Mon Sep 17 00:00:00 2001 From: Jonah Polack Date: Tue, 6 Nov 2018 16:52:32 +0000 Subject: [PATCH 150/249] test: switch order of strictEqual arguments PR-URL: https://github.com/nodejs/node/pull/24185 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- test/parallel/test-fs-read-file-sync.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-fs-read-file-sync.js b/test/parallel/test-fs-read-file-sync.js index c8a9941b4990da..ee6f34ac4dccfd 100644 --- a/test/parallel/test-fs-read-file-sync.js +++ b/test/parallel/test-fs-read-file-sync.js @@ -29,6 +29,6 @@ const fn = fixtures.path('elipses.txt'); const s = fs.readFileSync(fn, 'utf8'); for (let i = 0; i < s.length; i++) { - assert.strictEqual('\u2026', s[i]); + assert.strictEqual(s[i], '\u2026'); } -assert.strictEqual(10000, s.length); +assert.strictEqual(s.length, 10000); From 0c4facfbaf31cd11c140ddf4954b6db7458ae42c Mon Sep 17 00:00:00 2001 From: Paul Isache Date: Tue, 6 Nov 2018 15:22:40 +0000 Subject: [PATCH 151/249] test: change arguments order in strictEqual Fix actual/expected ordering in test-net-eaddrinuse. PR-URL: https://github.com/nodejs/node/pull/24156 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Trivikram Kamat --- test/parallel/test-net-eaddrinuse.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-net-eaddrinuse.js b/test/parallel/test-net-eaddrinuse.js index 8c3bcc6cf142dc..29508e4582852e 100644 --- a/test/parallel/test-net-eaddrinuse.js +++ b/test/parallel/test-net-eaddrinuse.js @@ -30,7 +30,7 @@ const server2 = net.createServer(function(socket) { }); server1.listen(0, function() { server2.on('error', function(error) { - assert.strictEqual(true, error.message.includes('EADDRINUSE')); + assert.strictEqual(error.message.includes('EADDRINUSE'), true); server1.close(); }); server2.listen(this.address().port); From 92d2d7917fbd40d8767acebcf59ce4ff3fd453fa Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 7 Nov 2018 07:50:51 +0100 Subject: [PATCH 152/249] test: fix NewFromUtf8 compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently there are a number of compiler warnings like the following: ../binding.cc:6:41: warning: 'NewFromUtf8' is deprecated: Use maybe version [-Wdeprecated-declarations] args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); ^ /node/deps/v8/include/v8.h:2883:10: note: 'NewFromUtf8' has been explicitly marked deprecated here static V8_DEPRECATE_SOON( ^ /node/deps/v8/include/v8config.h:341:29: note: expanded from macro 'V8_DEPRECATE_SOON' declarator __attribute__((deprecated(message))) ^ This commit updates the code to use the maybe versions. PR-URL: https://github.com/nodejs/node/pull/24216 Reviewed-By: Michaël Zasso Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig --- doc/api/addons.md | 46 ++++++++++++++----- test/addons/dlopen-ping-pong/binding.cc | 4 +- test/addons/heap-profiler/binding.cc | 3 +- test/addons/hello-world-esm/binding.cc | 3 +- .../hello-world-function-export/binding.cc | 3 +- test/addons/hello-world/binding.cc | 3 +- test/addons/load-long-path/binding.cc | 3 +- test/addons/new-target/binding.cc | 3 +- test/addons/openssl-binding/binding.cc | 3 +- test/addons/symlinked-module/binding.cc | 3 +- test/addons/zlib-binding/binding.cc | 3 +- 11 files changed, 56 insertions(+), 21 deletions(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index 757f24c5194271..e2530acb77d5e0 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -63,13 +63,15 @@ namespace demo { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; void Method(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(String::NewFromUtf8( + isolate, "world", NewStringType::kNormal).ToLocalChecked()); } void Initialize(Local exports) { @@ -464,6 +466,7 @@ using v8::Exception; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::String; @@ -479,14 +482,18 @@ void Add(const FunctionCallbackInfo& args) { if (args.Length() < 2) { // Throw an Error that is passed back to JavaScript isolate->ThrowException(Exception::TypeError( - String::NewFromUtf8(isolate, "Wrong number of arguments"))); + String::NewFromUtf8(isolate, + "Wrong number of arguments", + NewStringType::kNormal).ToLocalChecked())); return; } // Check the argument types if (!args[0]->IsNumber() || !args[1]->IsNumber()) { isolate->ThrowException(Exception::TypeError( - String::NewFromUtf8(isolate, "Wrong arguments"))); + String::NewFromUtf8(isolate, + "Wrong arguments", + NewStringType::kNormal).ToLocalChecked())); return; } @@ -534,6 +541,7 @@ using v8::Function; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Null; using v8::Object; using v8::String; @@ -543,7 +551,10 @@ void RunCallback(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); Local cb = Local::Cast(args[0]); const unsigned argc = 1; - Local argv[argc] = { String::NewFromUtf8(isolate, "hello world") }; + Local argv[argc] = { + String::NewFromUtf8(isolate, + "hello world", + NewStringType::kNormal).ToLocalChecked() }; cb->Call(Null(isolate), argc, argv); } @@ -591,6 +602,7 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; @@ -600,7 +612,9 @@ void CreateObject(const FunctionCallbackInfo& args) { Local context = isolate->GetCurrentContext(); Local obj = Object::New(isolate); - obj->Set(String::NewFromUtf8(isolate, "msg"), + obj->Set(String::NewFromUtf8(isolate, + "msg", + NewStringType::kNormal).ToLocalChecked(), args[0]->ToString(context).ToLocalChecked()); args.GetReturnValue().Set(obj); @@ -644,13 +658,15 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; void MyFunction(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world")); + args.GetReturnValue().Set(String::NewFromUtf8( + isolate, "hello world", NewStringType::kNormal).ToLocalChecked()); } void CreateFunction(const FunctionCallbackInfo& args) { @@ -661,7 +677,8 @@ void CreateFunction(const FunctionCallbackInfo& args) { Local fn = tpl->GetFunction(context).ToLocalChecked(); // omit this to make it anonymous - fn->SetName(String::NewFromUtf8(isolate, "theFunction")); + fn->SetName(String::NewFromUtf8( + isolate, "theFunction", NewStringType::kNormal).ToLocalChecked()); args.GetReturnValue().Set(fn); } @@ -757,6 +774,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::Persistent; @@ -776,7 +794,8 @@ void MyObject::Init(Local exports) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); + tpl->SetClassName(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype @@ -784,7 +803,8 @@ void MyObject::Init(Local exports) { Local context = isolate->GetCurrentContext(); constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked()); - exports->Set(String::NewFromUtf8(isolate, "MyObject"), + exports->Set(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(), tpl->GetFunction(context).ToLocalChecked()); } @@ -952,6 +972,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Number; using v8::Object; using v8::Persistent; @@ -969,7 +990,8 @@ MyObject::~MyObject() { void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); + tpl->SetClassName(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype @@ -1167,6 +1189,7 @@ using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::Persistent; using v8::String; @@ -1183,7 +1206,8 @@ MyObject::~MyObject() { void MyObject::Init(Isolate* isolate) { // Prepare constructor template Local tpl = FunctionTemplate::New(isolate, New); - tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject")); + tpl->SetClassName(String::NewFromUtf8( + isolate, "MyObject", NewStringType::kNormal).ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); Local context = isolate->GetCurrentContext(); diff --git a/test/addons/dlopen-ping-pong/binding.cc b/test/addons/dlopen-ping-pong/binding.cc index a3b9af1b8099a3..6a6c297b52fff9 100644 --- a/test/addons/dlopen-ping-pong/binding.cc +++ b/test/addons/dlopen-ping-pong/binding.cc @@ -15,6 +15,7 @@ using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; +using v8::NewStringType; using v8::String; using v8::Value; @@ -33,7 +34,8 @@ void LoadLibrary(const FunctionCallbackInfo& args) { void Ping(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); assert(ping_func != nullptr); - args.GetReturnValue().Set(String::NewFromUtf8(isolate, ping_func())); + args.GetReturnValue().Set(String::NewFromUtf8( + isolate, ping_func(), NewStringType::kNormal).ToLocalChecked()); } void init(Local exports) { diff --git a/test/addons/heap-profiler/binding.cc b/test/addons/heap-profiler/binding.cc index 861fb5a80c4651..29f58a5920825a 100644 --- a/test/addons/heap-profiler/binding.cc +++ b/test/addons/heap-profiler/binding.cc @@ -19,7 +19,8 @@ inline void Test(const v8::FunctionCallbackInfo& args) { inline void Initialize(v8::Local binding) { v8::Isolate* const isolate = binding->GetIsolate(); v8::Local context = isolate->GetCurrentContext(); - binding->Set(v8::String::NewFromUtf8(isolate, "test"), + binding->Set(v8::String::NewFromUtf8( + isolate, "test", v8::NewStringType::kNormal).ToLocalChecked(), v8::FunctionTemplate::New(isolate, Test) ->GetFunction(context) .ToLocalChecked()); diff --git a/test/addons/hello-world-esm/binding.cc b/test/addons/hello-world-esm/binding.cc index 944f5631956d15..02eecec099807a 100644 --- a/test/addons/hello-world-esm/binding.cc +++ b/test/addons/hello-world-esm/binding.cc @@ -3,7 +3,8 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(v8::String::NewFromUtf8( + isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); } void init(v8::Local exports) { diff --git a/test/addons/hello-world-function-export/binding.cc b/test/addons/hello-world-function-export/binding.cc index 55d64b3d6c3513..e5476c4ee1e364 100644 --- a/test/addons/hello-world-function-export/binding.cc +++ b/test/addons/hello-world-function-export/binding.cc @@ -3,7 +3,8 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(v8::String::NewFromUtf8( + isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); } void init(v8::Local exports, v8::Local module) { diff --git a/test/addons/hello-world/binding.cc b/test/addons/hello-world/binding.cc index 341b58f9a640d8..81bcbc29c78645 100644 --- a/test/addons/hello-world/binding.cc +++ b/test/addons/hello-world/binding.cc @@ -3,7 +3,8 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(v8::String::NewFromUtf8( + isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); } // Not using the full NODE_MODULE_INIT() macro here because we want to test the diff --git a/test/addons/load-long-path/binding.cc b/test/addons/load-long-path/binding.cc index 944f5631956d15..02eecec099807a 100644 --- a/test/addons/load-long-path/binding.cc +++ b/test/addons/load-long-path/binding.cc @@ -3,7 +3,8 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(v8::String::NewFromUtf8( + isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); } void init(v8::Local exports) { diff --git a/test/addons/new-target/binding.cc b/test/addons/new-target/binding.cc index 21b932ae018dfd..c2777c831e484a 100644 --- a/test/addons/new-target/binding.cc +++ b/test/addons/new-target/binding.cc @@ -12,7 +12,8 @@ inline void NewClass(const v8::FunctionCallbackInfo& args) { inline void Initialize(v8::Local binding) { auto isolate = binding->GetIsolate(); auto context = isolate->GetCurrentContext(); - binding->Set(v8::String::NewFromUtf8(isolate, "Class"), + binding->Set(v8::String::NewFromUtf8( + isolate, "Class", v8::NewStringType::kNormal).ToLocalChecked(), v8::FunctionTemplate::New(isolate, NewClass) ->GetFunction(context) .ToLocalChecked()); diff --git a/test/addons/openssl-binding/binding.cc b/test/addons/openssl-binding/binding.cc index bb00f1e176d7ce..122d420bc14e0b 100644 --- a/test/addons/openssl-binding/binding.cc +++ b/test/addons/openssl-binding/binding.cc @@ -22,7 +22,8 @@ inline void Initialize(v8::Local exports, v8::Local module, v8::Local context) { auto isolate = context->GetIsolate(); - auto key = v8::String::NewFromUtf8(isolate, "randomBytes"); + auto key = v8::String::NewFromUtf8( + isolate, "randomBytes", v8::NewStringType::kNormal).ToLocalChecked(); auto value = v8::FunctionTemplate::New(isolate, RandomBytes) ->GetFunction(context) .ToLocalChecked(); diff --git a/test/addons/symlinked-module/binding.cc b/test/addons/symlinked-module/binding.cc index 944f5631956d15..02eecec099807a 100644 --- a/test/addons/symlinked-module/binding.cc +++ b/test/addons/symlinked-module/binding.cc @@ -3,7 +3,8 @@ void Method(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "world")); + args.GetReturnValue().Set(v8::String::NewFromUtf8( + isolate, "world", v8::NewStringType::kNormal).ToLocalChecked()); } void init(v8::Local exports) { diff --git a/test/addons/zlib-binding/binding.cc b/test/addons/zlib-binding/binding.cc index 1d0af911115359..0b82de211a8430 100644 --- a/test/addons/zlib-binding/binding.cc +++ b/test/addons/zlib-binding/binding.cc @@ -45,7 +45,8 @@ inline void Initialize(v8::Local exports, v8::Local module, v8::Local context) { auto isolate = context->GetIsolate(); - auto key = v8::String::NewFromUtf8(isolate, "compressBytes"); + auto key = v8::String::NewFromUtf8( + isolate, "compressBytes", v8::NewStringType::kNormal).ToLocalChecked(); auto value = v8::FunctionTemplate::New(isolate, CompressBytes) ->GetFunction(context) .ToLocalChecked(); From 8b0626c836b228133d3424620748b29710726be0 Mon Sep 17 00:00:00 2001 From: Artur Daschevici Date: Tue, 6 Nov 2018 17:11:18 +0000 Subject: [PATCH 153/249] test: add coverage for escape key switch case PR-URL: https://github.com/nodejs/node/pull/24194 Reviewed-By: Anna Henningsen Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater --- test/parallel/test-readline-keys.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/parallel/test-readline-keys.js b/test/parallel/test-readline-keys.js index f739999110b12f..c5b3cbf44cd496 100644 --- a/test/parallel/test-readline-keys.js +++ b/test/parallel/test-readline-keys.js @@ -108,6 +108,11 @@ addTest('\b\x7f\x1b\b\x1b\x7f \x1b ', [ { name: 'space', sequence: '\x1b ', meta: true }, ]); +// escape key +addTest('\x1b\x1b\x1b', [ + { name: 'escape', sequence: '\x1b\x1b\x1b', meta: true }, +]); + // control keys addTest('\x01\x0b\x10', [ { name: 'a', sequence: '\x01', ctrl: true }, From 4a69d218b6a255480e1656d1b7b4dccf3ba63cd6 Mon Sep 17 00:00:00 2001 From: razvanbh Date: Wed, 7 Nov 2018 13:08:27 +0200 Subject: [PATCH 154/249] test: add test for 'ERR_INVALID_CALLBACK' PR-URL: https://github.com/nodejs/node/pull/24224 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater --- test/sequential/test-inspector-module.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/sequential/test-inspector-module.js b/test/sequential/test-inspector-module.js index eaecd49c982311..26bb7fe9262889 100644 --- a/test/sequential/test-inspector-module.js +++ b/test/sequential/test-inspector-module.js @@ -46,6 +46,17 @@ session.post('Runtime.evaluate', { expression: '2 + 2' }); ); }); +[1, 'a', {}, [], true, Infinity].forEach((i) => { + common.expectsError( + () => session.post('test', {}, i), + { + code: 'ERR_INVALID_CALLBACK', + type: TypeError, + message: 'Callback must be a function' + } + ); +}); + common.expectsError( () => session.connect(), { From 8de1030a70c4047f03e570e28c4364a1fe830345 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 6 Nov 2018 10:21:43 +0000 Subject: [PATCH 155/249] tracing: fix static destruction order issue Sometimes, the `parallel/test-tracing-no-crash` would not work as expected, at least on Windows, because there is a static destruction race between tearing down the `NodeTraceWriter` instance and the per-process options struct. If the per-process options were destroyed before the `NodeTraceWriter`, the reference to the tracing filename would be gone before opening the file was attempted. This can be solved by creating a copy of the string when creating the `NodeTraceWriter` instance rather than taking a reference. Fixes: https://github.com/nodejs/node/issues/22523 PR-URL: https://github.com/nodejs/node/pull/24123 Reviewed-By: Refael Ackermann Reviewed-By: Ben Noordhuis Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung --- src/tracing/node_trace_writer.h | 2 +- test/parallel/test-tracing-no-crash.js | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h index 5e5781479c689f..a91176ad4905a9 100644 --- a/src/tracing/node_trace_writer.h +++ b/src/tracing/node_trace_writer.h @@ -61,7 +61,7 @@ class NodeTraceWriter : public AsyncTraceWriter { int highest_request_id_completed_ = 0; int total_traces_ = 0; int file_num_ = 0; - const std::string& log_file_pattern_; + std::string log_file_pattern_; std::ostringstream stream_; std::unique_ptr json_trace_writer_; bool exited_ = false; diff --git a/test/parallel/test-tracing-no-crash.js b/test/parallel/test-tracing-no-crash.js index 5b11522911e75d..0ae402f5288cca 100644 --- a/test/parallel/test-tracing-no-crash.js +++ b/test/parallel/test-tracing-no-crash.js @@ -8,7 +8,15 @@ function CheckNoSignalAndErrorCodeOne(code, signal) { assert.strictEqual(code, 1); } -const child = spawn(process.execPath, - ['--trace-event-categories', 'madeup', '-e', - 'throw new Error()'], { stdio: 'inherit' }); +const child = spawn(process.execPath, [ + '--trace-event-categories', 'madeup', '-e', 'throw new Error()' +], { stdio: [ 'inherit', 'inherit', 'pipe' ] }); child.on('exit', common.mustCall(CheckNoSignalAndErrorCodeOne)); + +let stderr; +child.stderr.setEncoding('utf8'); +child.stderr.on('data', (chunk) => stderr += chunk); +child.stderr.on('end', common.mustCall(() => { + assert(stderr.includes('throw new Error()'), stderr); + assert(!stderr.includes('Could not open trace file'), stderr); +})); From b5b5f9f8bdbe1e3b24da9b5dc54665bb2469777f Mon Sep 17 00:00:00 2001 From: Grant Carthew Date: Tue, 6 Nov 2018 08:40:22 +1000 Subject: [PATCH 156/249] doc: fix code examples in stream.md * Replace `console.error()` with `console.log()`. * Fix case and punctuation in logged output. PR-URL: https://github.com/nodejs/node/pull/24112 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Vse Mozhet Byt --- doc/api/stream.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/api/stream.md b/doc/api/stream.md index 2f35ec30b5bde8..8d317191091207 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -291,7 +291,7 @@ for (let i = 0; i < 100; i++) { } writer.end('This is the end\n'); writer.on('finish', () => { - console.error('All writes are now complete.'); + console.log('All writes are now complete.'); }); ``` @@ -309,7 +309,7 @@ a readable stream, adding this writable to its set of destinations. const writer = getWritableStreamSomehow(); const reader = getReadableStreamSomehow(); writer.on('pipe', (src) => { - console.error('something is piping into the writer'); + console.log('Something is piping into the writer.'); assert.equal(src, reader); }); reader.pipe(writer); @@ -334,7 +334,7 @@ This is also emitted in case this [`Writable`][] stream emits an error when a const writer = getWritableStreamSomehow(); const reader = getReadableStreamSomehow(); writer.on('unpipe', (src) => { - console.error('Something has stopped piping into the writer.'); + console.log('Something has stopped piping into the writer.'); assert.equal(src, reader); }); reader.pipe(writer); @@ -551,7 +551,7 @@ function write(data, cb) { // Wait for cb to be called before doing any other write. write('hello', () => { - console.log('write completed, do more writes now'); + console.log('Write completed, do more writes now.'); }); ``` @@ -1091,7 +1091,7 @@ const readable = getReadableStreamSomehow(); readable.setEncoding('utf8'); readable.on('data', (chunk) => { assert.equal(typeof chunk, 'string'); - console.log('got %d characters of string data', chunk.length); + console.log('Got %d characters of string data:', chunk.length); }); ``` @@ -1119,9 +1119,9 @@ const writable = fs.createWriteStream('file.txt'); // but only for the first second readable.pipe(writable); setTimeout(() => { - console.log('Stop writing to file.txt'); + console.log('Stop writing to file.txt.'); readable.unpipe(writable); - console.log('Manually close the file stream'); + console.log('Manually close the file stream.'); writable.end(); }, 1000); ``` @@ -1338,9 +1338,9 @@ const rs = fs.createReadStream('archive.tar'); finished(rs, (err) => { if (err) { - console.error('Stream failed', err); + console.error('Stream failed.', err); } else { - console.log('Stream is done reading'); + console.log('Stream is done reading.'); } }); @@ -1360,7 +1360,7 @@ const rs = fs.createReadStream('archive.tar'); async function run() { await finished(rs); - console.log('Stream is done reading'); + console.log('Stream is done reading.'); } run().catch(console.error); @@ -1395,9 +1395,9 @@ pipeline( fs.createWriteStream('archive.tar.gz'), (err) => { if (err) { - console.error('Pipeline failed', err); + console.error('Pipeline failed.', err); } else { - console.log('Pipeline succeeded'); + console.log('Pipeline succeeded.'); } } ); @@ -1414,7 +1414,7 @@ async function run() { zlib.createGzip(), fs.createWriteStream('archive.tar.gz') ); - console.log('Pipeline succeeded'); + console.log('Pipeline succeeded.'); } run().catch(console.error); From bc97b62f35df86a632f349d6b34f2c7549fa8e2d Mon Sep 17 00:00:00 2001 From: Alex Seifert Date: Tue, 6 Nov 2018 14:51:20 +0000 Subject: [PATCH 157/249] test: fix order of arguments in assert.strictEqual PR-URL: https://github.com/nodejs/node/pull/24145 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater --- test/parallel/test-buffer-indexof.js | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/parallel/test-buffer-indexof.js b/test/parallel/test-buffer-indexof.js index d7e34b66d2b3b3..3647d115b0dc5b 100644 --- a/test/parallel/test-buffer-indexof.js +++ b/test/parallel/test-buffer-indexof.js @@ -505,20 +505,20 @@ assert.strictEqual(buf_bc.lastIndexOf(Buffer.from('你好'), 7), -1); // Test lastIndexOf on a longer buffer: const bufferString = Buffer.from('a man a plan a canal panama'); -assert.strictEqual(15, bufferString.lastIndexOf('canal')); -assert.strictEqual(21, bufferString.lastIndexOf('panama')); -assert.strictEqual(0, bufferString.lastIndexOf('a man a plan a canal panama')); +assert.strictEqual(bufferString.lastIndexOf('canal'), 15); +assert.strictEqual(bufferString.lastIndexOf('panama'), 21); +assert.strictEqual(bufferString.lastIndexOf('a man a plan a canal panama'), 0); assert.strictEqual(-1, bufferString.lastIndexOf('a man a plan a canal mexico')); assert.strictEqual(-1, bufferString .lastIndexOf('a man a plan a canal mexico city')); assert.strictEqual(-1, bufferString.lastIndexOf(Buffer.from('a'.repeat(1000)))); -assert.strictEqual(0, bufferString.lastIndexOf('a man a plan', 4)); -assert.strictEqual(13, bufferString.lastIndexOf('a ')); -assert.strictEqual(13, bufferString.lastIndexOf('a ', 13)); -assert.strictEqual(6, bufferString.lastIndexOf('a ', 12)); -assert.strictEqual(0, bufferString.lastIndexOf('a ', 5)); -assert.strictEqual(13, bufferString.lastIndexOf('a ', -1)); -assert.strictEqual(0, bufferString.lastIndexOf('a ', -27)); +assert.strictEqual(bufferString.lastIndexOf('a man a plan', 4), 0); +assert.strictEqual(bufferString.lastIndexOf('a '), 13); +assert.strictEqual(bufferString.lastIndexOf('a ', 13), 13); +assert.strictEqual(bufferString.lastIndexOf('a ', 12), 6); +assert.strictEqual(bufferString.lastIndexOf('a ', 5), 0); +assert.strictEqual(bufferString.lastIndexOf('a ', -1), 13); +assert.strictEqual(bufferString.lastIndexOf('a ', -27), 0); assert.strictEqual(-1, bufferString.lastIndexOf('a ', -28)); // Test lastIndexOf for the case that the first character can be found, @@ -534,18 +534,18 @@ assert.strictEqual(-1, Buffer.from('bc').lastIndexOf(Buffer.from('ab'))); assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf('ab', 'ucs2')); assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf(abInUCS2)); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab')); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 1)); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 2)); -assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 3)); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab'), 0); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 1), 0); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 2), 0); +assert.strictEqual(Buffer.from('abc').lastIndexOf('ab', 3), 0); // The above tests test the LINEAR and SINGLE-CHAR strategies. // Now, we test the BOYER-MOORE-HORSPOOL strategy. // Test lastIndexOf on a long buffer w multiple matches: pattern = 'JABACABADABACABA'; -assert.strictEqual(1535, longBufferString.lastIndexOf(pattern)); -assert.strictEqual(1535, longBufferString.lastIndexOf(pattern, 1535)); -assert.strictEqual(511, longBufferString.lastIndexOf(pattern, 1534)); +assert.strictEqual(longBufferString.lastIndexOf(pattern), 1535); +assert.strictEqual(longBufferString.lastIndexOf(pattern, 1535), 1535); +assert.strictEqual(longBufferString.lastIndexOf(pattern, 1534), 511); // Finally, give it a really long input to trigger fallback from BMH to // regular BOYER-MOORE (which has better worst-case complexity). @@ -567,19 +567,19 @@ for (let i = 0; i < 1000000; i++) { parts.push((countBits(i) % 2 === 0) ? 'yolo' : 'swag'); } const reallyLong = Buffer.from(parts.join(' ')); -assert.strictEqual('yolo swag swag yolo', reallyLong.slice(0, 19).toString()); +assert.strictEqual(reallyLong.slice(0, 19).toString(), 'yolo swag swag yolo'); // Expensive reverse searches. Stress test lastIndexOf: pattern = reallyLong.slice(0, 100000); // First 1/50th of the pattern. -assert.strictEqual(4751360, reallyLong.lastIndexOf(pattern)); -assert.strictEqual(3932160, reallyLong.lastIndexOf(pattern, 4000000)); -assert.strictEqual(2949120, reallyLong.lastIndexOf(pattern, 3000000)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 4751360); +assert.strictEqual(reallyLong.lastIndexOf(pattern, 4000000), 3932160); +assert.strictEqual(reallyLong.lastIndexOf(pattern, 3000000), 2949120); pattern = reallyLong.slice(100000, 200000); // Second 1/50th. -assert.strictEqual(4728480, reallyLong.lastIndexOf(pattern)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 4728480); pattern = reallyLong.slice(0, 1000000); // First 1/5th. -assert.strictEqual(3932160, reallyLong.lastIndexOf(pattern)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 3932160); pattern = reallyLong.slice(0, 2000000); // first 2/5ths. -assert.strictEqual(0, reallyLong.lastIndexOf(pattern)); +assert.strictEqual(reallyLong.lastIndexOf(pattern), 0); // test truncation of Number arguments to uint8 { From b16e485910f669a77a15bb4f4f1feee21c04ab6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Amer=20Alimanovi=C4=87?= Date: Tue, 6 Nov 2018 17:46:28 +0000 Subject: [PATCH 158/249] test: add coverage for systemerror set name PR-URL: https://github.com/nodejs/node/pull/24200 Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater --- test/parallel/test-errors-systemerror.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/parallel/test-errors-systemerror.js b/test/parallel/test-errors-systemerror.js index 957a0dd7b22196..0b5f9b9a107d59 100644 --- a/test/parallel/test-errors-systemerror.js +++ b/test/parallel/test-errors-systemerror.js @@ -111,3 +111,25 @@ const { ERR_TEST } = codes; assert.strictEqual(err.path, 'path'); assert.strictEqual(err.dest, 'path'); } + +{ + const ctx = { + code: 'ERR_TEST', + message: 'Error occurred', + syscall: 'syscall_test' + }; + assert.throws( + () => { + const err = new ERR_TEST(ctx); + err.name = 'SystemError [CUSTOM_ERR_TEST]'; + throw err; + }, + { + code: 'ERR_TEST', + name: 'SystemError [CUSTOM_ERR_TEST]', + message: 'custom message: syscall_test returned ERR_TEST ' + + '(Error occurred)', + info: ctx + } + ); +} From 825f0dda5b4eb8637457d3cb810a2c8fa3c1ad2b Mon Sep 17 00:00:00 2001 From: Nikita Malyschkin Date: Wed, 7 Nov 2018 10:10:12 +0100 Subject: [PATCH 159/249] test: add test for strictDeepEqual PR-URL: https://github.com/nodejs/node/pull/24197 Reviewed-By: Ruben Bridgewater Reviewed-By: Daijiro Wachi --- test/parallel/test-util-isDeepStrictEqual.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/parallel/test-util-isDeepStrictEqual.js b/test/parallel/test-util-isDeepStrictEqual.js index 938781a43084a5..fd585f7ccf0f1e 100644 --- a/test/parallel/test-util-isDeepStrictEqual.js +++ b/test/parallel/test-util-isDeepStrictEqual.js @@ -459,10 +459,13 @@ utilIsDeepStrict(-0, -0); const obj1 = { [symbol1]: 1 }; const obj2 = { [symbol1]: 1 }; const obj3 = { [Symbol()]: 1 }; + const obj4 = { }; // Add a non enumerable symbol as well. It is going to be ignored! Object.defineProperty(obj2, Symbol(), { value: 1 }); + Object.defineProperty(obj4, symbol1, { value: 1 }); notUtilIsDeepStrict(obj1, obj3); utilIsDeepStrict(obj1, obj2); + notUtilIsDeepStrict(obj1, obj4); // TypedArrays have a fast path. Test for this as well. const a = new Uint8Array(4); const b = new Uint8Array(4); From 6f80a45528479f255c2fd25e82ce012ffb70c50c Mon Sep 17 00:00:00 2001 From: Paul Isache Date: Tue, 6 Nov 2018 15:57:45 +0000 Subject: [PATCH 160/249] lib: combine contructor, tag, Object into a function combine these parts into a function to be used in multiple parts PR-URL: https://github.com/nodejs/node/pull/24171 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater --- lib/internal/util/inspect.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 4cff372b330ec1..ca06064085422c 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -400,6 +400,10 @@ function getKeys(value, showHidden) { return keys; } +function getCtxStyle(constructor, tag) { + return constructor || tag || 'Object'; +} + function formatProxy(ctx, proxy, recurseTimes) { if (recurseTimes != null) { if (recurseTimes < 0) @@ -741,7 +745,7 @@ function formatRaw(ctx, value, recurseTimes) { if (recurseTimes != null) { if (recurseTimes < 0) - return ctx.stylize(`[${constructor || tag || 'Object'}]`, 'special'); + return ctx.stylize(`[${getCtxStyle(constructor, tag)}]`, 'special'); recurseTimes -= 1; } @@ -793,7 +797,7 @@ function handleMaxCallStackSize(ctx, err, constructor, tag, indentationLvl) { ctx.seen.pop(); ctx.indentationLvl = indentationLvl; return ctx.stylize( - `[${constructor || tag || 'Object'}: Inspection interrupted ` + + `[${getCtxStyle(constructor, tag)}: Inspection interrupted ` + 'prematurely. Maximum call stack size exceeded.]', 'special' ); From 2b0410a3ef9750db7e078d70bc9632bdb2bab938 Mon Sep 17 00:00:00 2001 From: "ivan.filenko" Date: Mon, 15 Oct 2018 20:04:29 +0300 Subject: [PATCH 161/249] test: use assert.strictEqual instead of assert.equal PR-URL: https://github.com/nodejs/node/pull/23673 Reviewed-By: Ruben Bridgewater Reviewed-By: Refael Ackermann --- test/pseudo-tty/test-tty-get-color-depth.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/pseudo-tty/test-tty-get-color-depth.js b/test/pseudo-tty/test-tty-get-color-depth.js index d802add1189db2..e735f4c286aeb3 100644 --- a/test/pseudo-tty/test-tty-get-color-depth.js +++ b/test/pseudo-tty/test-tty-get-color-depth.js @@ -10,7 +10,7 @@ const writeStream = new WriteStream(fd); { const depth = writeStream.getColorDepth(); - assert.equal(typeof depth, 'number'); + assert.strictEqual(typeof depth, 'number'); assert(depth >= 1 && depth <= 24); } @@ -44,7 +44,7 @@ const writeStream = new WriteStream(fd); [{ TERM: 'dumb', COLORTERM: '1' }, 4], ].forEach(([env, depth], i) => { const actual = writeStream.getColorDepth(env); - assert.equal( + assert.strictEqual( actual, depth, `i: ${i}, expected: ${depth}, actual: ${actual}, env: ${env}` @@ -57,8 +57,8 @@ const writeStream = new WriteStream(fd); const [ value, depth1, depth2 ] = process.platform !== 'win32' ? ['win32', 1, 4] : ['linux', 4, 1]; - assert.equal(writeStream.getColorDepth({}), depth1); + assert.strictEqual(writeStream.getColorDepth({}), depth1); Object.defineProperty(process, 'platform', { value }); - assert.equal(writeStream.getColorDepth({}), depth2); + assert.strictEqual(writeStream.getColorDepth({}), depth2); Object.defineProperty(process, 'platform', platform); } From 9af7ad592c224918b096c975894e0d43fa51ab8e Mon Sep 17 00:00:00 2001 From: "ivan.filenko" Date: Mon, 15 Oct 2018 20:32:30 +0300 Subject: [PATCH 162/249] test: fix uses of deprecated assert.fail with multiple args PR-URL: https://github.com/nodejs/node/pull/23673 Reviewed-By: Ruben Bridgewater Reviewed-By: Refael Ackermann --- test/async-hooks/init-hooks.js | 3 +-- test/parallel/test-net-connect-options-fd.js | 4 ++-- test/parallel/test-string-decoder.js | 2 +- test/pseudo-tty/test-tty-get-color-depth.js | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/test/async-hooks/init-hooks.js b/test/async-hooks/init-hooks.js index 14969d8e753b68..817b2db0c781b4 100644 --- a/test/async-hooks/init-hooks.js +++ b/test/async-hooks/init-hooks.js @@ -120,8 +120,7 @@ class ActivityCollector { } if (violations.length) { console.error(violations.join('\n\n') + '\n'); - assert.fail(violations.length, 0, - `${violations.length} failed sanity checks`); + assert.fail(`${violations.length} failed sanity checks`); } } diff --git a/test/parallel/test-net-connect-options-fd.js b/test/parallel/test-net-connect-options-fd.js index 468e230ec7370a..94b831bf5d2ac3 100644 --- a/test/parallel/test-net-connect-options-fd.js +++ b/test/parallel/test-net-connect-options-fd.js @@ -70,7 +70,7 @@ const forAllClients = (cb) => common.mustCall(cb, CLIENT_VARIANTS); }) .on('error', function(err) { console.error(err); - assert.fail(null, null, `[Pipe server]${err}`); + assert.fail(`[Pipe server]${err}`); }) .listen({ path: serverPath }, common.mustCall(function serverOnListen() { const getSocketOpt = (index) => { @@ -94,7 +94,7 @@ const forAllClients = (cb) => common.mustCall(cb, CLIENT_VARIANTS); console.error(`[Pipe]Sending data through fd ${oldHandle.fd}`); this.on('error', function(err) { console.error(err); - assert.fail(null, null, `[Pipe Client]${err}`); + assert.fail(`[Pipe Client]${err}`); }); }); diff --git a/test/parallel/test-string-decoder.js b/test/parallel/test-string-decoder.js index 04e1d8c8fe2849..c043795fc6ee5e 100644 --- a/test/parallel/test-string-decoder.js +++ b/test/parallel/test-string-decoder.js @@ -228,7 +228,7 @@ function test(encoding, input, expected, singleSequence) { `input: ${input.toString('hex').match(hexNumberRE)}\n` + `Write sequence: ${JSON.stringify(sequence)}\n` + `Full Decoder State: ${inspect(decoder)}`; - assert.fail(output, expected, message); + assert.fail(message); } }); } diff --git a/test/pseudo-tty/test-tty-get-color-depth.js b/test/pseudo-tty/test-tty-get-color-depth.js index e735f4c286aeb3..d4062f5fdb6d39 100644 --- a/test/pseudo-tty/test-tty-get-color-depth.js +++ b/test/pseudo-tty/test-tty-get-color-depth.js @@ -2,7 +2,6 @@ const common = require('../common'); const assert = require('assert').strict; -/* eslint-disable no-restricted-properties */ const { WriteStream } = require('tty'); const fd = common.getTTYfd(); From 118d8d0febb025a2f0346ac75bbf9626c7cef33b Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 7 Nov 2018 22:43:45 -0800 Subject: [PATCH 163/249] doc: edit BUILDING.md Minor edits to BUILDING.md to keep sentences short and clear. PR-URL: https://github.com/nodejs/node/pull/24243 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann --- BUILDING.md | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 462e7b4a0104b6..63ddf8e7f4ff2a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -70,8 +70,7 @@ There are three support tiers: ### Supported platforms The community does not build or test against end-of-life distributions (EoL). -Thus, we do not recommend that you use Node.js on end-of-life or unsupported -platforms in production. +For production applications, run Node.js on supported platforms only. | System | Support type | Version | Architectures | Notes | | ------------ | ------------ | ------------------------------- | ---------------- | ----------------------------- | @@ -135,21 +134,20 @@ OpenSSL-1.1.0 requires the following assembler version for use of asm support on x86_64 and ia32. * gas (GNU assembler) version 2.23 or higher -* xcode version 5.0 or higher +* Xcode version 5.0 or higher * llvm version 3.3 or higher * nasm version 2.10 or higher in Windows -Otherwise `configure` will fail with an error. This can be avoided by -either providing a newer assembler as per the list above or by -using the `--openssl-no-asm` flag. +If compiling without one of the above, use `configure` with the +`--openssl-no-asm` flag. Otherwise, `configure` will fail. The forthcoming OpenSSL-1.1.1 will have different requirements. Please refer to https://www.openssl.org/docs/man1.1.1/man3/OPENSSL_ia32cap.html for details. ## Building Node.js on supported platforms -*Note:* All prerequisites can be easily installed by following -[this bootstrapping guide](https://github.com/nodejs/node/blob/master/tools/bootstrap/README.md). +The [bootstrapping guide](https://github.com/nodejs/node/blob/master/tools/bootstrap/README.md) +explains how to install all prerequisites. ### Unix/macOS @@ -160,7 +158,7 @@ The forthcoming OpenSSL-1.1.1 will have different requirements. Please refer to * Python 2.6 or 2.7 * GNU Make 3.81 or newer -On macOS, you will need to install the `Xcode Command Line Tools` by running +On macOS, install the `Xcode Command Line Tools` by running `xcode-select --install`. Alternatively, if you already have the full Xcode installed, you can find them under the menu `Xcode -> Open Developer Tool -> More Developer Tools...`. This step will install `clang`, `clang++`, and @@ -181,13 +179,9 @@ $ ./configure $ make -j4 ``` -Running `make` with the `-j4` flag will cause it to run 4 compilation jobs -concurrently which may significantly reduce build time. The number after `-j` -can be changed to best suit the number of processor cores on your machine. If -you run into problems running `make` with concurrency, try running it without -the `-j4` flag. See the -[GNU Make Documentation](https://www.gnu.org/software/make/manual/html_node/Parallel.html) -for more information. +The `-j4` option will cause `make` to run 4 simultaneous compilation jobs which +may reduce build time. For more information, see the +[GNU Make Documentation](https://www.gnu.org/software/make/manual/html_node/Parallel.html). Note that the above requires that `python` resolve to Python 2.6 or 2.7 and not a newer version. From a05f2fc46ba065593493563cf972d2665fc8cd4f Mon Sep 17 00:00:00 2001 From: Marcus Scott Date: Tue, 16 Oct 2018 14:16:17 +0000 Subject: [PATCH 164/249] test: move test-fs-watch-system-limit from sequential to pummel PR-URL: https://github.com/nodejs/node/pull/23692 Reviewed-By: Anna Henningsen Reviewed-By: Rich Trott Reviewed-By: James M Snell --- test/{sequential => pummel}/test-fs-watch-system-limit.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/{sequential => pummel}/test-fs-watch-system-limit.js (100%) diff --git a/test/sequential/test-fs-watch-system-limit.js b/test/pummel/test-fs-watch-system-limit.js similarity index 100% rename from test/sequential/test-fs-watch-system-limit.js rename to test/pummel/test-fs-watch-system-limit.js From 838fb550c66e6175abe3460f86a1950353ff9f91 Mon Sep 17 00:00:00 2001 From: Refael Ackermann Date: Tue, 23 Oct 2018 16:51:42 -0400 Subject: [PATCH 165/249] build,tools: update make-v8.sh for s390x PR-URL: https://github.com/nodejs/node/pull/23839 Reviewed-By: Michael Dawson Reviewed-By: James M Snell --- tools/make-v8.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/tools/make-v8.sh b/tools/make-v8.sh index 4365412856d741..1bbf472aae7df2 100755 --- a/tools/make-v8.sh +++ b/tools/make-v8.sh @@ -1,9 +1,27 @@ -#!/bin/bash +#!/bin/bash -xe BUILD_ARCH_TYPE=$1 V8_BUILD_OPTIONS=$2 cd deps/v8 tools/node/fetch_deps.py . -PATH=~/_depot_tools:$PATH tools/dev/v8gen.py $BUILD_ARCH_TYPE --no-goma $V8_BUILD_OPTIONS -PATH=~/_depot_tools:$PATH ninja -C out.gn/$BUILD_ARCH_TYPE/ d8 cctest inspector-test + +if [ "`arch`" == "s390x" ] +then + # set paths manually for now to use locally installed gn + export BUILD_TOOLS=/home/iojs/build-tools + export LD_LIBRARY_PATH=$BUILD_TOOLS:$LD_LIBRARY_PATH + export PATH=$BUILD_TOOLS:$PATH + CXX_PATH=`which $CXX |grep g++` + rm -f "$BUILD_TOOLS/g++" + rm -f "$BUILD_TOOLS/gcc" + ln -s $CXX_PATH "$BUILD_TOOLS/g++" + ln -s $CXX_PATH "$BUILD_TOOLS/gcc" + g++ --version + export PKG_CONFIG_PATH=$BUILD_TOOLS/pkg-config + gn gen -v out.gn/$BUILD_ARCH_TYPE --args='is_component_build=false is_debug=false use_goma=false goma_dir="None" use_custom_libcxx=false v8_target_cpu="s390x" target_cpu="s390x"' + ninja -v -C out.gn/$BUILD_ARCH_TYPE d8 cctest inspector-test +else + PATH=~/_depot_tools:$PATH tools/dev/v8gen.py $BUILD_ARCH_TYPE --no-goma $V8_BUILD_OPTIONS + PATH=~/_depot_tools:$PATH ninja -C out.gn/$BUILD_ARCH_TYPE/ d8 cctest inspector-test +fi From 56cd911cadcb4fe0396830a9a1dc031df9a0dca7 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 5 Nov 2018 14:20:53 +0100 Subject: [PATCH 166/249] test: use NULL instead of 0 in common.h This commit updates the macros in test/addons-napi/common.h to use NULL instead of 0. This is very minor, but I had to look twice while going through the code and finding what the macro was doing and comparing with the struct definition. Using NULL makes it a little clearer I think. PR-URL: https://github.com/nodejs/node/pull/24104 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- test/addons-napi/common.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/addons-napi/common.h b/test/addons-napi/common.h index 422418ced49a39..b16f944771c1df 100644 --- a/test/addons-napi/common.h +++ b/test/addons-napi/common.h @@ -54,7 +54,7 @@ NAPI_CALL_BASE(env, the_call, NAPI_RETVAL_NOTHING) #define DECLARE_NAPI_PROPERTY(name, func) \ - { (name), 0, (func), 0, 0, 0, napi_default, 0 } + { (name), NULL, (func), NULL, NULL, NULL, napi_default, NULL } #define DECLARE_NAPI_GETTER(name, func) \ - { (name), 0, 0, (func), 0, 0, napi_default, 0 } + { (name), NULL, NULL, (func), NULL, NULL, napi_default, NULL } From 636e4e02a5de3359613d83d4a98b9ecdda3ad450 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sun, 4 Nov 2018 12:28:27 +0100 Subject: [PATCH 167/249] net: simplify Socket.prototype._final Remove conditions that should be irrelevant since we started using `_final`, as well as an extra `defaultTriggerAsyncIdScope()` call which is unnecessary because there is an equivalent scope already present on the native side. PR-URL: https://github.com/nodejs/node/pull/24075 Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/net.js | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/lib/net.js b/lib/net.js index a0597bb0a08d64..ae389940b39596 100644 --- a/lib/net.js +++ b/lib/net.js @@ -336,14 +336,6 @@ Socket.prototype._unrefTimer = function _unrefTimer() { }; -function shutdownSocket(self, callback) { - var req = new ShutdownWrap(); - req.oncomplete = afterShutdown; - req.handle = self._handle; - req.callback = callback; - return self._handle.shutdown(req); -} - // the user has called .end(), and all the bytes have been // sent out to the other side. Socket.prototype._final = function(cb) { @@ -353,23 +345,16 @@ Socket.prototype._final = function(cb) { return this.once('connect', () => this._final(cb)); } - if (!this.readable || this._readableState.ended) { - debug('_final: ended, destroy', this._readableState); - cb(); - return this.destroy(); - } + if (!this._handle) + return cb(); debug('_final: not ended, call shutdown()'); - // otherwise, just shutdown, or destroy() if not possible - if (!this._handle || !this._handle.shutdown) { - cb(); - return this.destroy(); - } - - var err = defaultTriggerAsyncIdScope( - this[async_id_symbol], shutdownSocket, this, cb - ); + var req = new ShutdownWrap(); + req.oncomplete = afterShutdown; + req.handle = this._handle; + req.callback = cb; + var err = this._handle.shutdown(req); if (err) return this.destroy(errnoException(err, 'shutdown')); @@ -388,7 +373,7 @@ function afterShutdown(status, handle) { if (self.destroyed) return; - if (self._readableState.ended) { + if (!self.readable || self._readableState.ended) { debug('readableState ended, destroying'); self.destroy(); } From ddbd0e197352cd1cd3c5e04a069765ad450b33d6 Mon Sep 17 00:00:00 2001 From: Berry de Witte Date: Tue, 6 Nov 2018 15:14:12 +0000 Subject: [PATCH 168/249] test: increase coverage internal readline PR-URL: https://github.com/nodejs/node/pull/24150 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- test/parallel/test-readline-keys.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-readline-keys.js b/test/parallel/test-readline-keys.js index c5b3cbf44cd496..b1c88e2acee157 100644 --- a/test/parallel/test-readline-keys.js +++ b/test/parallel/test-readline-keys.js @@ -99,11 +99,12 @@ addTest('\n\r\t', [ ]); // space and backspace -addTest('\b\x7f\x1b\b\x1b\x7f \x1b ', [ +addTest('\b\x7f\x1b\b\x1b\x7f\x1b\x1b \x1b ', [ { name: 'backspace', sequence: '\b' }, { name: 'backspace', sequence: '\x7f' }, { name: 'backspace', sequence: '\x1b\b', meta: true }, { name: 'backspace', sequence: '\x1b\x7f', meta: true }, + { name: 'space', sequence: '\x1b\x1b ', meta: true }, { name: 'space', sequence: ' ' }, { name: 'space', sequence: '\x1b ', meta: true }, ]); From 74451263a3cf38946060be81302afa8abc6f19be Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 10 Nov 2018 20:59:50 +0100 Subject: [PATCH 169/249] net: partially revert "simplify Socket.prototype._final" Partially revert b7e6ccd0cc60f20cc397e6ac0705bb3f38c7d225 because it broke a test that was added since its last CI run. Refs: https://github.com/nodejs/node/pull/24075 Refs: https://github.com/nodejs/node/pull/23866 PR-URL: https://github.com/nodejs/node/pull/24288 Reviewed-By: Colin Ihrig Reviewed-By: Ujjwal Sharma --- lib/net.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/net.js b/lib/net.js index ae389940b39596..1bcbe94c53ddb9 100644 --- a/lib/net.js +++ b/lib/net.js @@ -345,6 +345,12 @@ Socket.prototype._final = function(cb) { return this.once('connect', () => this._final(cb)); } + // TODO(addaleax): This should not be necessary. + if (!this.readable || this._readableState.ended) { + cb(); + return this.destroy(); + } + if (!this._handle) return cb(); From 13dee430cd7728fa1d403f71505803a11f3b62fa Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 3 Nov 2018 17:48:47 +0100 Subject: [PATCH 170/249] stream: make `.destroy()` interact better with write queue Make sure that it is safe to call the callback for `_write()` even in the presence of `.destroy()` calls during that write. In particular, letting the write queue continue processing would previously have thrown an exception, because processing writes after calling `.destroy()` is forbidden. One test had to be modified to account for the fact that callbacks for writes will now always be called, even when the stream is destroyed during the process. PR-URL: https://github.com/nodejs/node/pull/24062 Reviewed-By: Matteo Collina Reviewed-By: James M Snell --- lib/_stream_writable.js | 2 +- test/parallel/test-stream-write-destroy.js | 59 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-stream-write-destroy.js diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 160179cd0e84fa..d62c95ad800567 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -461,7 +461,7 @@ function onwrite(stream, er) { onwriteError(stream, state, sync, er, cb); else { // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); + var finished = needFinish(state) || stream.destroyed; if (!finished && !state.corked && diff --git a/test/parallel/test-stream-write-destroy.js b/test/parallel/test-stream-write-destroy.js new file mode 100644 index 00000000000000..83b329a6a8a7b3 --- /dev/null +++ b/test/parallel/test-stream-write-destroy.js @@ -0,0 +1,59 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const { Writable } = require('stream'); + +// Test interaction between calling .destroy() on a writable and pending +// writes. + +for (const withPendingData of [ false, true ]) { + for (const useEnd of [ false, true ]) { + const callbacks = []; + + const w = new Writable({ + write(data, enc, cb) { + callbacks.push(cb); + }, + // Effectively disable the HWM to observe 'drain' events more easily. + highWaterMark: 1 + }); + + let chunksWritten = 0; + let drains = 0; + let finished = false; + w.on('drain', () => drains++); + w.on('finish', () => finished = true); + + w.write('abc', () => chunksWritten++); + assert.strictEqual(chunksWritten, 0); + assert.strictEqual(drains, 0); + callbacks.shift()(); + assert.strictEqual(chunksWritten, 1); + assert.strictEqual(drains, 1); + + if (withPendingData) { + // Test 2 cases: There either is or is not data still in the write queue. + // (The second write will never actually get executed either way.) + w.write('def', () => chunksWritten++); + } + if (useEnd) { + // Again, test 2 cases: Either we indicate that we want to end the + // writable or not. + w.end('ghi', () => chunksWritten++); + } else { + w.write('ghi', () => chunksWritten++); + } + + assert.strictEqual(chunksWritten, 1); + w.destroy(); + assert.strictEqual(chunksWritten, 1); + callbacks.shift()(); + assert.strictEqual(chunksWritten, 2); + assert.strictEqual(callbacks.length, 0); + assert.strictEqual(drains, 1); + + // When we used `.end()`, we see the 'finished' event if and only if + // we actually finished processing the write queue. + assert.strictEqual(finished, !withPendingData && useEnd); + } +} From 115c57a240208f2ada356bb9e4a2cf5639924895 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Mon, 29 Oct 2018 22:06:09 -0400 Subject: [PATCH 171/249] deps: introduce `llhttp` llhttp is modern, written in human-readable TypeScript, verifiable, and is very easy to maintain. See: https://github.com/indutny/llhttp PR-URL: https://github.com/nodejs/node/pull/24059 Reviewed-By: Matteo Collina Reviewed-By: Refael Ackermann Reviewed-By: James M Snell Reviewed-By: Rod Vagg Reviewed-By: Colin Ihrig Reviewed-By: Gus Caplan Reviewed-By: Ujjwal Sharma Reviewed-By: Ben Noordhuis --- LICENSE | 26 + configure.py | 8 + deps/llhttp/LICENSE-MIT | 22 + deps/llhttp/README.md | 129 + deps/llhttp/common.gypi | 46 + deps/llhttp/include/llhttp.h | 353 + deps/llhttp/llhttp.gyp | 13 + deps/llhttp/src/api.c | 205 + deps/llhttp/src/http.c | 120 + deps/llhttp/src/llhttp.c | 6044 +++++++++++++++++ node.gyp | 1 + node.gypi | 11 +- src/env.h | 1 + src/http_parser_adaptor.h | 24 + src/inspector_socket.cc | 34 +- src/node.cc | 46 +- src/node_http_parser.cc | 229 +- test/parallel/test-http-parser-bad-ref.js | 2 +- test/parallel/test-process-versions.js | 8 +- test/parallel/test-trace-events-metadata.js | 5 +- test/sequential/test-async-wrap-getasyncid.js | 2 +- tools/license-builder.sh | 1 + 22 files changed, 7253 insertions(+), 77 deletions(-) create mode 100644 deps/llhttp/LICENSE-MIT create mode 100644 deps/llhttp/README.md create mode 100644 deps/llhttp/common.gypi create mode 100644 deps/llhttp/include/llhttp.h create mode 100644 deps/llhttp/llhttp.gyp create mode 100644 deps/llhttp/src/api.c create mode 100644 deps/llhttp/src/http.c create mode 100644 deps/llhttp/src/llhttp.c create mode 100644 src/http_parser_adaptor.h diff --git a/LICENSE b/LICENSE index b19517094f64db..59958b20e24a06 100644 --- a/LICENSE +++ b/LICENSE @@ -606,6 +606,32 @@ The externally maintained libraries used by Node.js are: n° 289016). Three clause BSD license. """ +- llhttp, located at deps/llhttp, is licensed as follows: + """ + This software is licensed under the MIT License. + + Copyright Fedor Indutny, 2018. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to permit + persons to whom the Software is furnished to do so, subject to the + following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + USE OR OTHER DEALINGS IN THE SOFTWARE. + """ + - OpenSSL, located at deps/openssl, is licensed as follows: """ Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved. diff --git a/configure.py b/configure.py index 05a7fbc4cc93a0..0df8e12bf3a3c3 100755 --- a/configure.py +++ b/configure.py @@ -182,6 +182,11 @@ help='Use the specified path to system CA (PEM format) in addition to ' 'the OpenSSL supplied CA store or compiled-in Mozilla CA copy.') +parser.add_option('--experimental-http-parser', + action='store_true', + dest='experimental_http_parser', + help='use llhttp instead of http_parser') + shared_optgroup.add_option('--shared-http-parser', action='store_true', dest='shared_http_parser', @@ -1106,6 +1111,9 @@ def configure_node(o): else: o['variables']['node_target_type'] = 'executable' + o['variables']['node_experimental_http_parser'] = \ + b(options.experimental_http_parser) + def configure_library(lib, output): shared_lib = 'shared_' + lib output['variables']['node_' + shared_lib] = b(getattr(options, shared_lib)) diff --git a/deps/llhttp/LICENSE-MIT b/deps/llhttp/LICENSE-MIT new file mode 100644 index 00000000000000..6c1512dd6bcd6d --- /dev/null +++ b/deps/llhttp/LICENSE-MIT @@ -0,0 +1,22 @@ +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/deps/llhttp/README.md b/deps/llhttp/README.md new file mode 100644 index 00000000000000..bca973f80d0025 --- /dev/null +++ b/deps/llhttp/README.md @@ -0,0 +1,129 @@ +# llhttp +[![Build Status](https://secure.travis-ci.org/indutny/llhttp.svg)](http://travis-ci.org/indutny/llhttp) + +Port of [http_parser][0] to [llparse][1]. + +## Why? + +Let's face it, [http_parser][0] is practically unmaintainable. Even +introduction of a single new method results in a significant code churn. + +This project aims to: + +* Make it maintainable +* Verifiable +* Improving benchmarks where possible + +## How? + +Over time, different approaches for improving [http_parser][0]'s code base +were tried. However, all of them failed due to resulting significant performance +degradation. + +This project is a port of [http_parser][0] to TypeScript. [llparse][1] is used +to generate the output C and/or bitcode artifacts, which could be compiled and +linked with the embedder's program (like [Node.js][7]). + +## Peformance + +So far llhttp outperforms http_parser: + +| | input size | bandwidth | reqs/sec | time | +|:----------------|-----------:|-------------:|-----------:|--------:| +| **llhttp** _(C)_ | 8192.00 mb | 1497.88 mb/s | 3020458.87 ops/sec | 5.47 s | +| **llhttp** _(bitcode)_ | 8192.00 mb | 1131.75 mb/s | 2282171.24 ops/sec | 7.24 s | +| **http_parser** | 8192.00 mb | 694.66 mb/s | 1406180.33 req/sec | 11.79 s | + +llhttp is faster by approximately **116%**. + +## Maintenance + +llhttp project has about 1400 lines of TypeScript code describing the parser +itself and around 450 lines of C code and headers providing the helper methods. +The whole [http_parser][0] is implemented in approximately 2500 lines of C, and +436 lines of headers. + +All optimizations and multi-character matching in llhttp are generated +automatically, and thus doesn't add any extra maintenance cost. On the contrary, +most of http_parser's code is hand-optimized and unrolled. Instead describing +"how" it should parse the HTTP requests/responses, a maintainer should +implement the new features in [http_parser][0] cautiously, considering +possible performance degradation and manually optimizing the new code. + +## Verification + +The state machine graph is encoded explicitly in llhttp. The [llparse][1] +automatically checks the graph for absence of loops and correct reporting of the +input ranges (spans) like header names and values. In the future, additional +checks could be performed to get even stricter verification of the llhttp. + +## Usage + +```C +#include "llhttp.h" + +llhttp_t parser; +llhttp_settings_t settings; + +/* Initialize user callbacks and settings */ +llhttp_settings_init(&settings); + +/* Set user callback */ +settings.on_message_complete = handle_on_message_complete; + +/* Initialize the parser in HTTP_BOTH mode, meaning that it will select between + * HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first + * input. + */ +llhttp_init(&parser, HTTP_BOTH, &settings); + +/* Use `llhttp_set_type(&parser, HTTP_REQUEST);` to override the mode */ + +/* Parse request! */ +const char* request = "GET / HTTP/1.1\r\n\r\n"; +int request_len = strlen(request); + +enum llhttp_errno err = llhttp_execute(&parser, request, request_len); +if (err == HPE_OK) { + /* Successfully parsed! */ +} else { + fprintf(stderr, "Parse error: %s %s\n", llhttp_errno_name(err), + parser.reason); +} +``` + +--- + +#### LICENSE + +This software is licensed under the MIT License. + +Copyright Fedor Indutny, 2018. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +USE OR OTHER DEALINGS IN THE SOFTWARE. + +[0]: https://github.com/nodejs/http-parser +[1]: https://github.com/indutny/llparse +[2]: https://en.wikipedia.org/wiki/Register_allocation#Spilling +[3]: https://en.wikipedia.org/wiki/Tail_call +[4]: https://llvm.org/docs/LangRef.html +[5]: https://llvm.org/docs/LangRef.html#call-instruction +[6]: https://clang.llvm.org/ +[7]: https://github.com/nodejs/node diff --git a/deps/llhttp/common.gypi b/deps/llhttp/common.gypi new file mode 100644 index 00000000000000..ef7549f809df26 --- /dev/null +++ b/deps/llhttp/common.gypi @@ -0,0 +1,46 @@ +{ + 'target_defaults': { + 'default_configuration': 'Debug', + 'configurations': { + # TODO: hoist these out and put them somewhere common, because + # RuntimeLibrary MUST MATCH across the entire project + 'Debug': { + 'defines': [ 'DEBUG', '_DEBUG' ], + 'cflags': [ '-Wall', '-Wextra', '-O0', '-g', '-ftrapv' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 1, # static debug + }, + }, + }, + 'Release': { + 'defines': [ 'NDEBUG' ], + 'cflags': [ '-Wall', '-Wextra', '-O3' ], + 'msvs_settings': { + 'VCCLCompilerTool': { + 'RuntimeLibrary': 0, # static release + }, + }, + } + }, + 'msvs_settings': { + 'VCCLCompilerTool': { + # Compile as C++. llhttp.c is actually C99, but C++ is + # close enough in this case. + 'CompileAs': 2, + }, + 'VCLibrarianTool': { + }, + 'VCLinkerTool': { + 'GenerateDebugInformation': 'true', + }, + }, + 'conditions': [ + ['OS == "win"', { + 'defines': [ + 'WIN32' + ], + }] + ], + }, +} diff --git a/deps/llhttp/include/llhttp.h b/deps/llhttp/include/llhttp.h new file mode 100644 index 00000000000000..c114d11ffa9353 --- /dev/null +++ b/deps/llhttp/include/llhttp.h @@ -0,0 +1,353 @@ +#ifndef INCLUDE_LLHTTP_H_ +#define INCLUDE_LLHTTP_H_ + +#define LLHTTP_VERSION_MAJOR 1 +#define LLHTTP_VERSION_MINOR 0 +#define LLHTTP_VERSION_PATCH 0 + +#ifndef INCLUDE_LLHTTP_ITSELF_H_ +#define INCLUDE_LLHTTP_ITSELF_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct llhttp__internal_s llhttp__internal_t; +struct llhttp__internal_s { + int32_t _index; + void* _span_pos0; + void* _span_cb0; + int32_t error; + const char* reason; + const char* error_pos; + void* data; + void* _current; + uint64_t content_length; + uint8_t type; + uint8_t method; + uint8_t http_major; + uint8_t http_minor; + uint8_t header_state; + uint8_t flags; + uint8_t upgrade; + uint16_t status_code; + uint8_t finish; + void* settings; +}; + +int llhttp__internal_init(llhttp__internal_t* s); +int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_ITSELF_H_ */ + +#ifndef LLLLHTTP_C_HEADERS_ +#define LLLLHTTP_C_HEADERS_ +#ifdef __cplusplus +extern "C" { +#endif + +enum llhttp_errno { + HPE_OK = 0, + HPE_INTERNAL = 1, + HPE_STRICT = 2, + HPE_LF_EXPECTED = 3, + HPE_UNEXPECTED_CONTENT_LENGTH = 4, + HPE_CLOSED_CONNECTION = 5, + HPE_INVALID_METHOD = 6, + HPE_INVALID_URL = 7, + HPE_INVALID_CONSTANT = 8, + HPE_INVALID_VERSION = 9, + HPE_INVALID_HEADER_TOKEN = 10, + HPE_INVALID_CONTENT_LENGTH = 11, + HPE_INVALID_CHUNK_SIZE = 12, + HPE_INVALID_STATUS = 13, + HPE_INVALID_EOF_STATE = 14, + HPE_CB_MESSAGE_BEGIN = 15, + HPE_CB_HEADERS_COMPLETE = 16, + HPE_CB_MESSAGE_COMPLETE = 17, + HPE_CB_CHUNK_HEADER = 18, + HPE_CB_CHUNK_COMPLETE = 19, + HPE_PAUSED = 20, + HPE_PAUSED_UPGRADE = 21, + HPE_USER = 22 +}; +typedef enum llhttp_errno llhttp_errno_t; + +enum llhttp_flags { + F_CONNECTION_KEEP_ALIVE = 0x1, + F_CONNECTION_CLOSE = 0x2, + F_CONNECTION_UPGRADE = 0x4, + F_CHUNKED = 0x8, + F_UPGRADE = 0x10, + F_CONTENT_LENGTH = 0x20, + F_SKIPBODY = 0x40, + F_TRAILING = 0x80 +}; +typedef enum llhttp_flags llhttp_flags_t; + +enum llhttp_type { + HTTP_BOTH = 0, + HTTP_REQUEST = 1, + HTTP_RESPONSE = 2 +}; +typedef enum llhttp_type llhttp_type_t; + +enum llhttp_finish { + HTTP_FINISH_SAFE = 0, + HTTP_FINISH_SAFE_WITH_CB = 1, + HTTP_FINISH_UNSAFE = 2 +}; +typedef enum llhttp_finish llhttp_finish_t; + +enum llhttp_method { + HTTP_DELETE = 0, + HTTP_GET = 1, + HTTP_HEAD = 2, + HTTP_POST = 3, + HTTP_PUT = 4, + HTTP_CONNECT = 5, + HTTP_OPTIONS = 6, + HTTP_TRACE = 7, + HTTP_COPY = 8, + HTTP_LOCK = 9, + HTTP_MKCOL = 10, + HTTP_MOVE = 11, + HTTP_PROPFIND = 12, + HTTP_PROPPATCH = 13, + HTTP_SEARCH = 14, + HTTP_UNLOCK = 15, + HTTP_BIND = 16, + HTTP_REBIND = 17, + HTTP_UNBIND = 18, + HTTP_ACL = 19, + HTTP_REPORT = 20, + HTTP_MKACTIVITY = 21, + HTTP_CHECKOUT = 22, + HTTP_MERGE = 23, + HTTP_MSEARCH = 24, + HTTP_NOTIFY = 25, + HTTP_SUBSCRIBE = 26, + HTTP_UNSUBSCRIBE = 27, + HTTP_PATCH = 28, + HTTP_PURGE = 29, + HTTP_MKCALENDAR = 30, + HTTP_LINK = 31, + HTTP_UNLINK = 32, + HTTP_SOURCE = 33 +}; +typedef enum llhttp_method llhttp_method_t; + +#define HTTP_ERRNO_MAP(XX) \ + XX(0, OK, OK) \ + XX(1, INTERNAL, INTERNAL) \ + XX(2, STRICT, STRICT) \ + XX(3, LF_EXPECTED, LF_EXPECTED) \ + XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \ + XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \ + XX(6, INVALID_METHOD, INVALID_METHOD) \ + XX(7, INVALID_URL, INVALID_URL) \ + XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \ + XX(9, INVALID_VERSION, INVALID_VERSION) \ + XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \ + XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \ + XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \ + XX(13, INVALID_STATUS, INVALID_STATUS) \ + XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \ + XX(15, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \ + XX(16, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \ + XX(17, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \ + XX(18, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \ + XX(19, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \ + XX(20, PAUSED, PAUSED) \ + XX(21, PAUSED_UPGRADE, PAUSED_UPGRADE) \ + XX(22, USER, USER) \ + + +#define HTTP_METHOD_MAP(XX) \ + XX(0, DELETE, DELETE) \ + XX(1, GET, GET) \ + XX(2, HEAD, HEAD) \ + XX(3, POST, POST) \ + XX(4, PUT, PUT) \ + XX(5, CONNECT, CONNECT) \ + XX(6, OPTIONS, OPTIONS) \ + XX(7, TRACE, TRACE) \ + XX(8, COPY, COPY) \ + XX(9, LOCK, LOCK) \ + XX(10, MKCOL, MKCOL) \ + XX(11, MOVE, MOVE) \ + XX(12, PROPFIND, PROPFIND) \ + XX(13, PROPPATCH, PROPPATCH) \ + XX(14, SEARCH, SEARCH) \ + XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ + XX(33, SOURCE, SOURCE) \ + + + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* LLLLHTTP_C_HEADERS_ */ + +#ifndef INCLUDE_LLHTTP_API_H_ +#define INCLUDE_LLHTTP_API_H_ +#ifdef __cplusplus +extern "C" { +#endif + +typedef llhttp__internal_t llhttp_t; +typedef struct llhttp_settings_s llhttp_settings_t; + +typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length); +typedef int (*llhttp_cb)(llhttp_t*); + +struct llhttp_settings_s { + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_begin; + + llhttp_data_cb on_url; + llhttp_data_cb on_status; + llhttp_data_cb on_header_field; + llhttp_data_cb on_header_value; + + /* Possible return values: + * 0 - Proceed normally + * 1 - Assume that request/response has no body, and proceed to parsing the + * next message + * 2 - Assume absence of body (as above) and make `llhttp_execute()` return + * `HPE_PAUSED_UPGRADE` + * -1 - Error + * `HPE_PAUSED` + */ + llhttp_cb on_headers_complete; + + llhttp_data_cb on_body; + + /* Possible return values 0, -1, `HPE_PAUSED` */ + llhttp_cb on_message_complete; + + /* When on_chunk_header is called, the current chunk length is stored + * in parser->content_length. + * Possible return values 0, -1, `HPE_PAUSED` + */ + llhttp_cb on_chunk_header; + llhttp_cb on_chunk_complete; +}; + +/* Initialize the parser with specific type and user settings */ +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings); + +/* Initialize the settings object */ +void llhttp_settings_init(llhttp_settings_t* settings); + +/* Parse full or partial request/response, invoking user callbacks along the + * way. + * + * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing + * interrupts, and such errno is returned from `llhttp_execute()`. If + * `HPE_PAUSED` was used as a errno, the execution can be resumed with + * `llhttp_resume()` call. + * + * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` + * is returned after fully parsing the request/response. If the user wishes to + * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`. + */ +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len); + +/* This method should be called when the other side has no further bytes to + * send (e.g. shutdown of readable side of the TCP connection.) + * + * Requests without `Content-Length` and other messages might require treating + * all incoming bytes as the part of the body, up to the last byte of the + * connection. This method will invoke `on_message_complete()` callback if the + * request was terminated safely. Otherwise a error code would be returned. + */ +llhttp_errno_t llhttp_finish(llhttp_t* parser); + +/* Returns `1` if the incoming message is parsed until the last byte, and has + * to be completed by calling `llhttp_finish()` on EOF + */ +int llhttp_message_needs_eof(const llhttp_t* parser); + +/* Returns `1` if there might be any other messages following the last that was + * successfuly parsed. + */ +int llhttp_should_keep_alive(const llhttp_t* parser); + +/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set + * appropriate error reason. + * + * Important: do not call this from user callbacks! User callbacks must return + * `HPE_PAUSED` if pausing is required. + */ +void llhttp_pause(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED`. + */ +void llhttp_resume(llhttp_t* parser); + +/* Might be called to resume the execution after the pause in user's callback. + * See `llhttp_execute()` above for details. + * + * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE` + */ +void llhttp_resume_after_upgrade(llhttp_t* parser); + +/* Returns the latest return error */ +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser); + +/* Returns the verbal explanation of the latest returned error. + * + * Note: User callback should set error reason when returning the error. See + * `llhttp_set_error_reason()` for details. + */ +const char* llhttp_get_error_reason(const llhttp_t* parser); + +/* Assign verbal description to the returned error. Must be called in user + * callbacks right before returning the errno. + * + * Note: `HPE_USER` error code might be useful in user callbacks. + */ +void llhttp_set_error_reason(llhttp_t* parser, const char* reason); + +/* Returns the pointer to the last parsed byte before the returned error. The + * pointer is relative to the `data` argument of `llhttp_execute()`. + * + * Note: this method might be useful for counting the number of parsed bytes. + */ +const char* llhttp_get_error_pos(const llhttp_t* parser); + +/* Returns textual name of error code */ +const char* llhttp_errno_name(llhttp_errno_t err); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* INCLUDE_LLHTTP_API_H_ */ + +#endif /* INCLUDE_LLHTTP_H_ */ diff --git a/deps/llhttp/llhttp.gyp b/deps/llhttp/llhttp.gyp new file mode 100644 index 00000000000000..4acc79bdf399fc --- /dev/null +++ b/deps/llhttp/llhttp.gyp @@ -0,0 +1,13 @@ +{ + 'targets': [ + { + 'target_name': 'llhttp', + 'type': 'static_library', + 'include_dirs': [ '.', 'include' ], + 'direct_dependent_settings': { + 'include_dirs': [ 'include' ], + }, + 'sources': [ 'src/llhttp.c', 'src/api.c', 'src/http.c' ], + }, + ] +} diff --git a/deps/llhttp/src/api.c b/deps/llhttp/src/api.c new file mode 100644 index 00000000000000..37a5dcd183e0f6 --- /dev/null +++ b/deps/llhttp/src/api.c @@ -0,0 +1,205 @@ +#include +#include +#include + +#include "llhttp.h" + +#define CALLBACK_MAYBE(PARSER, NAME, ...) \ + do { \ + llhttp_settings_t* settings; \ + settings = (llhttp_settings_t*) (PARSER)->settings; \ + if (settings == NULL || settings->NAME == NULL) { \ + err = 0; \ + break; \ + } \ + err = settings->NAME(__VA_ARGS__); \ + } while (0) + +void llhttp_init(llhttp_t* parser, llhttp_type_t type, + const llhttp_settings_t* settings) { + llhttp__internal_init(parser); + + parser->type = type; + parser->settings = (void*) settings; +} + + +llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) { + return llhttp__internal_execute(parser, data, data + len); +} + + +void llhttp_settings_init(llhttp_settings_t* settings) { + memset(settings, 0, sizeof(*settings)); +} + + +llhttp_errno_t llhttp_finish(llhttp_t* parser) { + int err; + + /* We're in an error state. Don't bother doing anything. */ + if (parser->error != 0) { + return 0; + } + + switch (parser->finish) { + case HTTP_FINISH_SAFE_WITH_CB: + CALLBACK_MAYBE(parser, on_message_complete, parser); + if (err != HPE_OK) return err; + + /* FALLTHROUGH */ + case HTTP_FINISH_SAFE: + return HPE_OK; + case HTTP_FINISH_UNSAFE: + parser->reason = "Invalid EOF state"; + return HPE_INVALID_EOF_STATE; + default: + abort(); + } +} + + +void llhttp_pause(llhttp_t* parser) { + if (parser->error != HPE_OK) { + return; + } + + parser->error = HPE_PAUSED; + parser->reason = "Paused"; +} + + +void llhttp_resume(llhttp_t* parser) { + if (parser->error != HPE_PAUSED) { + return; + } + + parser->error = 0; +} + + +void llhttp_resume_after_upgrade(llhttp_t* parser) { + if (parser->error != HPE_PAUSED_UPGRADE) { + return; + } + + parser->error = 0; +} + + +llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) { + return parser->error; +} + + +const char* llhttp_get_error_reason(const llhttp_t* parser) { + return parser->reason; +} + + +void llhttp_set_error_reason(llhttp_t* parser, const char* reason) { + parser->reason = reason; +} + + +const char* llhttp_get_error_pos(const llhttp_t* parser) { + return parser->error_pos; +} + + +const char* llhttp_errno_name(llhttp_errno_t err) { +#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME; + switch (err) { + HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) + default: abort(); + } +#undef HTTP_ERRNO_GEN +} + + +/* Callbacks */ + + +int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_begin, s); + return err; +} + + +int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_url, s, p, endp - p); + return err; +} + + +int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_status, s, p, endp - p); + return err; +} + + +int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_field, s, p, endp - p); + return err; +} + + +int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_header_value, s, p, endp - p); + return err; +} + + +int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_headers_complete, s); + return err; +} + + +int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_message_complete, s); + return err; +} + + +int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_body, s, p, endp - p); + return err; +} + + +int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_header, s); + return err; +} + + +int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { + int err; + CALLBACK_MAYBE(s, on_chunk_complete, s); + return err; +} + + +/* Private */ + + +void llhttp__debug(llhttp_t* s, const char* p, const char* endp, + const char* msg) { + if (p == endp) { + fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type, + s->flags, msg); + } else { + fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s, + s->type, s->flags, *p, msg); + } +} diff --git a/deps/llhttp/src/http.c b/deps/llhttp/src/http.c new file mode 100644 index 00000000000000..67834c2d377c49 --- /dev/null +++ b/deps/llhttp/src/http.c @@ -0,0 +1,120 @@ +#include +#ifndef LLHTTP__TEST +# include "llhttp.h" +#else +# define llhttp_t llparse_t +#endif /* */ + +int llhttp_message_needs_eof(const llhttp_t* parser); +int llhttp_should_keep_alive(const llhttp_t* parser); + +int llhttp__before_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + /* Set this here so that on_headers_complete() callbacks can see it */ + if ((parser->flags & F_UPGRADE) && + (parser->flags & F_CONNECTION_UPGRADE)) { + /* For responses, "Upgrade: foo" and "Connection: upgrade" are + * mandatory only when it is a 101 Switching Protocols response, + * otherwise it is purely informational, to announce support. + */ + parser->upgrade = + (parser->type == HTTP_REQUEST || parser->status_code == 101); + } else { + parser->upgrade = (parser->method == HTTP_CONNECT); + } + return 0; +} + + +/* Return values: + * 0 - No body, `restart`, message_complete + * 1 - CONNECT request, `restart`, message_complete, and pause + * 2 - chunk_size_start + * 3 - body_identity + * 4 - body_identity_eof + */ +int llhttp__after_headers_complete(llhttp_t* parser, const char* p, + const char* endp) { + int hasBody; + + hasBody = parser->flags & F_CHUNKED || parser->content_length > 0; + if (parser->upgrade && (parser->method == HTTP_CONNECT || + (parser->flags & F_SKIPBODY) || !hasBody)) { + /* Exit, the rest of the message is in a different protocol. */ + return 1; + } + + if (parser->flags & F_SKIPBODY) { + return 0; + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + return 2; + } else { + if (!(parser->flags & F_CONTENT_LENGTH)) { + if (!llhttp_message_needs_eof(parser)) { + /* Assume content-length 0 - read the next */ + return 0; + } else { + /* Read body until EOF */ + return 4; + } + } else if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + return 0; + } else { + /* Content-Length header given and non-zero */ + return 3; + } + } +} + + +int llhttp__after_message_complete(llhttp_t* parser, const char* p, + const char* endp) { + int should_keep_alive; + + should_keep_alive = llhttp_should_keep_alive(parser); + parser->flags = 0; + parser->finish = HTTP_FINISH_SAFE; + + /* NOTE: this is ignored in loose parsing mode */ + return should_keep_alive; +} + + +int llhttp_message_needs_eof(const llhttp_t* parser) { + if (parser->type == HTTP_REQUEST) { + return 0; + } + + /* See RFC 2616 section 4.4 */ + if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ + parser->status_code == 204 || /* No Content */ + parser->status_code == 304 || /* Not Modified */ + (parser->flags & F_SKIPBODY)) { /* response to a HEAD request */ + return 0; + } + + if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) { + return 0; + } + + return 1; +} + + +int llhttp_should_keep_alive(const llhttp_t* parser) { + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } + } else { + /* HTTP/1.0 or earlier */ + if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { + return 0; + } + } + + return !llhttp_message_needs_eof(parser); +} diff --git a/deps/llhttp/src/llhttp.c b/deps/llhttp/src/llhttp.c new file mode 100644 index 00000000000000..cb12c8dfd0f182 --- /dev/null +++ b/deps/llhttp/src/llhttp.c @@ -0,0 +1,6044 @@ +#include +#include +#include + +#include "llhttp.h" + +typedef int (*llhttp__internal__span_cb)( + llhttp__internal_t*, const char*, const char*); + +static const unsigned char llparse_blob0[] = { + 'C', 'L' +}; +static const unsigned char llparse_blob1[] = { + 'o', 'n' +}; +static const unsigned char llparse_blob2[] = { + 'e', 'c', 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob3[] = { + 'l', 'o', 's', 'e' +}; +static const unsigned char llparse_blob4[] = { + 'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e' +}; +static const unsigned char llparse_blob5[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob6[] = { + 'h', 'u', 'n', 'k', 'e', 'd' +}; +static const unsigned char llparse_blob7[] = { + 'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h' +}; +static const unsigned char llparse_blob8[] = { + 'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c', + 't', 'i', 'o', 'n' +}; +static const unsigned char llparse_blob9[] = { + 'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c', + 'o', 'd', 'i', 'n', 'g' +}; +static const unsigned char llparse_blob10[] = { + 'p', 'g', 'r', 'a', 'd', 'e' +}; +static const unsigned char llparse_blob11[] = { + 0xd, 0xa +}; +static const unsigned char llparse_blob12[] = { + 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob13[] = { + 'C', 'E', '/' +}; +static const unsigned char llparse_blob14[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob15[] = { + 'E', 'C', 'K', 'O', 'U', 'T' +}; +static const unsigned char llparse_blob16[] = { + 'N', 'E', 'C', 'T' +}; +static const unsigned char llparse_blob17[] = { + 'E', 'L', 'E', 'T', 'E' +}; +static const unsigned char llparse_blob18[] = { + 'E', 'T' +}; +static const unsigned char llparse_blob19[] = { + 'E', 'A', 'D' +}; +static const unsigned char llparse_blob20[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob21[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob22[] = { + 'S', 'E', 'A', 'R', 'C', 'H' +}; +static const unsigned char llparse_blob23[] = { + 'R', 'G', 'E' +}; +static const unsigned char llparse_blob24[] = { + 'C', 'T', 'I', 'V', 'I', 'T', 'Y' +}; +static const unsigned char llparse_blob25[] = { + 'L', 'E', 'N', 'D', 'A', 'R' +}; +static const unsigned char llparse_blob26[] = { + 'V', 'E' +}; +static const unsigned char llparse_blob27[] = { + 'O', 'T', 'I', 'F', 'Y' +}; +static const unsigned char llparse_blob28[] = { + 'P', 'T', 'I', 'O', 'N', 'S' +}; +static const unsigned char llparse_blob29[] = { + 'T', 'C', 'H' +}; +static const unsigned char llparse_blob30[] = { + 'S', 'T' +}; +static const unsigned char llparse_blob31[] = { + 'O', 'P' +}; +static const unsigned char llparse_blob32[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob33[] = { + 'A', 'T', 'C', 'H' +}; +static const unsigned char llparse_blob34[] = { + 'G', 'E' +}; +static const unsigned char llparse_blob35[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob36[] = { + 'O', 'R', 'T' +}; +static const unsigned char llparse_blob37[] = { + 'A', 'R', 'C', 'H' +}; +static const unsigned char llparse_blob38[] = { + 'U', 'R', 'C', 'E' +}; +static const unsigned char llparse_blob39[] = { + 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob40[] = { + 'R', 'A', 'C', 'E' +}; +static const unsigned char llparse_blob41[] = { + 'I', 'N', 'D' +}; +static const unsigned char llparse_blob42[] = { + 'N', 'K' +}; +static const unsigned char llparse_blob43[] = { + 'C', 'K' +}; +static const unsigned char llparse_blob44[] = { + 'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E' +}; +static const unsigned char llparse_blob45[] = { + 'H', 'T', 'T', 'P', '/' +}; +static const unsigned char llparse_blob46[] = { + 'A', 'D' +}; +static const unsigned char llparse_blob47[] = { + 'T', 'P', '/' +}; + +enum llparse_match_status_e { + kMatchComplete, + kMatchPause, + kMatchMismatch +}; +typedef enum llparse_match_status_e llparse_match_status_t; + +struct llparse_match_s { + llparse_match_status_t status; + const unsigned char* current; +}; +typedef struct llparse_match_s llparse_match_t; + +static llparse_match_t llparse__match_sequence_id( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = *p; + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +static llparse_match_t llparse__match_sequence_to_lower_unsafe( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp, + const unsigned char* seq, uint32_t seq_len) { + uint32_t index; + llparse_match_t res; + + index = s->_index; + for (; p != endp; p++) { + unsigned char current; + + current = ((*p) | 0x20); + if (current == seq[index]) { + if (++index == seq_len) { + res.status = kMatchComplete; + goto reset; + } + } else { + res.status = kMatchMismatch; + goto reset; + } + } + s->_index = index; + res.status = kMatchPause; + res.current = p; + return res; +reset: + s->_index = 0; + res.current = p; + return res; +} + +enum llparse_state_e { + s_error, + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete, + s_n_llhttp__internal__n_pause_1, + s_n_llhttp__internal__n_invoke_is_equal_upgrade, + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2, + s_n_llhttp__internal__n_chunk_data_almost_done_skip, + s_n_llhttp__internal__n_chunk_data_almost_done, + s_n_llhttp__internal__n_consume_content_length, + s_n_llhttp__internal__n_span_start_llhttp__on_body, + s_n_llhttp__internal__n_invoke_is_equal_content_length, + s_n_llhttp__internal__n_chunk_size_almost_done, + s_n_llhttp__internal__n_chunk_parameters, + s_n_llhttp__internal__n_chunk_size_otherwise, + s_n_llhttp__internal__n_chunk_size, + s_n_llhttp__internal__n_invoke_update_content_length, + s_n_llhttp__internal__n_consume_content_length_1, + s_n_llhttp__internal__n_span_start_llhttp__on_body_1, + s_n_llhttp__internal__n_eof, + s_n_llhttp__internal__n_span_start_llhttp__on_body_2, + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete, + s_n_llhttp__internal__n_headers_almost_done, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value, + s_n_llhttp__internal__n_header_value_discard_lws, + s_n_llhttp__internal__n_header_value_discard_ws_almost_done, + s_n_llhttp__internal__n_header_value_lws, + s_n_llhttp__internal__n_header_value_almost_done, + s_n_llhttp__internal__n_header_value_otherwise, + s_n_llhttp__internal__n_header_value_connection_token, + s_n_llhttp__internal__n_header_value_connection_ws, + s_n_llhttp__internal__n_header_value_connection_1, + s_n_llhttp__internal__n_header_value_connection_2, + s_n_llhttp__internal__n_header_value_connection_3, + s_n_llhttp__internal__n_header_value_connection, + s_n_llhttp__internal__n_error_14, + s_n_llhttp__internal__n_header_value, + s_n_llhttp__internal__n_header_value_discard_rws, + s_n_llhttp__internal__n_error_15, + s_n_llhttp__internal__n_header_value_content_length_ws, + s_n_llhttp__internal__n_header_value_content_length, + s_n_llhttp__internal__n_header_value_te_chunked_1, + s_n_llhttp__internal__n_header_value_te_chunked, + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1, + s_n_llhttp__internal__n_header_value_discard_ws, + s_n_llhttp__internal__n_header_field_general_otherwise, + s_n_llhttp__internal__n_header_field_general, + s_n_llhttp__internal__n_header_field_colon, + s_n_llhttp__internal__n_header_field_3, + s_n_llhttp__internal__n_header_field_4, + s_n_llhttp__internal__n_header_field_2, + s_n_llhttp__internal__n_header_field_1, + s_n_llhttp__internal__n_header_field_5, + s_n_llhttp__internal__n_header_field_6, + s_n_llhttp__internal__n_header_field_7, + s_n_llhttp__internal__n_header_field, + s_n_llhttp__internal__n_span_start_llhttp__on_header_field, + s_n_llhttp__internal__n_header_field_start, + s_n_llhttp__internal__n_url_skip_to_http09, + s_n_llhttp__internal__n_url_skip_lf_to_http09, + s_n_llhttp__internal__n_req_http_end_1, + s_n_llhttp__internal__n_req_http_end, + s_n_llhttp__internal__n_req_http_minor, + s_n_llhttp__internal__n_req_http_dot, + s_n_llhttp__internal__n_req_http_major, + s_n_llhttp__internal__n_req_http_start_1, + s_n_llhttp__internal__n_req_http_start_2, + s_n_llhttp__internal__n_req_http_start, + s_n_llhttp__internal__n_url_skip_to_http, + s_n_llhttp__internal__n_url_fragment, + s_n_llhttp__internal__n_span_end_stub_query_3, + s_n_llhttp__internal__n_url_query, + s_n_llhttp__internal__n_url_query_or_fragment, + s_n_llhttp__internal__n_url_path, + s_n_llhttp__internal__n_span_start_stub_path_2, + s_n_llhttp__internal__n_span_start_stub_path, + s_n_llhttp__internal__n_span_start_stub_path_1, + s_n_llhttp__internal__n_url_server_with_at, + s_n_llhttp__internal__n_url_server, + s_n_llhttp__internal__n_url_schema_delim_1, + s_n_llhttp__internal__n_url_schema_delim, + s_n_llhttp__internal__n_span_end_stub_schema, + s_n_llhttp__internal__n_url_schema, + s_n_llhttp__internal__n_url_start, + s_n_llhttp__internal__n_span_start_llhttp__on_url_1, + s_n_llhttp__internal__n_span_start_llhttp__on_url, + s_n_llhttp__internal__n_req_spaces_before_url, + s_n_llhttp__internal__n_req_first_space_before_url, + s_n_llhttp__internal__n_start_req_1, + s_n_llhttp__internal__n_start_req_2, + s_n_llhttp__internal__n_start_req_4, + s_n_llhttp__internal__n_start_req_6, + s_n_llhttp__internal__n_start_req_7, + s_n_llhttp__internal__n_start_req_5, + s_n_llhttp__internal__n_start_req_3, + s_n_llhttp__internal__n_start_req_8, + s_n_llhttp__internal__n_start_req_9, + s_n_llhttp__internal__n_start_req_10, + s_n_llhttp__internal__n_start_req_12, + s_n_llhttp__internal__n_start_req_13, + s_n_llhttp__internal__n_start_req_11, + s_n_llhttp__internal__n_start_req_15, + s_n_llhttp__internal__n_start_req_16, + s_n_llhttp__internal__n_start_req_18, + s_n_llhttp__internal__n_start_req_20, + s_n_llhttp__internal__n_start_req_21, + s_n_llhttp__internal__n_start_req_19, + s_n_llhttp__internal__n_start_req_17, + s_n_llhttp__internal__n_start_req_22, + s_n_llhttp__internal__n_start_req_14, + s_n_llhttp__internal__n_start_req_23, + s_n_llhttp__internal__n_start_req_24, + s_n_llhttp__internal__n_start_req_26, + s_n_llhttp__internal__n_start_req_27, + s_n_llhttp__internal__n_start_req_30, + s_n_llhttp__internal__n_start_req_31, + s_n_llhttp__internal__n_start_req_29, + s_n_llhttp__internal__n_start_req_28, + s_n_llhttp__internal__n_start_req_33, + s_n_llhttp__internal__n_start_req_32, + s_n_llhttp__internal__n_start_req_25, + s_n_llhttp__internal__n_start_req_36, + s_n_llhttp__internal__n_start_req_37, + s_n_llhttp__internal__n_start_req_35, + s_n_llhttp__internal__n_start_req_34, + s_n_llhttp__internal__n_start_req_39, + s_n_llhttp__internal__n_start_req_40, + s_n_llhttp__internal__n_start_req_41, + s_n_llhttp__internal__n_start_req_38, + s_n_llhttp__internal__n_start_req_42, + s_n_llhttp__internal__n_start_req_45, + s_n_llhttp__internal__n_start_req_47, + s_n_llhttp__internal__n_start_req_48, + s_n_llhttp__internal__n_start_req_46, + s_n_llhttp__internal__n_start_req_49, + s_n_llhttp__internal__n_start_req_44, + s_n_llhttp__internal__n_start_req_43, + s_n_llhttp__internal__n_start_req, + s_n_llhttp__internal__n_res_line_almost_done, + s_n_llhttp__internal__n_res_status, + s_n_llhttp__internal__n_span_start_llhttp__on_status, + s_n_llhttp__internal__n_res_status_start, + s_n_llhttp__internal__n_res_status_code_otherwise, + s_n_llhttp__internal__n_res_status_code, + s_n_llhttp__internal__n_res_http_end, + s_n_llhttp__internal__n_res_http_minor, + s_n_llhttp__internal__n_res_http_dot, + s_n_llhttp__internal__n_res_http_major, + s_n_llhttp__internal__n_start_res, + s_n_llhttp__internal__n_req_or_res_method_2, + s_n_llhttp__internal__n_req_or_res_method_3, + s_n_llhttp__internal__n_req_or_res_method_1, + s_n_llhttp__internal__n_req_or_res_method, + s_n_llhttp__internal__n_start_req_or_res, + s_n_llhttp__internal__n_invoke_load_type, + s_n_llhttp__internal__n_start, +}; +typedef enum llparse_state_e llparse_state_t; + +int llhttp__on_url( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_field( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_header_value( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_body( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_status( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_finish( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 2; + return 0; +} + +int llhttp__on_message_begin( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_load_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->type; +} + +int llhttp__internal__c_store_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->method = match; + return 0; +} + +int llhttp__internal__c_is_equal_method( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method == 5; +} + +int llhttp__internal__c_update_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_major = 0; + return 0; +} + +int llhttp__internal__c_update_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->http_minor = 9; + return 0; +} + +int llhttp__internal__c_test_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 128) == 128; +} + +int llhttp__on_chunk_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->upgrade == 1; +} + +int llhttp__after_message_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_test_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 40) == 40; +} + +int llhttp__before_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__on_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__after_headers_complete( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_update_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->content_length = 0; + return 0; +} + +int llhttp__internal__c_mul_add_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 16) { + return 1; + } + + state->content_length *= 16; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__on_chunk_header( + llhttp__internal_t* s, const unsigned char* p, + const unsigned char* endp); + +int llhttp__internal__c_is_equal_content_length( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->content_length == 0; +} + +int llhttp__internal__c_or_flags( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 128; + return 0; +} + +int llhttp__internal__c_update_finish_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->finish = 1; + return 0; +} + +int llhttp__internal__c_or_flags_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 64; + return 0; +} + +int llhttp__internal__c_update_upgrade( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->upgrade = 1; + return 0; +} + +int llhttp__internal__c_store_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->header_state = match; + return 0; +} + +int llhttp__internal__c_load_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->header_state; +} + +int llhttp__internal__c_or_flags_3( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 1; + return 0; +} + +int llhttp__internal__c_update_header_state( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 1; + return 0; +} + +int llhttp__internal__c_or_flags_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 2; + return 0; +} + +int llhttp__internal__c_or_flags_5( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 4; + return 0; +} + +int llhttp__internal__c_or_flags_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 8; + return 0; +} + +int llhttp__internal__c_update_header_state_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 6; + return 0; +} + +int llhttp__internal__c_update_header_state_4( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 0; + return 0; +} + +int llhttp__internal__c_update_header_state_5( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 5; + return 0; +} + +int llhttp__internal__c_update_header_state_6( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 7; + return 0; +} + +int llhttp__internal__c_test_flags_2( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return (state->flags & 32) == 32; +} + +int llhttp__internal__c_mul_add_content_length_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->content_length > 0xffffffffffffffffULL / 10) { + return 1; + } + + state->content_length *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->content_length > 0xffffffffffffffffULL - match) { + return 1; + } + } else { + if (state->content_length < 0ULL - match) { + return 1; + } + } + state->content_length += match; + return 0; +} + +int llhttp__internal__c_or_flags_15( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 32; + return 0; +} + +int llhttp__internal__c_update_header_state_8( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->header_state = 8; + return 0; +} + +int llhttp__internal__c_or_flags_16( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->flags |= 16; + return 0; +} + +int llhttp__internal__c_store_http_major( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_major = match; + return 0; +} + +int llhttp__internal__c_store_http_minor( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + state->http_minor = match; + return 0; +} + +int llhttp__internal__c_is_equal_method_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + return state->method == 33; +} + +int llhttp__internal__c_update_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->status_code = 0; + return 0; +} + +int llhttp__internal__c_mul_add_status_code( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp, + int match) { + /* Multiplication overflow */ + if (state->status_code > 0xffff / 10) { + return 1; + } + + state->status_code *= 10; + + /* Addition overflow */ + if (match >= 0) { + if (state->status_code > 0xffff - match) { + return 1; + } + } else { + if (state->status_code < 0 - match) { + return 1; + } + } + state->status_code += match; + + /* Enforce maximum */ + if (state->status_code > 999) { + return 1; + } + return 0; +} + +int llhttp__internal__c_update_type( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 1; + return 0; +} + +int llhttp__internal__c_update_type_1( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + state->type = 2; + return 0; +} + +int llhttp__internal_init(llhttp__internal_t* state) { + memset(state, 0, sizeof(*state)); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start; + return 0; +} + +static llparse_state_t llhttp__internal__run( + llhttp__internal_t* state, + const unsigned char* p, + const unsigned char* endp) { + int match; + switch ((llparse_state_t) (intptr_t) state->_current) { + case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: { + switch (llhttp__after_message_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_start; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_pause_1: + s_n_llhttp__internal__n_pause_1: { + state->error = 0x15; + state->reason = "Pause on CONNECT/Upgrade"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_upgrade: + s_n_llhttp__internal__n_invoke_is_equal_upgrade: { + switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + default: + goto s_n_llhttp__internal__n_pause_1; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_upgrade; + case 20: + goto s_n_llhttp__internal__n_pause_5; + default: + goto s_n_llhttp__internal__n_error_8; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done_skip: + s_n_llhttp__internal__n_chunk_data_almost_done_skip: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done_skip; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_data_almost_done: + s_n_llhttp__internal__n_chunk_data_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_data_almost_done; + } + p++; + goto s_n_llhttp__internal__n_chunk_data_almost_done_skip; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length: + s_n_llhttp__internal__n_consume_content_length: { + size_t avail; + size_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body: + s_n_llhttp__internal__n_span_start_llhttp__on_body: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_is_equal_content_length: + s_n_llhttp__internal__n_invoke_is_equal_content_length: { + switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body; + default: + goto s_n_llhttp__internal__n_invoke_or_flags; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_almost_done: + s_n_llhttp__internal__n_chunk_size_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_almost_done; + } + p++; + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_parameters: + s_n_llhttp__internal__n_chunk_parameters: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_parameters; + } + switch (*p) { + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + default: { + p++; + goto s_n_llhttp__internal__n_chunk_parameters; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size_otherwise: + s_n_llhttp__internal__n_chunk_size_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size_otherwise; + } + switch (*p) { + case 13: { + p++; + goto s_n_llhttp__internal__n_chunk_size_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_chunk_parameters; + } + case ';': { + p++; + goto s_n_llhttp__internal__n_chunk_parameters; + } + default: { + goto s_n_llhttp__internal__n_error_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_chunk_size: + s_n_llhttp__internal__n_chunk_size: { + if (p == endp) { + return s_n_llhttp__internal__n_chunk_size; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'A': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'B': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'C': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'D': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'E': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'F': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'a': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'b': { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'c': { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'd': { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'e': { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + case 'f': { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length; + } + default: { + goto s_n_llhttp__internal__n_chunk_size_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_update_content_length: + s_n_llhttp__internal__n_invoke_update_content_length: { + switch (llhttp__internal__c_update_content_length(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_chunk_size; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_consume_content_length_1: + s_n_llhttp__internal__n_consume_content_length_1: { + size_t avail; + size_t need; + + avail = endp - p; + need = state->content_length; + if (avail >= need) { + p += need; + state->content_length = 0; + goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1; + } + + state->content_length -= avail; + return s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_1: + s_n_llhttp__internal__n_span_start_llhttp__on_body_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_consume_content_length_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_eof: + s_n_llhttp__internal__n_eof: { + if (p == endp) { + return s_n_llhttp__internal__n_eof; + } + p++; + goto s_n_llhttp__internal__n_eof; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_body_2: + s_n_llhttp__internal__n_span_start_llhttp__on_body_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_body; + goto s_n_llhttp__internal__n_invoke_update_finish_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: + s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: { + switch (llhttp__after_headers_complete(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_content_length; + case 3: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1; + case 4: + goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_headers_almost_done: + s_n_llhttp__internal__n_headers_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_headers_almost_done; + } + p++; + goto s_n_llhttp__internal__n_invoke_test_flags; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_lws: + s_n_llhttp__internal__n_header_value_discard_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_lws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws_almost_done: + s_n_llhttp__internal__n_header_value_discard_ws_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + p++; + goto s_n_llhttp__internal__n_header_value_discard_lws; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_lws: + s_n_llhttp__internal__n_header_value_lws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_lws; + } + switch (*p) { + case 9: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + case ' ': { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_load_header_state_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_almost_done: + s_n_llhttp__internal__n_header_value_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_almost_done; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_lws; + } + default: { + goto s_n_llhttp__internal__n_error_11; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_otherwise: + s_n_llhttp__internal__n_header_value_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_otherwise; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2; + } + default: { + goto s_n_llhttp__internal__n_error_12; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_token: + s_n_llhttp__internal__n_header_value_connection_token: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_token; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value_connection_token; + } + case 2: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_ws: + s_n_llhttp__internal__n_header_value_connection_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + case ',': { + p++; + goto s_n_llhttp__internal__n_invoke_load_header_state_3; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_1: + s_n_llhttp__internal__n_header_value_connection_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_1; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob3, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_2: + s_n_llhttp__internal__n_header_value_connection_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_2; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob4, 9); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_5; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection_3: + s_n_llhttp__internal__n_header_value_connection_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection_3; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_6; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_connection_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_connection: + s_n_llhttp__internal__n_header_value_connection: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_connection; + } + switch (((*p) | 0x20)) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_connection; + } + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_1; + } + case 'k': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_2; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_value_connection_3; + } + default: { + goto s_n_llhttp__internal__n_header_value_connection_token; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_14: + s_n_llhttp__internal__n_error_14: { + state->error = 0xb; + state->reason = "Content-Length overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value: + s_n_llhttp__internal__n_header_value: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_value; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_value; + } + default: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_rws: + s_n_llhttp__internal__n_header_value_discard_rws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_rws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_otherwise; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_error_15: + s_n_llhttp__internal__n_error_15: { + state->error = 0xb; + state->reason = "Invalid character in Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length_ws: + s_n_llhttp__internal__n_header_value_content_length_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length_ws; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_invoke_or_flags_15; + } + case 13: { + goto s_n_llhttp__internal__n_invoke_or_flags_15; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + default: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_content_length: + s_n_llhttp__internal__n_header_value_content_length: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_content_length; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; + } + default: { + goto s_n_llhttp__internal__n_header_value_content_length_ws; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked_1: + s_n_llhttp__internal__n_header_value_te_chunked_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked_1; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_header_state_8; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_value_te_chunked_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_te_chunked: + s_n_llhttp__internal__n_header_value_te_chunked: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_te_chunked; + } + switch (((*p) | 0x20)) { + case 10: { + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + case 13: { + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + case ' ': { + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_value_te_chunked_1; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: + s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_value; + goto s_n_llhttp__internal__n_invoke_load_header_state_1; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_value_discard_ws: + s_n_llhttp__internal__n_header_value_discard_ws: { + if (p == endp) { + return s_n_llhttp__internal__n_header_value_discard_ws; + } + switch (*p) { + case 9: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + case 10: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_lws; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general_otherwise: + s_n_llhttp__internal__n_header_field_general_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general_otherwise; + } + switch (*p) { + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1; + } + default: { + goto s_n_llhttp__internal__n_error_16; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_general: + s_n_llhttp__internal__n_header_field_general: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_header_field_general; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_header_field_general; + } + default: { + goto s_n_llhttp__internal__n_header_field_general_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_colon: + s_n_llhttp__internal__n_header_field_colon: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_colon; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_header_field_colon; + } + case ':': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_9; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_3: + s_n_llhttp__internal__n_header_field_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_3; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob2, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_4: + s_n_llhttp__internal__n_header_field_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_4; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob7, 10); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_2: + s_n_llhttp__internal__n_header_field_2: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_2; + } + switch (((*p) | 0x20)) { + case 'n': { + p++; + goto s_n_llhttp__internal__n_header_field_3; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_4; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_1: + s_n_llhttp__internal__n_header_field_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_1; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob1, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_header_field_2; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_5: + s_n_llhttp__internal__n_header_field_5: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_5; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob8, 15); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_5; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_6: + s_n_llhttp__internal__n_header_field_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_6; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob9, 16); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_7: + s_n_llhttp__internal__n_header_field_7: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_header_field_7; + } + match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob10, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_header_state; + } + case kMatchPause: { + return s_n_llhttp__internal__n_header_field_7; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field: + s_n_llhttp__internal__n_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field; + } + switch (((*p) | 0x20)) { + case 'c': { + p++; + goto s_n_llhttp__internal__n_header_field_1; + } + case 'p': { + p++; + goto s_n_llhttp__internal__n_header_field_5; + } + case 't': { + p++; + goto s_n_llhttp__internal__n_header_field_6; + } + case 'u': { + p++; + goto s_n_llhttp__internal__n_header_field_7; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_header_state_10; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_header_field: + s_n_llhttp__internal__n_span_start_llhttp__on_header_field: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_header_field; + goto s_n_llhttp__internal__n_header_field; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_header_field_start: + s_n_llhttp__internal__n_header_field_start: { + if (p == endp) { + return s_n_llhttp__internal__n_header_field_start; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_headers_almost_done; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_headers_almost_done; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http09: + s_n_llhttp__internal__n_url_skip_to_http09: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http09; + } + p++; + goto s_n_llhttp__internal__n_invoke_update_http_major; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_lf_to_http09: + s_n_llhttp__internal__n_url_skip_lf_to_http09: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_lf_to_http09; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob11, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_http_major; + } + case kMatchPause: { + return s_n_llhttp__internal__n_url_skip_lf_to_http09; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_17; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_end_1: + s_n_llhttp__internal__n_req_http_end_1: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_end_1; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_field_start; + } + default: { + goto s_n_llhttp__internal__n_error_18; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_end: + s_n_llhttp__internal__n_req_http_end: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_end; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_field_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_req_http_end_1; + } + default: { + goto s_n_llhttp__internal__n_error_18; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_minor: + s_n_llhttp__internal__n_req_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor; + } + default: { + goto s_n_llhttp__internal__n_error_19; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_dot: + s_n_llhttp__internal__n_req_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_req_http_minor; + } + default: { + goto s_n_llhttp__internal__n_error_20; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_major: + s_n_llhttp__internal__n_req_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major; + } + default: { + goto s_n_llhttp__internal__n_error_21; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_1: + s_n_llhttp__internal__n_req_http_start_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_1; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob12, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_req_http_major; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_23; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start_2: + s_n_llhttp__internal__n_req_http_start_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_is_equal_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_http_start_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_23; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_http_start: + s_n_llhttp__internal__n_req_http_start: { + if (p == endp) { + return s_n_llhttp__internal__n_req_http_start; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_http_start; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_http_start_1; + } + case 'I': { + p++; + goto s_n_llhttp__internal__n_req_http_start_2; + } + default: { + goto s_n_llhttp__internal__n_error_23; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_skip_to_http: + s_n_llhttp__internal__n_url_skip_to_http: { + if (p == endp) { + return s_n_llhttp__internal__n_url_skip_to_http; + } + p++; + goto s_n_llhttp__internal__n_req_http_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_fragment: + s_n_llhttp__internal__n_url_fragment: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_fragment; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8; + } + default: { + goto s_n_llhttp__internal__n_error_24; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_query_3: + s_n_llhttp__internal__n_span_end_stub_query_3: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_query_3; + } + p++; + goto s_n_llhttp__internal__n_url_fragment; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query: + s_n_llhttp__internal__n_url_query: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_query; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10; + } + case 4: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11; + } + case 5: { + goto s_n_llhttp__internal__n_span_end_stub_query_3; + } + default: { + goto s_n_llhttp__internal__n_error_25; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_query_or_fragment: + s_n_llhttp__internal__n_url_query_or_fragment: { + if (p == endp) { + return s_n_llhttp__internal__n_url_query_or_fragment; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4; + } + case ' ': { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5; + } + case '#': { + p++; + goto s_n_llhttp__internal__n_url_fragment; + } + case '?': { + p++; + goto s_n_llhttp__internal__n_url_query; + } + default: { + goto s_n_llhttp__internal__n_error_26; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_path: + s_n_llhttp__internal__n_url_path: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_path; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_url_path; + } + default: { + goto s_n_llhttp__internal__n_url_query_or_fragment; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_2: + s_n_llhttp__internal__n_span_start_stub_path_2: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_2; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path: + s_n_llhttp__internal__n_span_start_stub_path: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_stub_path_1: + s_n_llhttp__internal__n_span_start_stub_path_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_stub_path_1; + } + p++; + goto s_n_llhttp__internal__n_url_path; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server_with_at: + s_n_llhttp__internal__n_url_server_with_at: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6, + 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4, + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server_with_at; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14; + } + case 4: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 5: { + goto s_n_llhttp__internal__n_span_start_stub_path_1; + } + case 6: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_error_27; + } + default: { + goto s_n_llhttp__internal__n_error_28; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_server: + s_n_llhttp__internal__n_url_server: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6, + 7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4, + 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_server; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1; + } + case 3: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2; + } + case 4: { + p++; + goto s_n_llhttp__internal__n_url_server; + } + case 5: { + goto s_n_llhttp__internal__n_span_start_stub_path; + } + case 6: { + p++; + goto s_n_llhttp__internal__n_url_query; + } + case 7: { + p++; + goto s_n_llhttp__internal__n_url_server_with_at; + } + default: { + goto s_n_llhttp__internal__n_error_29; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim_1: + s_n_llhttp__internal__n_url_schema_delim_1: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim_1; + } + switch (*p) { + case '/': { + p++; + goto s_n_llhttp__internal__n_url_server; + } + default: { + goto s_n_llhttp__internal__n_error_31; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema_delim: + s_n_llhttp__internal__n_url_schema_delim: { + if (p == endp) { + return s_n_llhttp__internal__n_url_schema_delim; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case '/': { + p++; + goto s_n_llhttp__internal__n_url_schema_delim_1; + } + default: { + goto s_n_llhttp__internal__n_error_31; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_end_stub_schema: + s_n_llhttp__internal__n_span_end_stub_schema: { + if (p == endp) { + return s_n_llhttp__internal__n_span_end_stub_schema; + } + p++; + goto s_n_llhttp__internal__n_url_schema_delim; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_schema: + s_n_llhttp__internal__n_url_schema: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_schema; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case 2: { + goto s_n_llhttp__internal__n_span_end_stub_schema; + } + case 3: { + p++; + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_32; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_url_start: + s_n_llhttp__internal__n_url_start: { + static uint8_t lookup_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + if (p == endp) { + return s_n_llhttp__internal__n_url_start; + } + switch (lookup_table[(uint8_t) *p]) { + case 1: { + p++; + goto s_n_llhttp__internal__n_error_30; + } + case 2: { + goto s_n_llhttp__internal__n_span_start_stub_path_2; + } + case 3: { + goto s_n_llhttp__internal__n_url_schema; + } + default: { + goto s_n_llhttp__internal__n_error_33; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url_1: + s_n_llhttp__internal__n_span_start_llhttp__on_url_1: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_url: + s_n_llhttp__internal__n_span_start_llhttp__on_url: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_url; + goto s_n_llhttp__internal__n_url_server; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_spaces_before_url: + s_n_llhttp__internal__n_req_spaces_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_spaces_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_invoke_is_equal_method; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_first_space_before_url: + s_n_llhttp__internal__n_req_first_space_before_url: { + if (p == endp) { + return s_n_llhttp__internal__n_req_first_space_before_url; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_req_spaces_before_url; + } + default: { + goto s_n_llhttp__internal__n_error_34; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_1: + s_n_llhttp__internal__n_start_req_1: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_1; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob0, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 19; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_1; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_2: + s_n_llhttp__internal__n_start_req_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 16; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_4: + s_n_llhttp__internal__n_start_req_4: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_4; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 22; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_4; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_6: + s_n_llhttp__internal__n_start_req_6: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_6; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_6; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_7: + s_n_llhttp__internal__n_start_req_7: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_7; + } + switch (*p) { + case 'Y': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_5: + s_n_llhttp__internal__n_start_req_5: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_5; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_start_req_6; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_7; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_3: + s_n_llhttp__internal__n_start_req_3: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_3; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_start_req_4; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_5; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_8: + s_n_llhttp__internal__n_start_req_8: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_8; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_8; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_9: + s_n_llhttp__internal__n_start_req_9: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_9; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_9; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_10: + s_n_llhttp__internal__n_start_req_10: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_10; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_10; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_12: + s_n_llhttp__internal__n_start_req_12: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_12; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 31; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_12; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_13: + s_n_llhttp__internal__n_start_req_13: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_13; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_13; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_11: + s_n_llhttp__internal__n_start_req_11: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_11; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_start_req_12; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_13; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_15: + s_n_llhttp__internal__n_start_req_15: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_15; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 24; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_15; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_16: + s_n_llhttp__internal__n_start_req_16: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_16; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 23; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_16; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_18: + s_n_llhttp__internal__n_start_req_18: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_18; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 21; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_18; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_20: + s_n_llhttp__internal__n_start_req_20: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_20; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 30; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_20; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_21: + s_n_llhttp__internal__n_start_req_21: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_21; + } + switch (*p) { + case 'L': { + p++; + match = 10; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_19: + s_n_llhttp__internal__n_start_req_19: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_19; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_20; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_21; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_17: + s_n_llhttp__internal__n_start_req_17: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_17; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_18; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_start_req_19; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_22: + s_n_llhttp__internal__n_start_req_22: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_22; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 11; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_22; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_14: + s_n_llhttp__internal__n_start_req_14: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_14; + } + switch (*p) { + case '-': { + p++; + goto s_n_llhttp__internal__n_start_req_15; + } + case 'E': { + p++; + goto s_n_llhttp__internal__n_start_req_16; + } + case 'K': { + p++; + goto s_n_llhttp__internal__n_start_req_17; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_22; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_23: + s_n_llhttp__internal__n_start_req_23: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_23; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 25; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_23; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_24: + s_n_llhttp__internal__n_start_req_24: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_24; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 6); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_24; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_26: + s_n_llhttp__internal__n_start_req_26: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_26; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 28; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_26; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_27: + s_n_llhttp__internal__n_start_req_27: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_27; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_27; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_30: + s_n_llhttp__internal__n_start_req_30: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_30; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 12; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_30; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_31: + s_n_llhttp__internal__n_start_req_31: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_31; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 13; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_31; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_29: + s_n_llhttp__internal__n_start_req_29: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_29; + } + switch (*p) { + case 'F': { + p++; + goto s_n_llhttp__internal__n_start_req_30; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_31; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_28: + s_n_llhttp__internal__n_start_req_28: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_28; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_start_req_29; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_28; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_33: + s_n_llhttp__internal__n_start_req_33: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_33; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 29; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_33; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_32: + s_n_llhttp__internal__n_start_req_32: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_32; + } + switch (*p) { + case 'R': { + p++; + goto s_n_llhttp__internal__n_start_req_33; + } + case 'T': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_25: + s_n_llhttp__internal__n_start_req_25: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_25; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_26; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_27; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_start_req_28; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_start_req_32; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_36: + s_n_llhttp__internal__n_start_req_36: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_36; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 17; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_36; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_37: + s_n_llhttp__internal__n_start_req_37: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_37; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 20; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_37; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_35: + s_n_llhttp__internal__n_start_req_35: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_35; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_start_req_36; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_37; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_34: + s_n_llhttp__internal__n_start_req_34: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_34; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_start_req_35; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_39: + s_n_llhttp__internal__n_start_req_39: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_39; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 14; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_39; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_40: + s_n_llhttp__internal__n_start_req_40: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_40; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 33; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_40; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_41: + s_n_llhttp__internal__n_start_req_41: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_41; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 7); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 26; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_41; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_38: + s_n_llhttp__internal__n_start_req_38: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_38; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_start_req_39; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_40; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_start_req_41; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_42: + s_n_llhttp__internal__n_start_req_42: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_42; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 4); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_42; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_45: + s_n_llhttp__internal__n_start_req_45: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_45; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 18; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_45; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_47: + s_n_llhttp__internal__n_start_req_47: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_47; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 32; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_47; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_48: + s_n_llhttp__internal__n_start_req_48: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_48; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 15; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_48; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_46: + s_n_llhttp__internal__n_start_req_46: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_46; + } + switch (*p) { + case 'I': { + p++; + goto s_n_llhttp__internal__n_start_req_47; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_48; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_49: + s_n_llhttp__internal__n_start_req_49: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_req_49; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 8); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 27; + goto s_n_llhttp__internal__n_invoke_store_method_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_req_49; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_44: + s_n_llhttp__internal__n_start_req_44: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_44; + } + switch (*p) { + case 'B': { + p++; + goto s_n_llhttp__internal__n_start_req_45; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_start_req_46; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_start_req_49; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_43: + s_n_llhttp__internal__n_start_req_43: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_43; + } + switch (*p) { + case 'N': { + p++; + goto s_n_llhttp__internal__n_start_req_44; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req: + s_n_llhttp__internal__n_start_req: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req; + } + switch (*p) { + case 'A': { + p++; + goto s_n_llhttp__internal__n_start_req_1; + } + case 'B': { + p++; + goto s_n_llhttp__internal__n_start_req_2; + } + case 'C': { + p++; + goto s_n_llhttp__internal__n_start_req_3; + } + case 'D': { + p++; + goto s_n_llhttp__internal__n_start_req_8; + } + case 'G': { + p++; + goto s_n_llhttp__internal__n_start_req_9; + } + case 'H': { + p++; + goto s_n_llhttp__internal__n_start_req_10; + } + case 'L': { + p++; + goto s_n_llhttp__internal__n_start_req_11; + } + case 'M': { + p++; + goto s_n_llhttp__internal__n_start_req_14; + } + case 'N': { + p++; + goto s_n_llhttp__internal__n_start_req_23; + } + case 'O': { + p++; + goto s_n_llhttp__internal__n_start_req_24; + } + case 'P': { + p++; + goto s_n_llhttp__internal__n_start_req_25; + } + case 'R': { + p++; + goto s_n_llhttp__internal__n_start_req_34; + } + case 'S': { + p++; + goto s_n_llhttp__internal__n_start_req_38; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_start_req_42; + } + case 'U': { + p++; + goto s_n_llhttp__internal__n_start_req_43; + } + default: { + goto s_n_llhttp__internal__n_error_42; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_line_almost_done: + s_n_llhttp__internal__n_res_line_almost_done: { + if (p == endp) { + return s_n_llhttp__internal__n_res_line_almost_done; + } + p++; + goto s_n_llhttp__internal__n_header_field_start; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status: + s_n_llhttp__internal__n_res_status: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status; + } + case 13: { + goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1; + } + default: { + p++; + goto s_n_llhttp__internal__n_res_status; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_span_start_llhttp__on_status: + s_n_llhttp__internal__n_span_start_llhttp__on_status: { + if (p == endp) { + return s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + state->_span_pos0 = (void*) p; + state->_span_cb0 = llhttp__on_status; + goto s_n_llhttp__internal__n_res_status; + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_start: + s_n_llhttp__internal__n_res_status_start: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_header_field_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + } + default: { + goto s_n_llhttp__internal__n_span_start_llhttp__on_status; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code_otherwise: + s_n_llhttp__internal__n_res_status_code_otherwise: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code_otherwise; + } + switch (*p) { + case 10: { + goto s_n_llhttp__internal__n_res_status_start; + } + case 13: { + goto s_n_llhttp__internal__n_res_status_start; + } + case ' ': { + p++; + goto s_n_llhttp__internal__n_res_status_start; + } + default: { + goto s_n_llhttp__internal__n_error_36; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_status_code: + s_n_llhttp__internal__n_res_status_code: { + if (p == endp) { + return s_n_llhttp__internal__n_res_status_code; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_mul_add_status_code; + } + default: { + goto s_n_llhttp__internal__n_res_status_code_otherwise; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_end: + s_n_llhttp__internal__n_res_http_end: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_end; + } + switch (*p) { + case ' ': { + p++; + goto s_n_llhttp__internal__n_invoke_update_status_code; + } + default: { + goto s_n_llhttp__internal__n_error_37; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_minor: + s_n_llhttp__internal__n_res_http_minor: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_minor; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_minor_1; + } + default: { + goto s_n_llhttp__internal__n_error_38; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_dot: + s_n_llhttp__internal__n_res_http_dot: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_dot; + } + switch (*p) { + case '.': { + p++; + goto s_n_llhttp__internal__n_res_http_minor; + } + default: { + goto s_n_llhttp__internal__n_error_39; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_res_http_major: + s_n_llhttp__internal__n_res_http_major: { + if (p == endp) { + return s_n_llhttp__internal__n_res_http_major; + } + switch (*p) { + case '0': { + p++; + match = 0; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '1': { + p++; + match = 1; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '2': { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '3': { + p++; + match = 3; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '4': { + p++; + match = 4; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '5': { + p++; + match = 5; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '6': { + p++; + match = 6; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '7': { + p++; + match = 7; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '8': { + p++; + match = 8; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + case '9': { + p++; + match = 9; + goto s_n_llhttp__internal__n_invoke_store_http_major_1; + } + default: { + goto s_n_llhttp__internal__n_error_40; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_res: + s_n_llhttp__internal__n_start_res: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_start_res; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 5); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_res_http_major; + } + case kMatchPause: { + return s_n_llhttp__internal__n_start_res; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_43; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_2: + s_n_llhttp__internal__n_req_or_res_method_2: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 2); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + match = 2; + goto s_n_llhttp__internal__n_invoke_store_method; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_2; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_3: + s_n_llhttp__internal__n_req_or_res_method_3: { + llparse_match_t match_seq; + + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3); + p = match_seq.current; + switch (match_seq.status) { + case kMatchComplete: { + p++; + goto s_n_llhttp__internal__n_invoke_update_type_1; + } + case kMatchPause: { + return s_n_llhttp__internal__n_req_or_res_method_3; + } + case kMatchMismatch: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method_1: + s_n_llhttp__internal__n_req_or_res_method_1: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method_1; + } + switch (*p) { + case 'E': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_2; + } + case 'T': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_3; + } + default: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_req_or_res_method: + s_n_llhttp__internal__n_req_or_res_method: { + if (p == endp) { + return s_n_llhttp__internal__n_req_or_res_method; + } + switch (*p) { + case 'H': { + p++; + goto s_n_llhttp__internal__n_req_or_res_method_1; + } + default: { + goto s_n_llhttp__internal__n_error_41; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start_req_or_res: + s_n_llhttp__internal__n_start_req_or_res: { + if (p == endp) { + return s_n_llhttp__internal__n_start_req_or_res; + } + switch (*p) { + case 'H': { + goto s_n_llhttp__internal__n_req_or_res_method; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_type_2; + } + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_invoke_load_type: + s_n_llhttp__internal__n_invoke_load_type: { + switch (llhttp__internal__c_load_type(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_start_req; + case 2: + goto s_n_llhttp__internal__n_start_res; + default: + goto s_n_llhttp__internal__n_start_req_or_res; + } + /* UNREACHABLE */; + abort(); + } + case s_n_llhttp__internal__n_start: + s_n_llhttp__internal__n_start: { + if (p == endp) { + return s_n_llhttp__internal__n_start; + } + switch (*p) { + case 10: { + p++; + goto s_n_llhttp__internal__n_start; + } + case 13: { + p++; + goto s_n_llhttp__internal__n_start; + } + default: { + goto s_n_llhttp__internal__n_invoke_update_finish; + } + } + /* UNREACHABLE */; + abort(); + } + default: + /* UNREACHABLE */ + abort(); + } + s_n_llhttp__internal__n_error_30: { + state->error = 0x7; + state->reason = "Invalid characters in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_5: { + state->error = 0x14; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_8: { + state->error = 0x11; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_7: { + state->error = 0x14; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_10: { + state->error = 0x13; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + case 20: + goto s_n_llhttp__internal__n_pause_7; + default: + goto s_n_llhttp__internal__n_error_10; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_9: { + state->error = 0x4; + state->reason = "Content-Length can't be present with chunked encoding"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_2: { + state->error = 0x14; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_3: { + state->error = 0x11; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_pause_1; + case 20: + goto s_n_llhttp__internal__n_pause_2; + default: + goto s_n_llhttp__internal__n_error_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_4: { + state->error = 0xc; + state->reason = "Chunk size overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length: { + switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_4; + default: + goto s_n_llhttp__internal__n_chunk_size; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_3: { + state->error = 0x14; + state->reason = "on_chunk_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_6: { + state->error = 0x13; + state->reason = "`on_chunk_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: { + switch (llhttp__on_chunk_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_update_content_length; + case 20: + goto s_n_llhttp__internal__n_pause_3; + default: + goto s_n_llhttp__internal__n_error_6; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_chunk_data_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags: { + switch (llhttp__internal__c_or_flags(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_4: { + state->error = 0x14; + state->reason = "on_chunk_header pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_5: { + state->error = 0x12; + state->reason = "`on_chunk_header` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: { + switch (llhttp__on_chunk_header(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_is_equal_content_length; + case 20: + goto s_n_llhttp__internal__n_pause_4; + default: + goto s_n_llhttp__internal__n_error_5; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_7: { + state->error = 0xc; + state->reason = "Invalid character in chunk size"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_body_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_body(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + return s_error; + } + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish_1: { + switch (llhttp__internal__c_update_finish_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_eof; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause: { + state->error = 0x14; + state->reason = "on_message_complete pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_2: { + state->error = 0x11; + state->reason = "`on_message_complete` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: { + switch (llhttp__on_message_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; + case 20: + goto s_n_llhttp__internal__n_pause; + default: + goto s_n_llhttp__internal__n_error_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_1: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_2: { + switch (llhttp__internal__c_or_flags_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_upgrade: { + switch (llhttp__internal__c_update_upgrade(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_or_flags_2; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_6: { + state->error = 0x14; + state->reason = "Paused by on_headers_complete"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_1: { + state->error = 0x10; + state->reason = "User callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: { + switch (llhttp__on_headers_complete(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; + case 1: + goto s_n_llhttp__internal__n_invoke_or_flags_1; + case 2: + goto s_n_llhttp__internal__n_invoke_update_upgrade; + case 20: + goto s_n_llhttp__internal__n_pause_6; + default: + goto s_n_llhttp__internal__n_error_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: { + switch (llhttp__before_headers_complete(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_1: { + switch (llhttp__internal__c_test_flags_1(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_error_9; + default: + goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags: { + switch (llhttp__internal__c_test_flags(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1; + default: + goto s_n_llhttp__internal__n_invoke_test_flags_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; + return s_error; + } + goto s_n_llhttp__internal__n_header_field_start; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_3: { + switch (llhttp__internal__c_or_flags_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_4: { + switch (llhttp__internal__c_or_flags_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_5: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_6: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_3; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_4; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_5; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_6; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_1: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_7: { + switch (llhttp__internal__c_or_flags_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_8: { + switch (llhttp__internal__c_or_flags_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_9: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_1; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_10: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_2: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_7; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_8; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_9; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_10; + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_11: { + state->error = 0x3; + state->reason = "Missing expected LF after header value"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_12: { + state->error = 0xa; + state->reason = "Invalid header value char"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_3: { + switch (llhttp__internal__c_update_header_state(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_11: { + switch (llhttp__internal__c_or_flags_3(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_12: { + switch (llhttp__internal__c_or_flags_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_13: { + switch (llhttp__internal__c_or_flags_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_3; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_14: { + switch (llhttp__internal__c_or_flags_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_3: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 5: + goto s_n_llhttp__internal__n_invoke_or_flags_11; + case 6: + goto s_n_llhttp__internal__n_invoke_or_flags_12; + case 7: + goto s_n_llhttp__internal__n_invoke_or_flags_13; + case 8: + goto s_n_llhttp__internal__n_invoke_or_flags_14; + default: + goto s_n_llhttp__internal__n_header_value_connection; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_4: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_token; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_2: { + switch (llhttp__internal__c_update_header_state_2(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_5: { + switch (llhttp__internal__c_update_header_state_5(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_6: { + switch (llhttp__internal__c_update_header_state_6(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_connection_ws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_14; + return s_error; + } + goto s_n_llhttp__internal__n_error_14; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_content_length_1: { + switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3; + default: + goto s_n_llhttp__internal__n_header_value_content_length; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_7: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_15: { + switch (llhttp__internal__c_or_flags_15(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_value(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_15; + return s_error; + } + goto s_n_llhttp__internal__n_error_15; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_13: { + state->error = 0x4; + state->reason = "Duplicate Content-Length"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_test_flags_2: { + switch (llhttp__internal__c_test_flags_2(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_header_value_content_length; + default: + goto s_n_llhttp__internal__n_error_13; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_8: { + switch (llhttp__internal__c_update_header_state_8(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_value_discard_rws; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_or_flags_16: { + switch (llhttp__internal__c_or_flags_16(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_header_state_7; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_load_header_state_1: { + switch (llhttp__internal__c_load_header_state(state, p, endp)) { + case 1: + goto s_n_llhttp__internal__n_header_value_connection; + case 2: + goto s_n_llhttp__internal__n_invoke_test_flags_2; + case 3: + goto s_n_llhttp__internal__n_header_value_te_chunked; + case 4: + goto s_n_llhttp__internal__n_invoke_or_flags_16; + default: + goto s_n_llhttp__internal__n_header_value; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_discard_ws; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_header_field(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_discard_ws; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_value_discard_ws; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_16: { + state->error = 0xa; + state->reason = "Invalid header token"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_9: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_header_state: { + switch (llhttp__internal__c_store_header_state(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_header_field_colon; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_header_state_10: { + switch (llhttp__internal__c_update_header_state_4(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_general; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_minor: { + switch (llhttp__internal__c_update_http_minor(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_header_field_start; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_http_major: { + switch (llhttp__internal__c_update_http_major(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_update_http_minor; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_3: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_17: { + state->error = 0x7; + state->reason = "Expected CRLF"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_4: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_18: { + state->error = 0x9; + state->reason = "Expected CRLF after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_http_end; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_19: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_20: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_21: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_23: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_22: { + state->error = 0x8; + state->reason = "Expected SOURCE method for ICE/x.x request"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_is_equal_method_1: { + switch (llhttp__internal__c_is_equal_method_1(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_error_22; + default: + goto s_n_llhttp__internal__n_req_http_major; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_5: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_6: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_7: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_8: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_24: { + state->error = 0x7; + state->reason = "Invalid char in url fragment start"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_9: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_10: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_11: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_25: { + state->error = 0x7; + state->reason = "Invalid char in url query"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_26: { + state->error = 0x7; + state->reason = "Invalid char in url path"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_2: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_12: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_13: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_lf_to_http09; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_url_14: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_url(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; + return s_error; + } + goto s_n_llhttp__internal__n_url_skip_to_http; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_27: { + state->error = 0x7; + state->reason = "Double @ in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_28: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_29: { + state->error = 0x7; + state->reason = "Unexpected char in url server"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_31: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_32: { + state->error = 0x7; + state->reason = "Unexpected char in url schema"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_33: { + state->error = 0x7; + state->reason = "Unexpected start char in url"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_is_equal_method: { + switch (llhttp__internal__c_is_equal_method(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1; + default: + goto s_n_llhttp__internal__n_span_start_llhttp__on_url; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_34: { + state->error = 0x6; + state->reason = "Expected space after method"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method_1: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_req_first_space_before_url; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_42: { + state->error = 0x6; + state->reason = "Invalid method encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_35: { + state->error = 0xd; + state->reason = "Response overflow"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_mul_add_status_code: { + switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { + case 1: + goto s_n_llhttp__internal__n_error_35; + default: + goto s_n_llhttp__internal__n_res_status_code; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_header_field_start; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_span_end_llhttp__on_status_1: { + const unsigned char* start; + int err; + + start = state->_span_pos0; + state->_span_pos0 = NULL; + err = llhttp__on_status(state, start, p); + if (err != 0) { + state->error = err; + state->error_pos = (const char*) (p + 1); + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done; + return s_error; + } + p++; + goto s_n_llhttp__internal__n_res_line_almost_done; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_36: { + state->error = 0xd; + state->reason = "Invalid response status"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_status_code: { + switch (llhttp__internal__c_update_status_code(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_res_status_code; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_37: { + state->error = 0x9; + state->reason = "Expected space after version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_minor_1: { + switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_res_http_end; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_38: { + state->error = 0x9; + state->reason = "Invalid minor version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_39: { + state->error = 0x9; + state->reason = "Expected dot"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_http_major_1: { + switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_res_http_dot; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_40: { + state->error = 0x9; + state->reason = "Invalid major version"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_43: { + state->error = 0x8; + state->reason = "Expected HTTP/"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_req_first_space_before_url; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_store_method: { + switch (llhttp__internal__c_store_method(state, p, endp, match)) { + default: + goto s_n_llhttp__internal__n_invoke_update_type; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error_41: { + state->error = 0x8; + state->reason = "Invalid word encountered"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type_1: { + switch (llhttp__internal__c_update_type_1(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_res_http_major; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_type_2: { + switch (llhttp__internal__c_update_type(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_start_req; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_pause_8: { + state->error = 0x14; + state->reason = "on_message_begin pause"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_error: { + state->error = 0xf; + state->reason = "`on_message_begin` callback error"; + state->error_pos = (const char*) p; + state->_current = (void*) (intptr_t) s_error; + return s_error; + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: { + switch (llhttp__on_message_begin(state, p, endp)) { + case 0: + goto s_n_llhttp__internal__n_invoke_load_type; + case 20: + goto s_n_llhttp__internal__n_pause_8; + default: + goto s_n_llhttp__internal__n_error; + } + /* UNREACHABLE */; + abort(); + } + s_n_llhttp__internal__n_invoke_update_finish: { + switch (llhttp__internal__c_update_finish(state, p, endp)) { + default: + goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin; + } + /* UNREACHABLE */; + abort(); + } +} + +int llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) { + llparse_state_t next; + + /* check lingering errors */ + if (state->error != 0) { + return state->error; + } + + /* restart spans */ + if (state->_span_pos0 != NULL) { + state->_span_pos0 = (void*) p; + } + + next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp); + if (next == s_error) { + return state->error; + } + state->_current = (void*) (intptr_t) next; + + /* execute spans */ + if (state->_span_pos0 != NULL) { + int error; + + error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp); + if (error != 0) { + state->error = error; + state->error_pos = endp; + } + } + + return 0; +} \ No newline at end of file diff --git a/node.gyp b/node.gyp index cdea08bbbc993f..83bd412dea6c9d 100644 --- a/node.gyp +++ b/node.gyp @@ -12,6 +12,7 @@ 'force_dynamic_crt%': 0, 'node_module_version%': '', 'node_shared_zlib%': 'false', + 'node_experimental_http_parser%': 'false', 'node_shared_http_parser%': 'false', 'node_shared_cares%': 'false', 'node_shared_libuv%': 'false', diff --git a/node.gypi b/node.gypi index eba49be69c3cc5..fdf81b7465b906 100644 --- a/node.gypi +++ b/node.gypi @@ -163,9 +163,14 @@ ], }], - [ 'node_shared_http_parser=="false"', { - 'dependencies': [ 'deps/http_parser/http_parser.gyp:http_parser' ], - }], + [ 'node_experimental_http_parser=="true"', { + 'defines': [ 'NODE_EXPERIMENTAL_HTTP' ], + 'dependencies': [ 'deps/llhttp/llhttp.gyp:llhttp' ], + }, { + 'conditions': [ [ 'node_shared_http_parser=="false"', { + 'dependencies': [ 'deps/http_parser/http_parser.gyp:http_parser' ], + } ] ], + } ], [ 'node_shared_cares=="false"', { 'dependencies': [ 'deps/cares/cares.gyp:cares' ], diff --git a/src/env.h b/src/env.h index eed9b8cd172d67..dec0b9d4c00994 100644 --- a/src/env.h +++ b/src/env.h @@ -262,6 +262,7 @@ struct PackageConfig { V(raw_string, "raw") \ V(read_host_object_string, "_readHostObject") \ V(readable_string, "readable") \ + V(reason_string, "reason") \ V(refresh_string, "refresh") \ V(regexp_string, "regexp") \ V(rename_string, "rename") \ diff --git a/src/http_parser_adaptor.h b/src/http_parser_adaptor.h new file mode 100644 index 00000000000000..6d786bd09519b5 --- /dev/null +++ b/src/http_parser_adaptor.h @@ -0,0 +1,24 @@ +#ifndef SRC_HTTP_PARSER_ADAPTOR_H_ +#define SRC_HTTP_PARSER_ADAPTOR_H_ + +#ifdef NODE_EXPERIMENTAL_HTTP +# include "llhttp.h" + +typedef llhttp_type_t parser_type_t; +typedef llhttp_errno_t parser_errno_t; +typedef llhttp_settings_t parser_settings_t; +typedef llhttp_t parser_t; + +#else /* !NODE_EXPERIMENTAL_HTTP */ +# include "http_parser.h" + +typedef enum http_parser_type parser_type_t; +typedef enum http_errno parser_errno_t; +typedef http_parser_settings parser_settings_t; +typedef http_parser parser_t; + +#define HPE_USER HPE_UNKNOWN + +#endif /* NODE_EXPERIMENTAL_HTTP */ + +#endif /* SRC_HTTP_PARSER_ADAPTOR_H_ */ diff --git a/src/inspector_socket.cc b/src/inspector_socket.cc index dc36359b5c927c..8c2d0a5a22da28 100644 --- a/src/inspector_socket.cc +++ b/src/inspector_socket.cc @@ -1,6 +1,6 @@ #include "inspector_socket.h" -#include "http_parser.h" +#include "http_parser_adaptor.h" #include "util-inl.h" #define NODE_WANT_INTERNALS 1 @@ -433,8 +433,13 @@ class HttpHandler : public ProtocolHandler { explicit HttpHandler(InspectorSocket* inspector, TcpHolder::Pointer tcp) : ProtocolHandler(inspector, std::move(tcp)), parsing_value_(false) { +#ifdef NODE_EXPERIMENTAL_HTTP + llhttp_init(&parser_, HTTP_REQUEST, &parser_settings); + llhttp_settings_init(&parser_settings); +#else /* !NODE_EXPERIMENTAL_HTTP */ http_parser_init(&parser_, HTTP_REQUEST); http_parser_settings_init(&parser_settings); +#endif /* NODE_EXPERIMENTAL_HTTP */ parser_settings.on_header_field = OnHeaderField; parser_settings.on_header_value = OnHeaderValue; parser_settings.on_message_complete = OnMessageComplete; @@ -478,9 +483,20 @@ class HttpHandler : public ProtocolHandler { } void OnData(std::vector* data) override { + parser_errno_t err; +#ifdef NODE_EXPERIMENTAL_HTTP + err = llhttp_execute(&parser_, data->data(), data->size()); + + if (err == HPE_PAUSED_UPGRADE) { + err = HPE_OK; + llhttp_resume_after_upgrade(&parser_); + } +#else /* !NODE_EXPERIMENTAL_HTTP */ http_parser_execute(&parser_, &parser_settings, data->data(), data->size()); + err = HTTP_PARSER_ERRNO(&parser_); +#endif /* NODE_EXPERIMENTAL_HTTP */ data->clear(); - if (parser_.http_errno != HPE_OK) { + if (err != HPE_OK) { CancelHandshake(); } // Event handling may delete *this @@ -517,14 +533,14 @@ class HttpHandler : public ProtocolHandler { handler->inspector()->SwitchProtocol(nullptr); } - static int OnHeaderValue(http_parser* parser, const char* at, size_t length) { + static int OnHeaderValue(parser_t* parser, const char* at, size_t length) { HttpHandler* handler = From(parser); handler->parsing_value_ = true; handler->headers_[handler->current_header_].append(at, length); return 0; } - static int OnHeaderField(http_parser* parser, const char* at, size_t length) { + static int OnHeaderField(parser_t* parser, const char* at, size_t length) { HttpHandler* handler = From(parser); if (handler->parsing_value_) { handler->parsing_value_ = false; @@ -534,17 +550,17 @@ class HttpHandler : public ProtocolHandler { return 0; } - static int OnPath(http_parser* parser, const char* at, size_t length) { + static int OnPath(parser_t* parser, const char* at, size_t length) { HttpHandler* handler = From(parser); handler->path_.append(at, length); return 0; } - static HttpHandler* From(http_parser* parser) { + static HttpHandler* From(parser_t* parser) { return node::ContainerOf(&HttpHandler::parser_, parser); } - static int OnMessageComplete(http_parser* parser) { + static int OnMessageComplete(parser_t* parser) { // Event needs to be fired after the parser is done. HttpHandler* handler = From(parser); handler->events_.push_back( @@ -581,8 +597,8 @@ class HttpHandler : public ProtocolHandler { } bool parsing_value_; - http_parser parser_; - http_parser_settings parser_settings; + parser_t parser_; + parser_settings_t parser_settings; std::vector events_; std::string current_header_; std::map headers_; diff --git a/src/node.cc b/src/node.cc index 4fd18147855091..9ed73b60511bbb 100644 --- a/src/node.cc +++ b/src/node.cc @@ -53,7 +53,11 @@ #include "async_wrap-inl.h" #include "env-inl.h" #include "handle_wrap.h" -#include "http_parser.h" +#ifdef NODE_EXPERIMENTAL_HTTP +# include "llhttp.h" +#else /* !NODE_EXPERIMENTAL_HTTP */ +# include "http_parser.h" +#endif /* NODE_EXPERIMENTAL_HTTP */ #include "nghttp2/nghttp2ver.h" #include "req_wrap-inl.h" #include "string_bytes.h" @@ -179,6 +183,22 @@ static node_module* modlist_internal; static node_module* modlist_linked; static node_module* modlist_addon; +#ifdef NODE_EXPERIMENTAL_HTTP +static const char llhttp_version[] = + NODE_STRINGIFY(LLHTTP_VERSION_MAJOR) + "." + NODE_STRINGIFY(LLHTTP_VERSION_MINOR) + "." + NODE_STRINGIFY(LLHTTP_VERSION_PATCH); +#else /* !NODE_EXPERIMENTAL_HTTP */ +static const char http_parser_version[] = + NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) + "." + NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) + "." + NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); +#endif /* NODE_EXPERIMENTAL_HTTP */ + // Bit flag used to track security reverts (see node_revert.h) unsigned int reverted = 0; @@ -217,17 +237,15 @@ class NodeTraceStateObserver : auto trace_process = tracing::TracedValue::Create(); trace_process->BeginDictionary("versions"); - const char http_parser_version[] = - NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) - "." - NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) - "." - NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); +#ifdef NODE_EXPERIMENTAL_HTTP + trace_process->SetString("llhttp", llhttp_version); +#else /* !NODE_EXPERIMENTAL_HTTP */ + trace_process->SetString("http_parser", http_parser_version); +#endif /* NODE_EXPERIMENTAL_HTTP */ const char node_napi_version[] = NODE_STRINGIFY(NAPI_VERSION); const char node_modules_version[] = NODE_STRINGIFY(NODE_MODULE_VERSION); - trace_process->SetString("http_parser", http_parser_version); trace_process->SetString("node", NODE_VERSION_STRING); trace_process->SetString("v8", V8::GetVersion()); trace_process->SetString("uv", uv_version_string()); @@ -1340,14 +1358,16 @@ void SetupProcessObject(Environment* env, Local versions = Object::New(env->isolate()); READONLY_PROPERTY(process, "versions", versions); - const char http_parser_version[] = NODE_STRINGIFY(HTTP_PARSER_VERSION_MAJOR) - "." - NODE_STRINGIFY(HTTP_PARSER_VERSION_MINOR) - "." - NODE_STRINGIFY(HTTP_PARSER_VERSION_PATCH); +#ifdef NODE_EXPERIMENTAL_HTTP + READONLY_PROPERTY(versions, + "llhttp", + FIXED_ONE_BYTE_STRING(env->isolate(), llhttp_version)); +#else /* !NODE_EXPERIMENTAL_HTTP */ READONLY_PROPERTY(versions, "http_parser", FIXED_ONE_BYTE_STRING(env->isolate(), http_parser_version)); +#endif /* NODE_EXPERIMENTAL_HTTP */ + // +1 to get rid of the leading 'v' READONLY_PROPERTY(versions, "node", diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index b82710480de4bc..482c7263ca719c 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -25,7 +25,6 @@ #include "async_wrap-inl.h" #include "env-inl.h" -#include "http_parser.h" #include "stream_base-inl.h" #include "util-inl.h" #include "v8.h" @@ -33,6 +32,8 @@ #include // free() #include // strdup() +#include "http_parser_adaptor.h" + // This is a binding to http_parser (https://github.com/nodejs/http-parser) // The goal is to decouple sockets from parsing for more javascript-level // agility. A Buffer is read from a socket and passed to parser.execute(). @@ -148,7 +149,7 @@ struct StringPtr { class Parser : public AsyncWrap, public StreamListener { public: - Parser(Environment* env, Local wrap, enum http_parser_type type) + Parser(Environment* env, Local wrap, parser_type_t type) : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER), current_buffer_len_(0), current_buffer_data_(nullptr) { @@ -172,18 +173,33 @@ class Parser : public AsyncWrap, public StreamListener { int on_url(const char* at, size_t length) { + int rv = TrackHeader(length); + if (rv != 0) { + return rv; + } + url_.Update(at, length); return 0; } int on_status(const char* at, size_t length) { + int rv = TrackHeader(length); + if (rv != 0) { + return rv; + } + status_message_.Update(at, length); return 0; } int on_header_field(const char* at, size_t length) { + int rv = TrackHeader(length); + if (rv != 0) { + return rv; + } + if (num_fields_ == num_values_) { // start of new field name num_fields_++; @@ -206,6 +222,11 @@ class Parser : public AsyncWrap, public StreamListener { int on_header_value(const char* at, size_t length) { + int rv = TrackHeader(length); + if (rv != 0) { + return rv; + } + if (num_values_ != num_fields_) { // start of new header value num_values_++; @@ -222,6 +243,10 @@ class Parser : public AsyncWrap, public StreamListener { int on_headers_complete() { +#ifdef NODE_EXPERIMENTAL_HTTP + header_nread_ = 0; +#endif /* NODE_EXPERIMENTAL_HTTP */ + // Arguments for the on-headers-complete javascript callback. This // list needs to be kept in sync with the actual argument list for // `parserOnHeadersComplete` in lib/_http_common.js. @@ -279,8 +304,15 @@ class Parser : public AsyncWrap, public StreamListener { argv[A_VERSION_MAJOR] = Integer::New(env()->isolate(), parser_.http_major); argv[A_VERSION_MINOR] = Integer::New(env()->isolate(), parser_.http_minor); + bool should_keep_alive; +#ifdef NODE_EXPERIMENTAL_HTTP + should_keep_alive = llhttp_should_keep_alive(&parser_); +#else /* !NODE_EXPERIMENTAL_HTTP */ + should_keep_alive = http_should_keep_alive(&parser_); +#endif /* NODE_EXPERIMENTAL_HTTP */ + argv[A_SHOULD_KEEP_ALIVE] = - Boolean::New(env()->isolate(), http_should_keep_alive(&parser_)); + Boolean::New(env()->isolate(), should_keep_alive); argv[A_UPGRADE] = Boolean::New(env()->isolate(), parser_.upgrade); @@ -332,7 +364,10 @@ class Parser : public AsyncWrap, public StreamListener { if (r.IsEmpty()) { got_exception_ = true; - return -1; +#ifdef NODE_EXPERIMENTAL_HTTP + llhttp_set_error_reason(&parser_, "JS Exception"); +#endif /* NODE_EXPERIMENTAL_HTTP */ + return HPE_USER; } return 0; @@ -357,18 +392,33 @@ class Parser : public AsyncWrap, public StreamListener { if (r.IsEmpty()) { got_exception_ = true; - return -1; + return HPE_USER; } return 0; } +#ifdef NODE_EXPERIMENTAL_HTTP + // Reset nread for the next chunk + int on_chunk_header() { + header_nread_ = 0; + return 0; + } + + + // Reset nread for the next chunk + int on_chunk_complete() { + header_nread_ = 0; + return 0; + } +#endif /* NODE_EXPERIMENTAL_HTTP */ + static void New(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsInt32()); - http_parser_type type = - static_cast(args[0].As()->Value()); + parser_type_t type = + static_cast(args[0].As()->Value()); CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE); new Parser(env, args.This(), type); } @@ -434,30 +484,11 @@ class Parser : public AsyncWrap, public StreamListener { static void Finish(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - Parser* parser; ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder()); CHECK(parser->current_buffer_.IsEmpty()); - parser->got_exception_ = false; - - int rv = http_parser_execute(&(parser->parser_), &settings, nullptr, 0); - - if (parser->got_exception_) - return; - - if (rv != 0) { - enum http_errno err = HTTP_PARSER_ERRNO(&parser->parser_); - - Local e = Exception::Error(env->parse_error_string()); - Local obj = e.As(); - obj->Set(env->bytes_parsed_string(), Integer::New(env->isolate(), 0)); - obj->Set(env->code_string(), - OneByteString(env->isolate(), http_errno_name(err))); - - args.GetReturnValue().Set(e); - } + parser->Execute(nullptr, 0); } @@ -467,8 +498,8 @@ class Parser : public AsyncWrap, public StreamListener { CHECK(args[0]->IsInt32()); CHECK(args[1]->IsBoolean()); bool isReused = args[1]->IsTrue(); - http_parser_type type = - static_cast(args[0].As()->Value()); + parser_type_t type = + static_cast(args[0].As()->Value()); CHECK(type == HTTP_REQUEST || type == HTTP_RESPONSE); Parser* parser; @@ -492,7 +523,21 @@ class Parser : public AsyncWrap, public StreamListener { ASSIGN_OR_RETURN_UNWRAP(&parser, args.Holder()); // Should always be called from the same context. CHECK_EQ(env, parser->env()); + +#ifdef NODE_EXPERIMENTAL_HTTP + if (parser->execute_depth_) { + parser->pending_pause_ = should_pause; + return; + } + + if (should_pause) { + llhttp_pause(&parser->parser_); + } else { + llhttp_resume(&parser->parser_); + } +#else /* !NODE_EXPERIMENTAL_HTTP */ http_parser_pause(&parser->parser_, should_pause); +#endif /* NODE_EXPERIMENTAL_HTTP */ } @@ -602,10 +647,46 @@ class Parser : public AsyncWrap, public StreamListener { current_buffer_data_ = data; got_exception_ = false; - size_t nparsed = - http_parser_execute(&parser_, &settings, data, len); + parser_errno_t err; + +#ifdef NODE_EXPERIMENTAL_HTTP + // Do not allow re-entering `http_parser_execute()` + CHECK_EQ(execute_depth_, 0); + + execute_depth_++; + if (data == nullptr) { + err = llhttp_finish(&parser_); + } else { + err = llhttp_execute(&parser_, data, len); + Save(); + } + execute_depth_--; + + // Calculate bytes read and resume after Upgrade/CONNECT pause + size_t nread = len; + if (err != HPE_OK) { + nread = llhttp_get_error_pos(&parser_) - data; + + // This isn't a real pause, just a way to stop parsing early. + if (err == HPE_PAUSED_UPGRADE) { + err = HPE_OK; + llhttp_resume_after_upgrade(&parser_); + } + } + + // Apply pending pause + if (pending_pause_) { + pending_pause_ = false; + llhttp_pause(&parser_); + } +#else /* !NODE_EXPERIMENTAL_HTTP */ + size_t nread = http_parser_execute(&parser_, &settings, data, len); + if (data != nullptr) { + Save(); + } - Save(); + err = HTTP_PARSER_ERRNO(&parser_); +#endif /* NODE_EXPERIMENTAL_HTTP */ // Unassign the 'buffer_' variable current_buffer_.Clear(); @@ -616,22 +697,29 @@ class Parser : public AsyncWrap, public StreamListener { if (got_exception_) return scope.Escape(Local()); - Local nparsed_obj = Integer::New(env()->isolate(), nparsed); + Local nread_obj = Integer::New(env()->isolate(), nread); + // If there was a parse error in one of the callbacks // TODO(bnoordhuis) What if there is an error on EOF? - if (!parser_.upgrade && nparsed != len) { - enum http_errno err = HTTP_PARSER_ERRNO(&parser_); - + if (!parser_.upgrade && err != HPE_OK) { Local e = Exception::Error(env()->parse_error_string()); Local obj = e->ToObject(env()->isolate()->GetCurrentContext()) .ToLocalChecked(); - obj->Set(env()->bytes_parsed_string(), nparsed_obj); + obj->Set(env()->bytes_parsed_string(), nread_obj); +#ifdef NODE_EXPERIMENTAL_HTTP + obj->Set(env()->code_string(), + OneByteString(env()->isolate(), llhttp_errno_name(err))); + obj->Set(env()->reason_string(), + OneByteString(env()->isolate(), parser_.reason)); +#else /* !NODE_EXPERIMENTAL_HTTP */ obj->Set(env()->code_string(), OneByteString(env()->isolate(), http_errno_name(err))); +#endif /* NODE_EXPERIMENTAL_HTTP */ return scope.Escape(e); } - return scope.Escape(nparsed_obj); + + return scope.Escape(nread_obj); } Local CreateHeaders() { @@ -684,8 +772,12 @@ class Parser : public AsyncWrap, public StreamListener { } - void Init(enum http_parser_type type) { + void Init(parser_type_t type) { +#ifdef NODE_EXPERIMENTAL_HTTP + llhttp_init(&parser_, type, &settings); +#else /* !NODE_EXPERIMENTAL_HTTP */ http_parser_init(&parser_, type); +#endif /* NODE_EXPERIMENTAL_HTTP */ url_.Reset(); status_message_.Reset(); num_fields_ = 0; @@ -695,7 +787,35 @@ class Parser : public AsyncWrap, public StreamListener { } - http_parser parser_; + int TrackHeader(size_t len) { +#ifdef NODE_EXPERIMENTAL_HTTP + header_nread_ += len; + if (header_nread_ >= kMaxHeaderSize) { + llhttp_set_error_reason(&parser_, "Headers overflow"); + return HPE_USER; + } +#endif /* NODE_EXPERIMENTAL_HTTP */ + return 0; + } + + + int MaybePause() { +#ifdef NODE_EXPERIMENTAL_HTTP + CHECK_NE(execute_depth_, 0); + + if (!pending_pause_) { + return 0; + } + + pending_pause_ = false; + llhttp_set_error_reason(&parser_, "Paused in callback"); + return HPE_PAUSED; +#else /* !NODE_EXPERIMENTAL_HTTP */ + return 0; +#endif /* NODE_EXPERIMENTAL_HTTP */ + } + + parser_t parser_; StringPtr fields_[32]; // header fields StringPtr values_[32]; // header values StringPtr url_; @@ -707,25 +827,37 @@ class Parser : public AsyncWrap, public StreamListener { Local current_buffer_; size_t current_buffer_len_; char* current_buffer_data_; +#ifdef NODE_EXPERIMENTAL_HTTP + unsigned int execute_depth_ = 0; + bool pending_pause_ = false; + uint64_t header_nread_ = 0; +#endif /* NODE_EXPERIMENTAL_HTTP */ // These are helper functions for filling `http_parser_settings`, which turn // a member function of Parser into a C-style HTTP parser callback. template struct Proxy; template struct Proxy { - static int Raw(http_parser* p, Args ... args) { + static int Raw(parser_t* p, Args ... args) { Parser* parser = ContainerOf(&Parser::parser_, p); - return (parser->*Member)(std::forward(args)...); + int rv = (parser->*Member)(std::forward(args)...); + if (rv == 0) { + rv = parser->MaybePause(); + } + return rv; } }; typedef int (Parser::*Call)(); typedef int (Parser::*DataCall)(const char* at, size_t length); - static const struct http_parser_settings settings; + static const parser_settings_t settings; +#ifdef NODE_EXPERIMENTAL_HTTP + static const uint64_t kMaxHeaderSize = 80 * 1024; +#endif /* NODE_EXPERIMENTAL_HTTP */ }; -const struct http_parser_settings Parser::settings = { +const parser_settings_t Parser::settings = { Proxy::Raw, Proxy::Raw, Proxy::Raw, @@ -734,8 +866,13 @@ const struct http_parser_settings Parser::settings = { Proxy::Raw, Proxy::Raw, Proxy::Raw, - nullptr, // on_chunk_header - nullptr // on_chunk_complete +#ifdef NODE_EXPERIMENTAL_HTTP + Proxy::Raw, + Proxy::Raw, +#else /* !NODE_EXPERIMENTAL_HTTP */ + nullptr, + nullptr, +#endif /* NODE_EXPERIMENTAL_HTTP */ }; diff --git a/test/parallel/test-http-parser-bad-ref.js b/test/parallel/test-http-parser-bad-ref.js index aca94361b493aa..5b002b2ce0e926 100644 --- a/test/parallel/test-http-parser-bad-ref.js +++ b/test/parallel/test-http-parser-bad-ref.js @@ -25,7 +25,7 @@ function flushPool() { function demoBug(part1, part2) { flushPool(); - const parser = new HTTPParser(0); + const parser = new HTTPParser(HTTPParser.REQUEST); parser.headers = []; parser.url = ''; diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index e8527fe574a53a..ba7b9e70b2a9b8 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -2,7 +2,7 @@ const common = require('../common'); const assert = require('assert'); -const expected_keys = ['ares', 'http_parser', 'modules', 'node', +const expected_keys = ['ares', 'modules', 'node', 'uv', 'v8', 'zlib', 'nghttp2', 'napi']; if (common.hasCrypto) { @@ -16,6 +16,9 @@ if (common.hasIntl) { expected_keys.push('unicode'); } +expected_keys.push( + process.versions.llhttp === undefined ? 'http_parser' : 'llhttp'); + expected_keys.sort(); const actual_keys = Object.keys(process.versions).sort(); @@ -24,7 +27,8 @@ assert.deepStrictEqual(actual_keys, expected_keys); const commonTemplate = /^\d+\.\d+\.\d+(?:-.*)?$/; assert(commonTemplate.test(process.versions.ares)); -assert(commonTemplate.test(process.versions.http_parser)); +assert(commonTemplate.test(process.versions.llhttp === undefined ? + process.versions.http_parser : process.versions.llhttp)); assert(commonTemplate.test(process.versions.node)); assert(commonTemplate.test(process.versions.uv)); assert(commonTemplate.test(process.versions.zlib)); diff --git a/test/parallel/test-trace-events-metadata.js b/test/parallel/test-trace-events-metadata.js index 951f398404ac66..0db8555838cd42 100644 --- a/test/parallel/test-trace-events-metadata.js +++ b/test/parallel/test-trace-events-metadata.js @@ -36,8 +36,9 @@ proc.once('exit', common.mustCall(() => { assert(traces.some((trace) => trace.name === 'node' && - trace.args.process.versions.http_parser === - process.versions.http_parser && + (trace.args.process.versions.http_parser === + process.versions.http_parser || + trace.args.process.versions.llhttp === process.versions.llhttp) && trace.args.process.versions.node === process.versions.node && trace.args.process.versions.v8 === diff --git a/test/sequential/test-async-wrap-getasyncid.js b/test/sequential/test-async-wrap-getasyncid.js index 851a0b3fbc2118..4ebe3e0472f4ee 100644 --- a/test/sequential/test-async-wrap-getasyncid.js +++ b/test/sequential/test-async-wrap-getasyncid.js @@ -149,7 +149,7 @@ if (common.hasCrypto) { // eslint-disable-line node-core/crypto-check { const { HTTPParser } = internalBinding('http_parser'); - testInitialized(new HTTPParser(0), 'HTTPParser'); + testInitialized(new HTTPParser(HTTPParser.REQUEST), 'HTTPParser'); } diff --git a/tools/license-builder.sh b/tools/license-builder.sh index 82addcd0b40731..58a3b5a209b8c7 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -58,6 +58,7 @@ else fi addlicense "libuv" "deps/uv" "$(cat ${rootdir}/deps/uv/LICENSE)" +addlicense "llhttp" "deps/llhttp" "$(cat deps/llhttp/LICENSE-MIT)" addlicense "OpenSSL" "deps/openssl" \ "$(sed -e '/^ \*\/$/,$d' -e '/^ [^*].*$/d' -e '/\/\*.*$/d' -e '/^$/d' -e 's/^[/ ]\* *//' ${rootdir}/deps/openssl/openssl/LICENSE)" addlicense "Punycode.js" "lib/punycode.js" \ From 883519679e082489704c55516449731b2ef8860a Mon Sep 17 00:00:00 2001 From: saurabhSiddhu Date: Sun, 4 Nov 2018 18:10:56 +0530 Subject: [PATCH 172/249] test: replacing fixture directory with temp PR-URL: https://github.com/nodejs/node/pull/24077 Reviewed-By: Rich Trott Reviewed-By: James M Snell --- test/parallel/test-fs-error-messages.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-fs-error-messages.js b/test/parallel/test-fs-error-messages.js index b0480059edd37f..96ff606cccec4e 100644 --- a/test/parallel/test-fs-error-messages.js +++ b/test/parallel/test-fs-error-messages.js @@ -26,15 +26,22 @@ const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const assert = require('assert'); const fs = require('fs'); +const path = require('path'); tmpdir.refresh(); -const nonexistentFile = fixtures.path('non-existent'); -const nonexistentDir = fixtures.path('non-existent', 'foo', 'bar'); -const existingFile = fixtures.path('exit.js'); -const existingFile2 = fixtures.path('a.js'); -const existingDir = tmpdir.path; + +const nonexistentFile = path.join(tmpdir.path, 'non-existent'); +const nonexistentDir = path.join(tmpdir.path, 'non-existent', 'foo', 'bar'); +const existingFile = path.join(tmpdir.path, 'existingFile.js'); +const existingFile2 = path.join(tmpdir.path, 'existingFile2.js'); +const existingDir = path.join(tmpdir.path, 'dir'); const existingDir2 = fixtures.path('keys'); +fs.mkdirSync(existingDir); +fs.writeFileSync(existingFile, 'test', 'utf-8'); +fs.writeFileSync(existingFile2, 'test', 'utf-8'); + + const { COPYFILE_EXCL } = fs.constants; const { internalBinding } = require('internal/test/binding'); const { From beb0800ab3bd857d67ba34addfc4ae03b5a7cfee Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 8 Nov 2018 16:33:42 -0800 Subject: [PATCH 173/249] test: move benchmark tests out of main test suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move benchmark tests (which are slow) out of the main test suite. We can hopefully add them to node-daily-master so that they are still run daily on CI. PR-URL: https://github.com/nodejs/node/pull/24265 Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Michaël Zasso Reviewed-By: Joyee Cheung Reviewed-By: Refael Ackermann Reviewed-By: James M Snell --- Makefile | 11 +++++--- test/README.md | 1 + test/benchmark/benchmark.status | 21 ++++++++++++++ .../test-benchmark-assert.js | 0 .../test-benchmark-async-hooks.js | 0 .../test-benchmark-buffer.js | 0 .../test-benchmark-child-process.js | 0 .../test-benchmark-cluster.js | 0 .../test-benchmark-crypto.js | 0 .../test-benchmark-dgram.js | 0 .../test-benchmark-dns.js | 0 .../test-benchmark-domain.js | 0 .../test-benchmark-es.js | 0 .../test-benchmark-events.js | 0 .../test-benchmark-fs.js | 0 .../test-benchmark-http.js | 0 .../test-benchmark-http2.js | 0 .../test-benchmark-misc.js | 0 .../test-benchmark-module.js | 0 .../test-benchmark-napi.js | 0 .../test-benchmark-net.js | 0 .../test-benchmark-os.js | 0 .../test-benchmark-path.js | 0 .../test-benchmark-process.js | 0 .../test-benchmark-querystring.js | 0 .../test-benchmark-streams.js | 0 .../test-benchmark-string_decoder.js | 0 .../test-benchmark-timers.js | 0 .../test-benchmark-tls.js | 0 .../test-benchmark-url.js | 0 .../test-benchmark-util.js | 0 .../test-benchmark-v8.js | 0 .../test-benchmark-vm.js | 0 .../test-benchmark-worker.js | 0 .../test-benchmark-zlib.js | 0 test/benchmark/testcfg.py | 6 ++++ test/root.status | 28 ------------------- tools/test.py | 1 + vcbuild.bat | 3 +- 39 files changed, 38 insertions(+), 33 deletions(-) create mode 100644 test/benchmark/benchmark.status rename test/{parallel => benchmark}/test-benchmark-assert.js (100%) rename test/{sequential => benchmark}/test-benchmark-async-hooks.js (100%) rename test/{sequential => benchmark}/test-benchmark-buffer.js (100%) rename test/{sequential => benchmark}/test-benchmark-child-process.js (100%) rename test/{parallel => benchmark}/test-benchmark-cluster.js (100%) rename test/{parallel => benchmark}/test-benchmark-crypto.js (100%) rename test/{sequential => benchmark}/test-benchmark-dgram.js (100%) rename test/{parallel => benchmark}/test-benchmark-dns.js (100%) rename test/{parallel => benchmark}/test-benchmark-domain.js (100%) rename test/{parallel => benchmark}/test-benchmark-es.js (100%) rename test/{parallel => benchmark}/test-benchmark-events.js (100%) rename test/{parallel => benchmark}/test-benchmark-fs.js (100%) rename test/{sequential => benchmark}/test-benchmark-http.js (100%) rename test/{sequential => benchmark}/test-benchmark-http2.js (100%) rename test/{parallel => benchmark}/test-benchmark-misc.js (100%) rename test/{parallel => benchmark}/test-benchmark-module.js (100%) rename test/{sequential => benchmark}/test-benchmark-napi.js (100%) rename test/{sequential => benchmark}/test-benchmark-net.js (100%) rename test/{parallel => benchmark}/test-benchmark-os.js (100%) rename test/{sequential => benchmark}/test-benchmark-path.js (100%) rename test/{parallel => benchmark}/test-benchmark-process.js (100%) rename test/{parallel => benchmark}/test-benchmark-querystring.js (100%) rename test/{parallel => benchmark}/test-benchmark-streams.js (100%) rename test/{parallel => benchmark}/test-benchmark-string_decoder.js (100%) rename test/{parallel => benchmark}/test-benchmark-timers.js (100%) rename test/{sequential => benchmark}/test-benchmark-tls.js (100%) rename test/{parallel => benchmark}/test-benchmark-url.js (100%) rename test/{parallel => benchmark}/test-benchmark-util.js (100%) rename test/{parallel => benchmark}/test-benchmark-v8.js (100%) rename test/{parallel => benchmark}/test-benchmark-vm.js (100%) rename test/{sequential => benchmark}/test-benchmark-worker.js (100%) rename test/{parallel => benchmark}/test-benchmark-zlib.js (100%) create mode 100644 test/benchmark/testcfg.py diff --git a/Makefile b/Makefile index e003341f70cf51..6a426384f2d4b7 100644 --- a/Makefile +++ b/Makefile @@ -270,7 +270,7 @@ v8: tools/make-v8.sh $(V8_ARCH).$(BUILDTYPE_LOWER) $(V8_BUILD_OPTIONS) .PHONY: jstest -jstest: build-addons build-addons-napi bench-addons-build ## Runs addon tests and JS tests +jstest: build-addons build-addons-napi ## Runs addon tests and JS tests $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) \ --skip-tests=$(CI_SKIP_TESTS) \ $(CI_JS_SUITES) \ @@ -414,7 +414,7 @@ clear-stalled: echo $${PS_OUT} | xargs kill -9; \ fi -test-build: | all build-addons build-addons-napi bench-addons-build +test-build: | all build-addons build-addons-napi test-build-addons-napi: all build-addons-napi @@ -455,7 +455,7 @@ test-ci-js: | clear-stalled .PHONY: test-ci # Related CI jobs: most CI tests, excluding node-test-commit-arm-fanned test-ci: LOGLEVEL := info -test-ci: | clear-stalled build-addons build-addons-napi doc-only bench-addons-build +test-ci: | clear-stalled build-addons build-addons-napi doc-only out/Release/cctest --gtest_output=tap:cctest.tap $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \ @@ -499,7 +499,7 @@ test-message: test-build test-wpt: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) wpt -test-simple: | cctest bench-addons-build # Depends on 'all'. +test-simple: | cctest # Depends on 'all'. $(PYTHON) tools/test.py $(PARALLEL_ARGS) parallel sequential test-pummel: all @@ -512,6 +512,9 @@ test-node-inspect: $(NODE_EXE) USE_EMBEDDED_NODE_INSPECT=1 $(NODE) tools/test-npm-package \ --install deps/node-inspect test +test-benchmark: | bench-addons-build + $(PYTHON) tools/test.py $(PARALLEL_ARGS) benchmark + test-tick-processor: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) tick-processor diff --git a/test/README.md b/test/README.md index 7ef705230983f3..25243d7687d133 100644 --- a/test/README.md +++ b/test/README.md @@ -19,6 +19,7 @@ GitHub with the `autocrlf` git config flag set to true. | `addons` | Yes | Tests for [addon](https://nodejs.org/api/addons.html) functionality along with some tests that require an addon to function properly. | | `addons-napi` | Yes | Tests for [n-api](https://nodejs.org/api/n-api.html) functionality. | | `async-hooks` | Yes | Tests for [async_hooks](https://nodejs.org/api/async_hooks.html) functionality. | +| `benchmark` | No | Test minimal functionality of benchmarks. | | `cctest` | Yes | C++ tests that are run as part of the build process. | | `code-cache` | No | Tests for a Node.js binary compiled with V8 code cache. | | `common` | | Common modules shared among many tests. [Documentation](./common/README.md) | diff --git a/test/benchmark/benchmark.status b/test/benchmark/benchmark.status new file mode 100644 index 00000000000000..6a966743aab26b --- /dev/null +++ b/test/benchmark/benchmark.status @@ -0,0 +1,21 @@ +prefix benchmark + +# To mark a test as flaky, list the test name in the appropriate section +# below, without ".js", followed by ": PASS,FLAKY". Example: +# sample-test : PASS,FLAKY + +[true] # This section applies to all platforms + +[$system==win32] + +[$system==linux] + +[$system==macos] + +[$system==solaris] # Also applies to SmartOS + +[$system==freebsd] + +[$system==aix] + +[$arch==arm] diff --git a/test/parallel/test-benchmark-assert.js b/test/benchmark/test-benchmark-assert.js similarity index 100% rename from test/parallel/test-benchmark-assert.js rename to test/benchmark/test-benchmark-assert.js diff --git a/test/sequential/test-benchmark-async-hooks.js b/test/benchmark/test-benchmark-async-hooks.js similarity index 100% rename from test/sequential/test-benchmark-async-hooks.js rename to test/benchmark/test-benchmark-async-hooks.js diff --git a/test/sequential/test-benchmark-buffer.js b/test/benchmark/test-benchmark-buffer.js similarity index 100% rename from test/sequential/test-benchmark-buffer.js rename to test/benchmark/test-benchmark-buffer.js diff --git a/test/sequential/test-benchmark-child-process.js b/test/benchmark/test-benchmark-child-process.js similarity index 100% rename from test/sequential/test-benchmark-child-process.js rename to test/benchmark/test-benchmark-child-process.js diff --git a/test/parallel/test-benchmark-cluster.js b/test/benchmark/test-benchmark-cluster.js similarity index 100% rename from test/parallel/test-benchmark-cluster.js rename to test/benchmark/test-benchmark-cluster.js diff --git a/test/parallel/test-benchmark-crypto.js b/test/benchmark/test-benchmark-crypto.js similarity index 100% rename from test/parallel/test-benchmark-crypto.js rename to test/benchmark/test-benchmark-crypto.js diff --git a/test/sequential/test-benchmark-dgram.js b/test/benchmark/test-benchmark-dgram.js similarity index 100% rename from test/sequential/test-benchmark-dgram.js rename to test/benchmark/test-benchmark-dgram.js diff --git a/test/parallel/test-benchmark-dns.js b/test/benchmark/test-benchmark-dns.js similarity index 100% rename from test/parallel/test-benchmark-dns.js rename to test/benchmark/test-benchmark-dns.js diff --git a/test/parallel/test-benchmark-domain.js b/test/benchmark/test-benchmark-domain.js similarity index 100% rename from test/parallel/test-benchmark-domain.js rename to test/benchmark/test-benchmark-domain.js diff --git a/test/parallel/test-benchmark-es.js b/test/benchmark/test-benchmark-es.js similarity index 100% rename from test/parallel/test-benchmark-es.js rename to test/benchmark/test-benchmark-es.js diff --git a/test/parallel/test-benchmark-events.js b/test/benchmark/test-benchmark-events.js similarity index 100% rename from test/parallel/test-benchmark-events.js rename to test/benchmark/test-benchmark-events.js diff --git a/test/parallel/test-benchmark-fs.js b/test/benchmark/test-benchmark-fs.js similarity index 100% rename from test/parallel/test-benchmark-fs.js rename to test/benchmark/test-benchmark-fs.js diff --git a/test/sequential/test-benchmark-http.js b/test/benchmark/test-benchmark-http.js similarity index 100% rename from test/sequential/test-benchmark-http.js rename to test/benchmark/test-benchmark-http.js diff --git a/test/sequential/test-benchmark-http2.js b/test/benchmark/test-benchmark-http2.js similarity index 100% rename from test/sequential/test-benchmark-http2.js rename to test/benchmark/test-benchmark-http2.js diff --git a/test/parallel/test-benchmark-misc.js b/test/benchmark/test-benchmark-misc.js similarity index 100% rename from test/parallel/test-benchmark-misc.js rename to test/benchmark/test-benchmark-misc.js diff --git a/test/parallel/test-benchmark-module.js b/test/benchmark/test-benchmark-module.js similarity index 100% rename from test/parallel/test-benchmark-module.js rename to test/benchmark/test-benchmark-module.js diff --git a/test/sequential/test-benchmark-napi.js b/test/benchmark/test-benchmark-napi.js similarity index 100% rename from test/sequential/test-benchmark-napi.js rename to test/benchmark/test-benchmark-napi.js diff --git a/test/sequential/test-benchmark-net.js b/test/benchmark/test-benchmark-net.js similarity index 100% rename from test/sequential/test-benchmark-net.js rename to test/benchmark/test-benchmark-net.js diff --git a/test/parallel/test-benchmark-os.js b/test/benchmark/test-benchmark-os.js similarity index 100% rename from test/parallel/test-benchmark-os.js rename to test/benchmark/test-benchmark-os.js diff --git a/test/sequential/test-benchmark-path.js b/test/benchmark/test-benchmark-path.js similarity index 100% rename from test/sequential/test-benchmark-path.js rename to test/benchmark/test-benchmark-path.js diff --git a/test/parallel/test-benchmark-process.js b/test/benchmark/test-benchmark-process.js similarity index 100% rename from test/parallel/test-benchmark-process.js rename to test/benchmark/test-benchmark-process.js diff --git a/test/parallel/test-benchmark-querystring.js b/test/benchmark/test-benchmark-querystring.js similarity index 100% rename from test/parallel/test-benchmark-querystring.js rename to test/benchmark/test-benchmark-querystring.js diff --git a/test/parallel/test-benchmark-streams.js b/test/benchmark/test-benchmark-streams.js similarity index 100% rename from test/parallel/test-benchmark-streams.js rename to test/benchmark/test-benchmark-streams.js diff --git a/test/parallel/test-benchmark-string_decoder.js b/test/benchmark/test-benchmark-string_decoder.js similarity index 100% rename from test/parallel/test-benchmark-string_decoder.js rename to test/benchmark/test-benchmark-string_decoder.js diff --git a/test/parallel/test-benchmark-timers.js b/test/benchmark/test-benchmark-timers.js similarity index 100% rename from test/parallel/test-benchmark-timers.js rename to test/benchmark/test-benchmark-timers.js diff --git a/test/sequential/test-benchmark-tls.js b/test/benchmark/test-benchmark-tls.js similarity index 100% rename from test/sequential/test-benchmark-tls.js rename to test/benchmark/test-benchmark-tls.js diff --git a/test/parallel/test-benchmark-url.js b/test/benchmark/test-benchmark-url.js similarity index 100% rename from test/parallel/test-benchmark-url.js rename to test/benchmark/test-benchmark-url.js diff --git a/test/parallel/test-benchmark-util.js b/test/benchmark/test-benchmark-util.js similarity index 100% rename from test/parallel/test-benchmark-util.js rename to test/benchmark/test-benchmark-util.js diff --git a/test/parallel/test-benchmark-v8.js b/test/benchmark/test-benchmark-v8.js similarity index 100% rename from test/parallel/test-benchmark-v8.js rename to test/benchmark/test-benchmark-v8.js diff --git a/test/parallel/test-benchmark-vm.js b/test/benchmark/test-benchmark-vm.js similarity index 100% rename from test/parallel/test-benchmark-vm.js rename to test/benchmark/test-benchmark-vm.js diff --git a/test/sequential/test-benchmark-worker.js b/test/benchmark/test-benchmark-worker.js similarity index 100% rename from test/sequential/test-benchmark-worker.js rename to test/benchmark/test-benchmark-worker.js diff --git a/test/parallel/test-benchmark-zlib.js b/test/benchmark/test-benchmark-zlib.js similarity index 100% rename from test/parallel/test-benchmark-zlib.js rename to test/benchmark/test-benchmark-zlib.js diff --git a/test/benchmark/testcfg.py b/test/benchmark/testcfg.py new file mode 100644 index 00000000000000..2c2929f610b851 --- /dev/null +++ b/test/benchmark/testcfg.py @@ -0,0 +1,6 @@ +import sys, os +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +import testpy + +def GetConfiguration(context, root): + return testpy.SimpleTestConfiguration(context, root, 'benchmark') diff --git a/test/root.status b/test/root.status index 9ed9004c2169d0..9c40512cb68051 100644 --- a/test/root.status +++ b/test/root.status @@ -9,27 +9,6 @@ async-hooks/test-tlswrap: SLOW async-hooks/test-tlswrap: SLOW message/eval_messages: SLOW message/stdin_messages: SLOW -parallel/test-benchmark-assert: SLOW -parallel/test-benchmark-cluster: SLOW -parallel/test-benchmark-crypto: SLOW -parallel/test-benchmark-dns: SLOW -parallel/test-benchmark-domain: SLOW -parallel/test-benchmark-es: SLOW -parallel/test-benchmark-events: SLOW -parallel/test-benchmark-fs: SLOW -parallel/test-benchmark-misc: SLOW -parallel/test-benchmark-module: SLOW -parallel/test-benchmark-os: SLOW -parallel/test-benchmark-process: SLOW -parallel/test-benchmark-querystring: SLOW -parallel/test-benchmark-streams: SLOW -parallel/test-benchmark-string_decoder: SLOW -parallel/test-benchmark-timers: SLOW -parallel/test-benchmark-url: SLOW -parallel/test-benchmark-util: SLOW -parallel/test-benchmark-v8: SLOW -parallel/test-benchmark-vm: SLOW -parallel/test-benchmark-zlib: SLOW parallel/test-buffer-constructor-node-modules-paths: SLOW parallel/test-buffer-indexof: SLOW parallel/test-child-process-spawnsync-input: SLOW @@ -165,13 +144,6 @@ parallel/test-worker-unsupported-things: SLOW parallel/test-worker-workerdata-sharedarraybuffer: SLOW parallel/test-zlib-bytes-read: SLOW parallel/test-zlib-convenience-methods: SLOW -sequential/test-benchmark-buffer: SLOW -sequential/test-benchmark-child-process: SLOW -sequential/test-benchmark-dgram: SLOW -sequential/test-benchmark-http: SLOW -sequential/test-benchmark-net: SLOW -sequential/test-benchmark-path: SLOW -sequential/test-benchmark-tls: SLOW sequential/test-child-process-execsync: SLOW sequential/test-child-process-exit: SLOW sequential/test-child-process-pass-fd: SLOW diff --git a/tools/test.py b/tools/test.py index cd361196653043..3a464be61da1b3 100755 --- a/tools/test.py +++ b/tools/test.py @@ -1498,6 +1498,7 @@ def PrintCrashed(code): IGNORED_SUITES = [ 'addons', 'addons-napi', + 'benchmark', 'doctool', 'internet', 'pummel', diff --git a/vcbuild.bat b/vcbuild.bat index 1e31440cc29857..a22c756200bf17 100644 --- a/vcbuild.bat +++ b/vcbuild.bat @@ -83,6 +83,7 @@ if /i "%1"=="build-addons" set build_addons=1&goto arg-ok if /i "%1"=="build-addons-napi" set build_addons_napi=1&goto arg-ok if /i "%1"=="test-addons" set test_args=%test_args% addons&set build_addons=1&goto arg-ok if /i "%1"=="test-addons-napi" set test_args=%test_args% addons-napi&set build_addons_napi=1&goto arg-ok +if /i "%1"=="test-benchmark" set test_args=%test_args% benchmark&goto arg-ok if /i "%1"=="test-simple" set test_args=%test_args% sequential parallel -J&goto arg-ok if /i "%1"=="test-message" set test_args=%test_args% message&goto arg-ok if /i "%1"=="test-tick-processor" set test_args=%test_args% tick-processor&goto arg-ok @@ -634,7 +635,7 @@ del .used_configure_flags goto exit :help -echo vcbuild.bat [debug/release] [msi] [doc] [test/test-ci/test-all/test-addons/test-addons-napi/test-internet/test-pummel/test-simple/test-message/test-tick-processor/test-known-issues/test-node-inspect/test-check-deopts/test-npm/test-async-hooks/test-v8/test-v8-intl/test-v8-benchmarks/test-v8-all] [ignore-flaky] [static/dll] [noprojgen] [projgen] [small-icu/full-icu/without-intl] [nobuild] [nosnapshot] [noetw] [ltcg] [nopch] [licensetf] [sign] [ia32/x86/x64] [vs2017] [download-all] [enable-vtune] [lint/lint-ci/lint-js/lint-js-ci/lint-md] [lint-md-build] [package] [build-release] [upload] [no-NODE-OPTIONS] [link-module path-to-module] [debug-http2] [debug-nghttp2] [clean] [no-cctest] [openssl-no-asm] +echo vcbuild.bat [debug/release] [msi] [doc] [test/test-ci/test-all/test-addons/test-addons-napi/test-benchmark/test-internet/test-pummel/test-simple/test-message/test-tick-processor/test-known-issues/test-node-inspect/test-check-deopts/test-npm/test-async-hooks/test-v8/test-v8-intl/test-v8-benchmarks/test-v8-all] [ignore-flaky] [static/dll] [noprojgen] [projgen] [small-icu/full-icu/without-intl] [nobuild] [nosnapshot] [noetw] [ltcg] [nopch] [licensetf] [sign] [ia32/x86/x64] [vs2017] [download-all] [enable-vtune] [lint/lint-ci/lint-js/lint-js-ci/lint-md] [lint-md-build] [package] [build-release] [upload] [no-NODE-OPTIONS] [link-module path-to-module] [debug-http2] [debug-nghttp2] [clean] [no-cctest] [openssl-no-asm] echo Examples: echo vcbuild.bat : builds release build echo vcbuild.bat debug : builds debug build From 70699ee09b645128d70080ed02aba14647519e68 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Thu, 8 Nov 2018 13:27:39 -0500 Subject: [PATCH 174/249] build: lint commit message in separate Travis job Move the first commit message linting to a separate Travis job. Run the script in bash debug mode to capture any issues communicating with the GitHub API (e.g. network issues, rate limits). PR-URL: https://github.com/nodejs/node/pull/24254 Reviewed-By: Rich Trott Reviewed-By: Refael Ackermann Reviewed-By: Matheus Marchini --- .travis.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 80c729a772fed5..e496919579b2f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,14 @@ cache: ccache os: linux matrix: include: + - name: "First commit message adheres to guidelines at https://goo.gl/p2fr5Q" + if: type = pull_request + language: node_js + node_js: "node" + script: + - if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then + bash -x tools/lint-pr-commit-message.sh ${TRAVIS_PULL_REQUEST}; + fi - name: "Linter" language: node_js node_js: "node" @@ -11,10 +19,6 @@ matrix: - NODE=$(which node) script: - make lint - # Lint the first commit in the PR. - - if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then - bash tools/lint-pr-commit-message.sh ${TRAVIS_PULL_REQUEST} || true; - fi - name: "Test Suite" addons: apt: From e1c792919e174ff369d4c82457a1a58ea7c550f7 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 8 Nov 2018 07:22:13 +0100 Subject: [PATCH 175/249] src: fix v8 compiler warnings in src This commit changes the code to use the maybe version. PR-URL: https://github.com/nodejs/node/pull/24246 Reviewed-By: Anna Henningsen Reviewed-By: Refael Ackermann --- src/cares_wrap.cc | 49 ++++++++++++++++++------------ src/env.cc | 4 ++- src/exceptions.cc | 24 +++++++++------ src/fs_event_wrap.cc | 4 ++- src/js_stream.cc | 6 ++-- src/module_wrap.cc | 4 +-- src/node.cc | 65 +++++++++++++++++++++++++++------------- src/node_constants.cc | 36 ++++++++++++++++------ src/node_contextify.cc | 16 ++++++---- src/node_crypto.cc | 63 ++++++++++++++++++++++++-------------- src/node_dtrace.cc | 18 +++++++---- src/node_errors.cc | 17 +++++++---- src/node_file.cc | 19 ++++++++---- src/node_http2.cc | 6 ++-- src/node_http_parser.cc | 44 +++++++++++++++++---------- src/node_os.cc | 51 ++++++++++++++++++++----------- src/node_process.cc | 11 +++++-- src/node_stat_watcher.cc | 4 +-- src/node_trace_events.cc | 6 ++-- src/node_util.cc | 10 ++++--- src/node_v8.cc | 34 +++++++++++++-------- src/node_worker.cc | 4 ++- src/node_zlib.cc | 9 ++++-- src/pipe_wrap.cc | 8 +++-- src/process_wrap.cc | 5 ++-- src/signal_wrap.cc | 5 ++-- src/stream_base-inl.h | 14 ++++++--- src/stream_base.cc | 14 +++++---- src/stream_wrap.cc | 9 ++++-- src/tcp_wrap.cc | 36 ++++++++++++++++------ src/tls_wrap.cc | 4 ++- src/tty_wrap.cc | 8 +++-- src/udp_wrap.cc | 11 ++++--- src/uv.cc | 9 +++--- 34 files changed, 414 insertions(+), 213 deletions(-) diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index d9f6485edfb507..8cc2339872b553 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -1848,7 +1848,7 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) { continue; Local s = OneByteString(env->isolate(), ip); - results->Set(n, s); + results->Set(env->context(), n, s).FromJust(); n++; } }; @@ -2049,10 +2049,12 @@ void GetServers(const FunctionCallbackInfo& args) { CHECK_EQ(err, 0); Local ret = Array::New(env->isolate(), 2); - ret->Set(0, OneByteString(env->isolate(), ip)); - ret->Set(1, Integer::New(env->isolate(), cur->udp_port)); + ret->Set(env->context(), 0, OneByteString(env->isolate(), ip)).FromJust(); + ret->Set(env->context(), + 1, + Integer::New(env->isolate(), cur->udp_port)).FromJust(); - server_array->Set(i, ret); + server_array->Set(env->context(), i, ret).FromJust(); } ares_free_data(servers); @@ -2175,16 +2177,19 @@ void Initialize(Local target, env->SetMethod(target, "strerror", StrError); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), - Integer::New(env->isolate(), AF_INET)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"), - Integer::New(env->isolate(), AF_INET6)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AF_UNSPEC"), - Integer::New(env->isolate(), AF_UNSPEC)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_ADDRCONFIG"), - Integer::New(env->isolate(), AI_ADDRCONFIG)); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"), - Integer::New(env->isolate(), AI_V4MAPPED)); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET"), + Integer::New(env->isolate(), AF_INET)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), "AF_INET6"), + Integer::New(env->isolate(), AF_INET6)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), + "AF_UNSPEC"), + Integer::New(env->isolate(), AF_UNSPEC)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), + "AI_ADDRCONFIG"), + Integer::New(env->isolate(), AI_ADDRCONFIG)).FromJust(); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(env->isolate(), + "AI_V4MAPPED"), + Integer::New(env->isolate(), AI_V4MAPPED)).FromJust(); Local aiw = BaseObject::MakeLazilyInitializedJSTemplate(env); @@ -2192,7 +2197,9 @@ void Initialize(Local target, Local addrInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"); aiw->SetClassName(addrInfoWrapString); - target->Set(addrInfoWrapString, aiw->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + addrInfoWrapString, + aiw->GetFunction(context).ToLocalChecked()).FromJust(); Local niw = BaseObject::MakeLazilyInitializedJSTemplate(env); @@ -2200,7 +2207,9 @@ void Initialize(Local target, Local nameInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"); niw->SetClassName(nameInfoWrapString); - target->Set(nameInfoWrapString, niw->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + nameInfoWrapString, + niw->GetFunction(context).ToLocalChecked()).FromJust(); Local qrw = BaseObject::MakeLazilyInitializedJSTemplate(env); @@ -2208,7 +2217,9 @@ void Initialize(Local target, Local queryWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"); qrw->SetClassName(queryWrapString); - target->Set(queryWrapString, qrw->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + queryWrapString, + qrw->GetFunction(context).ToLocalChecked()).FromJust(); Local channel_wrap = env->NewFunctionTemplate(ChannelWrap::New); @@ -2235,8 +2246,8 @@ void Initialize(Local target, Local channelWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "ChannelWrap"); channel_wrap->SetClassName(channelWrapString); - target->Set(channelWrapString, - channel_wrap->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), channelWrapString, + channel_wrap->GetFunction(context).ToLocalChecked()).FromJust(); } } // anonymous namespace diff --git a/src/env.cc b/src/env.cc index 9d8fd967a406a6..727d13b98b13a1 100644 --- a/src/env.cc +++ b/src/env.cc @@ -746,7 +746,9 @@ void CollectExceptionInfo(Environment* env, const char* message, const char* path, const char* dest) { - obj->Set(env->errno_string(), v8::Integer::New(env->isolate(), errorno)); + obj->Set(env->context(), + env->errno_string(), + v8::Integer::New(env->isolate(), errorno)).FromJust(); obj->Set(env->context(), env->code_string(), OneByteString(env->isolate(), err_string)).FromJust(); diff --git a/src/exceptions.cc b/src/exceptions.cc index 98c87603dd9be3..7bbee45467ff35 100644 --- a/src/exceptions.cc +++ b/src/exceptions.cc @@ -51,15 +51,19 @@ Local ErrnoException(Isolate* isolate, e = Exception::Error(cons); Local obj = e.As(); - obj->Set(env->errno_string(), Integer::New(isolate, errorno)); - obj->Set(env->code_string(), estring); + obj->Set(env->context(), + env->errno_string(), + Integer::New(isolate, errorno)).FromJust(); + obj->Set(env->context(), env->code_string(), estring).FromJust(); if (path_string.IsEmpty() == false) { - obj->Set(env->path_string(), path_string); + obj->Set(env->context(), env->path_string(), path_string).FromJust(); } if (syscall != nullptr) { - obj->Set(env->syscall_string(), OneByteString(isolate, syscall)); + obj->Set(env->context(), + env->syscall_string(), + OneByteString(isolate, syscall)).FromJust(); } return e; @@ -132,13 +136,15 @@ Local UVException(Isolate* isolate, Exception::Error(js_msg)->ToObject(isolate->GetCurrentContext()) .ToLocalChecked(); - e->Set(env->errno_string(), Integer::New(isolate, errorno)); - e->Set(env->code_string(), js_code); - e->Set(env->syscall_string(), js_syscall); + e->Set(env->context(), + env->errno_string(), + Integer::New(isolate, errorno)).FromJust(); + e->Set(env->context(), env->code_string(), js_code).FromJust(); + e->Set(env->context(), env->syscall_string(), js_syscall).FromJust(); if (!js_path.IsEmpty()) - e->Set(env->path_string(), js_path); + e->Set(env->context(), env->path_string(), js_path).FromJust(); if (!js_dest.IsEmpty()) - e->Set(env->dest_string(), js_dest); + e->Set(env->context(), env->dest_string(), js_dest).FromJust(); return e; } diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index 739794665b2cfe..057445776a5255 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -119,7 +119,9 @@ void FSEventWrap::Initialize(Local target, Local(), static_cast(ReadOnly | DontDelete | v8::DontEnum)); - target->Set(fsevent_string, t->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + fsevent_string, + t->GetFunction(context).ToLocalChecked()).FromJust(); } diff --git a/src/js_stream.cc b/src/js_stream.cc index 99ea7d870b8afb..2d07b11b636ef9 100644 --- a/src/js_stream.cc +++ b/src/js_stream.cc @@ -118,7 +118,7 @@ int JSStream::DoWrite(WriteWrap* w, Local buf; for (size_t i = 0; i < count; i++) { buf = Buffer::Copy(env(), bufs[i].base, bufs[i].len).ToLocalChecked(); - bufs_arr->Set(i, buf); + bufs_arr->Set(env()->context(), i, buf).FromJust(); } Local argv[] = { @@ -210,7 +210,9 @@ void JSStream::Initialize(Local target, env->SetProtoMethod(t, "emitEOF", EmitEOF); StreamBase::AddMethods(env, t); - target->Set(jsStreamString, t->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + jsStreamString, + t->GetFunction(context).ToLocalChecked()).FromJust(); } } // namespace node diff --git a/src/module_wrap.cc b/src/module_wrap.cc index ebe84fd1ec569d..5443b2e07dc856 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -837,8 +837,8 @@ void ModuleWrap::Initialize(Local target, env->SetProtoMethodNoSideEffect(tpl, "getStaticDependencySpecifiers", GetStaticDependencySpecifiers); - target->Set(FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"), - tpl->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), FIXED_ONE_BYTE_STRING(isolate, "ModuleWrap"), + tpl->GetFunction(context).ToLocalChecked()).FromJust(); env->SetMethod(target, "resolve", Resolve); env->SetMethod(target, "setImportModuleDynamicallyCallback", diff --git a/src/node.cc b/src/node.cc index 9ed73b60511bbb..f1bfc89a3cd211 100644 --- a/src/node.cc +++ b/src/node.cc @@ -686,7 +686,8 @@ MaybeLocal MakeCallback(Isolate* isolate, int argc, Local argv[], async_context asyncContext) { - Local callback_v = recv->Get(symbol); + Local callback_v = recv->Get(isolate->GetCurrentContext(), + symbol).ToLocalChecked(); if (callback_v.IsEmpty()) return Local(); if (!callback_v->IsFunction()) return Local(); Local callback = callback_v.As(); @@ -1260,7 +1261,7 @@ static void GetLinkedBinding(const FunctionCallbackInfo& args) { Local exports = Object::New(env->isolate()); Local exports_prop = String::NewFromUtf8(env->isolate(), "exports", NewStringType::kNormal).ToLocalChecked(); - module->Set(exports_prop, exports); + module->Set(env->context(), exports_prop, exports).FromJust(); if (mod->nm_context_register_func != nullptr) { mod->nm_context_register_func(exports, @@ -1273,7 +1274,8 @@ static void GetLinkedBinding(const FunctionCallbackInfo& args) { return env->ThrowError("Linked module has no declared entry point."); } - auto effective_exports = module->Get(exports_prop); + auto effective_exports = module->Get(env->context(), + exports_prop).ToLocalChecked(); args.GetReturnValue().Set(effective_exports); } @@ -1288,10 +1290,16 @@ static Local GetFeatures(Environment* env) { Local debug = False(env->isolate()); #endif // defined(DEBUG) && DEBUG - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "debug"), debug); - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "uv"), True(env->isolate())); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "debug"), + debug).FromJust(); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "uv"), + True(env->isolate())).FromJust(); // TODO(bnoordhuis) ping libuv - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ipv6"), True(env->isolate())); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "ipv6"), + True(env->isolate())).FromJust(); #ifdef HAVE_OPENSSL Local have_openssl = True(env->isolate()); @@ -1299,10 +1307,18 @@ static Local GetFeatures(Environment* env) { Local have_openssl = False(env->isolate()); #endif - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_alpn"), have_openssl); - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_sni"), have_openssl); - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls_ocsp"), have_openssl); - obj->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "tls"), have_openssl); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "tls_alpn"), + have_openssl).FromJust(); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "tls_sni"), + have_openssl).FromJust(); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "tls_ocsp"), + have_openssl).FromJust(); + obj->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "tls"), + have_openssl).FromJust(); return scope.Escape(obj); } @@ -1464,7 +1480,9 @@ void SetupProcessObject(Environment* env, NewStringType::kNormal).ToLocalChecked()) .FromJust(); } - process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "argv"), arguments); + process->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "argv"), + arguments).FromJust(); // process.execArgv Local exec_arguments = Array::New(env->isolate(), exec_args.size()); @@ -1474,8 +1492,9 @@ void SetupProcessObject(Environment* env, NewStringType::kNormal).ToLocalChecked()) .FromJust(); } - process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"), - exec_arguments); + process->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "execArgv"), + exec_arguments).FromJust(); // create process.env Local process_env_template = @@ -1490,7 +1509,9 @@ void SetupProcessObject(Environment* env, Local process_env = process_env_template->NewInstance(env->context()).ToLocalChecked(); - process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "env"), process_env); + process->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "env"), + process_env).FromJust(); READONLY_PROPERTY(process, "pid", Integer::New(env->isolate(), uv_os_getpid())); @@ -1535,7 +1556,7 @@ void SetupProcessObject(Environment* env, preload_modules[i].c_str(), NewStringType::kNormal) .ToLocalChecked(); - array->Set(i, module); + array->Set(env->context(), i, module).FromJust(); } READONLY_PROPERTY(process, "_preload_modules", @@ -1625,8 +1646,9 @@ void SetupProcessObject(Environment* env, exec_path_value = String::NewFromUtf8(env->isolate(), args[0].c_str(), NewStringType::kInternalized).ToLocalChecked(); } - process->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"), - exec_path_value); + process->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "execPath"), + exec_path_value).FromJust(); delete[] exec_path; auto debug_port_string = FIXED_ONE_BYTE_STRING(env->isolate(), "debugPort"); @@ -1779,7 +1801,9 @@ void LoadEnvironment(Environment* env) { // Expose the global object as a property on itself // (Allows you to set stuff on `global` from anywhere in JavaScript.) - global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global); + global->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "global"), + global).FromJust(); // Create binding loaders Local get_binding_fn = @@ -2340,8 +2364,9 @@ int EmitExit(Environment* env) { HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); Local process_object = env->process_object(); - process_object->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"), - True(env->isolate())); + process_object->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "_exiting"), + True(env->isolate())).FromJust(); Local exit_code = env->exit_code_string(); int code = process_object->Get(env->context(), exit_code).ToLocalChecked() diff --git a/src/node_constants.cc b/src/node_constants.cc index 753b8f8fe16602..3b028b52aa75cc 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -1347,15 +1347,33 @@ void DefineConstants(v8::Isolate* isolate, Local target) { // Define libuv constants. NODE_DEFINE_CONSTANT(os_constants, UV_UDP_REUSEADDR); - os_constants->Set(OneByteString(isolate, "dlopen"), dlopen_constants); - os_constants->Set(OneByteString(isolate, "errno"), err_constants); - os_constants->Set(OneByteString(isolate, "signals"), sig_constants); - os_constants->Set(OneByteString(isolate, "priority"), priority_constants); - target->Set(OneByteString(isolate, "os"), os_constants); - target->Set(OneByteString(isolate, "fs"), fs_constants); - target->Set(OneByteString(isolate, "crypto"), crypto_constants); - target->Set(OneByteString(isolate, "zlib"), zlib_constants); - target->Set(OneByteString(isolate, "trace"), trace_constants); + os_constants->Set(env->context(), + OneByteString(isolate, "dlopen"), + dlopen_constants).FromJust(); + os_constants->Set(env->context(), + OneByteString(isolate, "errno"), + err_constants).FromJust(); + os_constants->Set(env->context(), + OneByteString(isolate, "signals"), + sig_constants).FromJust(); + os_constants->Set(env->context(), + OneByteString(isolate, "priority"), + priority_constants).FromJust(); + target->Set(env->context(), + OneByteString(isolate, "os"), + os_constants).FromJust(); + target->Set(env->context(), + OneByteString(isolate, "fs"), + fs_constants).FromJust(); + target->Set(env->context(), + OneByteString(isolate, "crypto"), + crypto_constants).FromJust(); + target->Set(env->context(), + OneByteString(isolate, "zlib"), + zlib_constants).FromJust(); + target->Set(env->context(), + OneByteString(isolate, "trace"), + trace_constants).FromJust(); } } // namespace node diff --git a/src/node_contextify.cc b/src/node_contextify.cc index e878507731ef1c..37afead80896d0 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -392,7 +392,7 @@ void ContextifyContext::PropertySetterCallback( args.GetReturnValue().Set(false); } - ctx->sandbox()->Set(property, value); + ctx->sandbox()->Set(ctx->context(), property, value).FromJust(); } // static @@ -606,8 +606,8 @@ void ContextifyScript::Init(Environment* env, Local target) { env->SetProtoMethod(script_tmpl, "runInContext", RunInContext); env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext); - target->Set(class_name, - script_tmpl->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), class_name, + script_tmpl->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_script_context_constructor_template(script_tmpl); } @@ -728,8 +728,9 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { if (compile_options == ScriptCompiler::kConsumeCodeCache) { args.This()->Set( + env->context(), env->cached_data_rejected_string(), - Boolean::New(isolate, source.GetCachedData()->rejected)); + Boolean::New(isolate, source.GetCachedData()->rejected)).FromJust(); } else if (produce_cached_data) { const ScriptCompiler::CachedData* cached_data = ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()); @@ -739,11 +740,14 @@ void ContextifyScript::New(const FunctionCallbackInfo& args) { env, reinterpret_cast(cached_data->data), cached_data->length); - args.This()->Set(env->cached_data_string(), buf.ToLocalChecked()); + args.This()->Set(env->context(), + env->cached_data_string(), + buf.ToLocalChecked()).FromJust(); } args.This()->Set( + env->context(), env->cached_data_produced_string(), - Boolean::New(isolate, cached_data_produced)); + Boolean::New(isolate, cached_data_produced)).FromJust(); } TRACE_EVENT_NESTABLE_ASYNC_END0( TRACING_CATEGORY_NODE2(vm, script), diff --git a/src/node_crypto.cc b/src/node_crypto.cc index fa5335344c9f85..baa0fbe635cd8b 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -379,8 +379,8 @@ void SecureContext::Initialize(Environment* env, Local target) { Local(), static_cast(ReadOnly | DontDelete)); - target->Set(secureContextString, - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), secureContextString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_secure_context_constructor_template(t); } @@ -1267,18 +1267,24 @@ int SecureContext::TicketKeyCallback(SSL* ssl, Local arr = ret.As(); int r = - arr->Get(kTicketKeyReturnIndex)->Int32Value(env->context()).FromJust(); + arr->Get(env->context(), + kTicketKeyReturnIndex).ToLocalChecked() + ->Int32Value(env->context()).FromJust(); if (r < 0) return r; - Local hmac = arr->Get(kTicketKeyHMACIndex); - Local aes = arr->Get(kTicketKeyAESIndex); + Local hmac = arr->Get(env->context(), + kTicketKeyHMACIndex).ToLocalChecked(); + Local aes = arr->Get(env->context(), + kTicketKeyAESIndex).ToLocalChecked(); if (Buffer::Length(aes) != kTicketPartSize) return -1; if (enc) { - Local name_val = arr->Get(kTicketKeyNameIndex); - Local iv_val = arr->Get(kTicketKeyIVIndex); + Local name_val = arr->Get(env->context(), + kTicketKeyNameIndex).ToLocalChecked(); + Local iv_val = arr->Get(env->context(), + kTicketKeyIVIndex).ToLocalChecked(); if (Buffer::Length(name_val) != kTicketPartSize || Buffer::Length(iv_val) != kTicketPartSize) { @@ -1658,7 +1664,7 @@ static Local X509ToObject(Environment* env, X509* cert) { unsigned char* pubserialized = reinterpret_cast(Buffer::Data(pubbuff)); i2d_RSA_PUBKEY(rsa.get(), &pubserialized); - info->Set(env->pubkey_string(), pubbuff); + info->Set(env->context(), env->pubkey_string(), pubbuff).FromJust(); } pkey.reset(); @@ -2413,7 +2419,8 @@ void SSLWrap::CertCbDone(const FunctionCallbackInfo& args) { CHECK(w->is_waiting_cert_cb() && w->cert_cb_running_); Local object = w->object(); - Local ctx = object->Get(env->sni_context_string()); + Local ctx = object->Get(env->context(), + env->sni_context_string()).ToLocalChecked(); Local cons = env->secure_context_constructor_template(); // Not an object, probably undefined or null @@ -2577,8 +2584,9 @@ void CipherBase::Initialize(Environment* env, Local target) { env->SetProtoMethod(t, "setAuthTag", SetAuthTag); env->SetProtoMethod(t, "setAAD", SetAAD); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "CipherBase"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "CipherBase"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -3182,8 +3190,9 @@ void Hmac::Initialize(Environment* env, v8::Local target) { env->SetProtoMethod(t, "update", HmacUpdate); env->SetProtoMethod(t, "digest", HmacDigest); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Hmac"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "Hmac"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -3302,8 +3311,9 @@ void Hash::Initialize(Environment* env, v8::Local target) { env->SetProtoMethod(t, "update", HashUpdate); env->SetProtoMethod(t, "digest", HashDigest); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Hash"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "Hash"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -3497,8 +3507,9 @@ void Sign::Initialize(Environment* env, v8::Local target) { env->SetProtoMethod(t, "update", SignUpdate); env->SetProtoMethod(t, "sign", SignFinal); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Sign"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "Sign"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -3728,8 +3739,9 @@ void Verify::Initialize(Environment* env, v8::Local target) { env->SetProtoMethod(t, "update", VerifyUpdate); env->SetProtoMethod(t, "verify", VerifyFinal); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "Verify"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "Verify"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -3965,7 +3977,9 @@ void DiffieHellman::Initialize(Environment* env, Local target) { Local(), attributes); - target->Set(name, t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + name, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); }; make(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellman"), New); @@ -4292,8 +4306,9 @@ void ECDH::Initialize(Environment* env, Local target) { env->SetProtoMethod(t, "setPublicKey", SetPublicKey); env->SetProtoMethod(t, "setPrivateKey", SetPrivateKey); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -5300,7 +5315,9 @@ static void array_push_back(const TypeName* md, const char* to, void* arg) { CipherPushContext* ctx = static_cast(arg); - ctx->arr->Set(ctx->arr->Length(), OneByteString(ctx->env()->isolate(), from)); + ctx->arr->Set(ctx->env()->context(), + ctx->arr->Length(), + OneByteString(ctx->env()->isolate(), from)).FromJust(); } diff --git a/src/node_dtrace.cc b/src/node_dtrace.cc index 164a602fb62a09..cd3986cef56a97 100644 --- a/src/node_dtrace.cc +++ b/src/node_dtrace.cc @@ -65,7 +65,8 @@ using v8::Value; "expected object for " #obj " to contain string member " #member); \ } \ node::Utf8Value _##member(env->isolate(), \ - obj->Get(OneByteString(env->isolate(), #member))); \ + obj->Get(env->context(), \ + OneByteString(env->isolate(), #member)).ToLocalChecked()); \ if ((*(const char **)valp = *_##member) == nullptr) \ *(const char **)valp = ""; @@ -75,7 +76,8 @@ using v8::Value; env, \ "expected object for " #obj " to contain integer member " #member); \ } \ - *valp = obj->Get(OneByteString(env->isolate(), #member)) \ + *valp = obj->Get(env->context(), \ + OneByteString(env->isolate(), #member)).ToLocalChecked() \ ->Int32Value(env->context()) \ .FromJust(); @@ -84,7 +86,8 @@ using v8::Value; return node::THROW_ERR_INVALID_ARG_TYPE(env, \ "expected object for " #obj " to contain object member " #member); \ } \ - *valp = Local::Cast(obj->Get(OneByteString(env->isolate(), #member))); + *valp = Local::Cast(obj->Get(env->context(), \ + OneByteString(env->isolate(), #member)).ToLocalChecked()); #define SLURP_CONNECTION(arg, conn) \ if (!(arg)->IsObject()) { \ @@ -94,7 +97,9 @@ using v8::Value; node_dtrace_connection_t conn; \ Local _##conn = Local::Cast(arg); \ Local _handle = \ - (_##conn)->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "_handle")); \ + (_##conn)->Get(env->context(), \ + FIXED_ONE_BYTE_STRING(env->isolate(), "_handle")) \ + .ToLocalChecked(); \ if (_handle->IsObject()) { \ SLURP_INT(_handle.As(), fd, &conn.fd); \ } else { \ @@ -173,7 +178,8 @@ void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo& args) { "expected object for request to contain string member headers"); } - Local strfwdfor = headers->Get(env->x_forwarded_string()); + Local strfwdfor = headers->Get( + env->context(), env->x_forwarded_string()).ToLocalChecked(); node::Utf8Value fwdfor(env->isolate(), strfwdfor); if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == nullptr) @@ -279,7 +285,7 @@ void InitDTrace(Environment* env, Local target) { Local val = env->NewFunctionTemplate(tab[i].func) ->GetFunction(env->context()) .ToLocalChecked(); - target->Set(key, val); + target->Set(env->context(), key, val).FromJust(); } #ifdef HAVE_ETW diff --git a/src/node_errors.cc b/src/node_errors.cc index cc8cff0f0ed2b8..d78608bf7bf24c 100644 --- a/src/node_errors.cc +++ b/src/node_errors.cc @@ -198,7 +198,8 @@ void ReportException(Environment* env, } else { Local err_obj = er->ToObject(env->context()).ToLocalChecked(); - trace_value = err_obj->Get(env->stack_string()); + trace_value = err_obj->Get(env->context(), + env->stack_string()).ToLocalChecked(); arrow = err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol()) .ToLocalChecked(); @@ -223,8 +224,10 @@ void ReportException(Environment* env, if (er->IsObject()) { Local err_obj = er.As(); - message = err_obj->Get(env->message_string()); - name = err_obj->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "name")); + message = err_obj->Get(env->context(), + env->message_string()).ToLocalChecked(); + name = err_obj->Get(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "name")).ToLocalChecked(); } if (message.IsEmpty() || message->IsUndefined() || name.IsEmpty() || @@ -269,7 +272,8 @@ void DecorateErrorStack(Environment* env, const TryCatch& try_catch) { if (IsExceptionDecorated(env, err_obj)) return; AppendExceptionLine(env, exception, try_catch.Message(), CONTEXTIFY_ERROR); - Local stack = err_obj->Get(env->stack_string()); + Local stack = err_obj->Get(env->context(), + env->stack_string()).ToLocalChecked(); MaybeLocal maybe_value = err_obj->GetPrivate(env->context(), env->arrow_message_private_symbol()); @@ -288,7 +292,7 @@ void DecorateErrorStack(Environment* env, const TryCatch& try_catch) { arrow.As(), FIXED_ONE_BYTE_STRING(env->isolate(), "\n")), stack.As()); - err_obj->Set(env->stack_string(), decorated_stack); + err_obj->Set(env->context(), env->stack_string(), decorated_stack).FromJust(); err_obj->SetPrivate( env->context(), env->decorated_private_symbol(), True(env->isolate())); } @@ -361,7 +365,8 @@ void FatalException(Isolate* isolate, Local process_object = env->process_object(); Local fatal_exception_string = env->fatal_exception_string(); Local fatal_exception_function = - process_object->Get(fatal_exception_string); + process_object->Get(env->context(), + fatal_exception_string).ToLocalChecked(); if (!fatal_exception_function->IsFunction()) { // Failed before the process._fatalException function was added! diff --git a/src/node_file.cc b/src/node_file.cc index 683aeee3440b55..cf3b944a5504bb 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -640,8 +640,14 @@ void AfterScanDirWithTypes(uv_fs_t* req) { } Local result = Array::New(isolate, 2); - result->Set(0, Array::New(isolate, name_v.data(), name_v.size())); - result->Set(1, Array::New(isolate, type_v.data(), type_v.size())); + result->Set(env->context(), + 0, + Array::New(isolate, name_v.data(), + name_v.size())).FromJust(); + result->Set(env->context(), + 1, + Array::New(isolate, type_v.data(), + type_v.size())).FromJust(); req_wrap->Resolve(result); } @@ -1482,8 +1488,11 @@ static void ReadDir(const FunctionCallbackInfo& args) { Local names = Array::New(isolate, name_v.data(), name_v.size()); if (with_types) { Local result = Array::New(isolate, 2); - result->Set(0, names); - result->Set(1, Array::New(isolate, type_v.data(), type_v.size())); + result->Set(env->context(), 0, names).FromJust(); + result->Set(env->context(), + 1, + Array::New(isolate, type_v.data(), + type_v.size())).FromJust(); args.GetReturnValue().Set(result); } else { args.GetReturnValue().Set(names); @@ -1667,7 +1676,7 @@ static void WriteBuffers(const FunctionCallbackInfo& args) { MaybeStackBuffer iovs(chunks->Length()); for (uint32_t i = 0; i < iovs.length(); i++) { - Local chunk = chunks->Get(i); + Local chunk = chunks->Get(env->context(), i).ToLocalChecked(); CHECK(Buffer::HasInstance(chunk)); iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk)); } diff --git a/src/node_http2.cc b/src/node_http2.cc index 95f3f4a8f7c1d2..8ae58d5134e15d 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -3057,8 +3057,10 @@ void Initialize(Local target, #define V(name) \ NODE_DEFINE_CONSTANT(constants, name); \ - name_for_error_code->Set(static_cast(name), \ - FIXED_ONE_BYTE_STRING(isolate, #name)); + name_for_error_code->Set(env->context(), \ + static_cast(name), \ + FIXED_ONE_BYTE_STRING(isolate, \ + #name)).FromJust(); NODE_NGHTTP2_ERROR_CODES(V) #undef V diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 482c7263ca719c..c9e057711d9253 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -265,7 +265,8 @@ class Parser : public AsyncWrap, public StreamListener { Local argv[A_MAX]; Local obj = object(); - Local cb = obj->Get(kOnHeadersComplete); + Local cb = obj->Get(env()->context(), + kOnHeadersComplete).ToLocalChecked(); if (!cb->IsFunction()) return 0; @@ -338,7 +339,7 @@ class Parser : public AsyncWrap, public StreamListener { EscapableHandleScope scope(env()->isolate()); Local obj = object(); - Local cb = obj->Get(kOnBody); + Local cb = obj->Get(env()->context(), kOnBody).ToLocalChecked(); if (!cb->IsFunction()) return 0; @@ -381,7 +382,8 @@ class Parser : public AsyncWrap, public StreamListener { Flush(); // Flush trailing HTTP headers. Local obj = object(); - Local cb = obj->Get(kOnMessageComplete); + Local cb = obj->Get(env()->context(), + kOnMessageComplete).ToLocalChecked(); if (!cb->IsFunction()) return 0; @@ -705,17 +707,23 @@ class Parser : public AsyncWrap, public StreamListener { Local e = Exception::Error(env()->parse_error_string()); Local obj = e->ToObject(env()->isolate()->GetCurrentContext()) .ToLocalChecked(); - obj->Set(env()->bytes_parsed_string(), nread_obj); + obj->Set(env()->context(), + env()->bytes_parsed_string(), + nread_obj).FromJust(); #ifdef NODE_EXPERIMENTAL_HTTP - obj->Set(env()->code_string(), - OneByteString(env()->isolate(), llhttp_errno_name(err))); - obj->Set(env()->reason_string(), - OneByteString(env()->isolate(), parser_.reason)); + obj->Set(env()->context(), + env()->code_string(), + OneByteString(env()->isolate(), + llhttp_errno_name(err))).FromJust(); + obj->Set(env()->context(), + env()->reason_string(), + OneByteString(env()->isolate(), parser_.reason)).FromJust(); #else /* !NODE_EXPERIMENTAL_HTTP */ - obj->Set(env()->code_string(), - OneByteString(env()->isolate(), http_errno_name(err))); + obj->Set(env()->context(), + env()->code_string(), + OneByteString(env()->isolate(), + http_errno_name(err))).FromJust(); #endif /* NODE_EXPERIMENTAL_HTTP */ - return scope.Escape(e); } @@ -750,7 +758,7 @@ class Parser : public AsyncWrap, public StreamListener { HandleScope scope(env()->isolate()); Local obj = object(); - Local cb = obj->Get(kOnHeaders); + Local cb = obj->Get(env()->context(), kOnHeaders).ToLocalChecked(); if (!cb->IsFunction()) return; @@ -902,10 +910,13 @@ void Initialize(Local target, Local methods = Array::New(env->isolate()); #define V(num, name, string) \ - methods->Set(num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)); + methods->Set(env->context(), \ + num, FIXED_ONE_BYTE_STRING(env->isolate(), #string)).FromJust(); HTTP_METHOD_MAP(V) #undef V - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), methods); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), + methods).FromJust(); t->Inherit(AsyncWrap::GetConstructorTemplate(env)); env->SetProtoMethod(t, "close", Parser::Close); @@ -919,8 +930,9 @@ void Initialize(Local target, env->SetProtoMethod(t, "unconsume", Parser::Unconsume); env->SetProtoMethod(t, "getCurrentBuffer", Parser::GetCurrentBuffer); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"), - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "HTTPParser"), + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } } // anonymous namespace diff --git a/src/node_os.cc b/src/node_os.cc index 723cf18b3efd27..5a2a7a4db05996 100644 --- a/src/node_os.cc +++ b/src/node_os.cc @@ -267,10 +267,11 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { v8::NewStringType::kNormal).ToLocalChecked(); if (ret->Has(env->context(), name).FromJust()) { - ifarr = Local::Cast(ret->Get(name)); + ifarr = Local::Cast(ret->Get(env->context(), + name).ToLocalChecked()); } else { ifarr = Array::New(env->isolate()); - ret->Set(name, ifarr); + ret->Set(env->context(), name, ifarr).FromJust(); } snprintf(mac, @@ -297,22 +298,29 @@ static void GetInterfaceAddresses(const FunctionCallbackInfo& args) { } o = Object::New(env->isolate()); - o->Set(env->address_string(), OneByteString(env->isolate(), ip)); - o->Set(env->netmask_string(), OneByteString(env->isolate(), netmask)); - o->Set(env->family_string(), family); - o->Set(env->mac_string(), FIXED_ONE_BYTE_STRING(env->isolate(), mac)); + o->Set(env->context(), + env->address_string(), + OneByteString(env->isolate(), ip)).FromJust(); + o->Set(env->context(), + env->netmask_string(), + OneByteString(env->isolate(), netmask)).FromJust(); + o->Set(env->context(), + env->family_string(), family).FromJust(); + o->Set(env->context(), + env->mac_string(), + FIXED_ONE_BYTE_STRING(env->isolate(), mac)).FromJust(); if (interfaces[i].address.address4.sin_family == AF_INET6) { uint32_t scopeid = interfaces[i].address.address6.sin6_scope_id; - o->Set(env->scopeid_string(), - Integer::NewFromUnsigned(env->isolate(), scopeid)); + o->Set(env->context(), env->scopeid_string(), + Integer::NewFromUnsigned(env->isolate(), scopeid)).FromJust(); } const bool internal = interfaces[i].is_internal; - o->Set(env->internal_string(), - internal ? True(env->isolate()) : False(env->isolate())); + o->Set(env->context(), env->internal_string(), + internal ? True(env->isolate()) : False(env->isolate())).FromJust(); - ifarr->Set(ifarr->Length(), o); + ifarr->Set(env->context(), ifarr->Length(), o).FromJust(); } uv_free_interface_addresses(interfaces, count); @@ -397,11 +405,17 @@ static void GetUserInfo(const FunctionCallbackInfo& args) { Local entry = Object::New(env->isolate()); - entry->Set(env->uid_string(), uid); - entry->Set(env->gid_string(), gid); - entry->Set(env->username_string(), username.ToLocalChecked()); - entry->Set(env->homedir_string(), homedir.ToLocalChecked()); - entry->Set(env->shell_string(), shell.ToLocalChecked()); + entry->Set(env->context(), env->uid_string(), uid).FromJust(); + entry->Set(env->context(), env->gid_string(), gid).FromJust(); + entry->Set(env->context(), + env->username_string(), + username.ToLocalChecked()).FromJust(); + entry->Set(env->context(), + env->homedir_string(), + homedir.ToLocalChecked()).FromJust(); + entry->Set(env->context(), + env->shell_string(), + shell.ToLocalChecked()).FromJust(); args.GetReturnValue().Set(entry); } @@ -464,8 +478,9 @@ void Initialize(Local target, env->SetMethod(target, "getUserInfo", GetUserInfo); env->SetMethod(target, "setPriority", SetPriority); env->SetMethod(target, "getPriority", GetPriority); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"), - Boolean::New(env->isolate(), IsBigEndian())); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"), + Boolean::New(env->isolate(), IsBigEndian())).FromJust(); } } // namespace os diff --git a/src/node_process.cc b/src/node_process.cc index 600f85b8044671..6c12dcc02b2cd0 100644 --- a/src/node_process.cc +++ b/src/node_process.cc @@ -488,7 +488,8 @@ void GetGroups(const FunctionCallbackInfo& args) { gid_t egid = getegid(); for (int i = 0; i < ngroups; i++) { - groups_list->Set(i, Integer::New(env->isolate(), groups[i])); + groups_list->Set(env->context(), + i, Integer::New(env->isolate(), groups[i])).FromJust(); if (groups[i] == egid) seen_egid = true; } @@ -496,7 +497,9 @@ void GetGroups(const FunctionCallbackInfo& args) { delete[] groups; if (seen_egid == false) - groups_list->Set(ngroups, Integer::New(env->isolate(), egid)); + groups_list->Set(env->context(), + ngroups, + Integer::New(env->isolate(), egid)).FromJust(); args.GetReturnValue().Set(groups_list); } @@ -513,7 +516,9 @@ void SetGroups(const FunctionCallbackInfo& args) { gid_t* groups = new gid_t[size]; for (size_t i = 0; i < size; i++) { - gid_t gid = gid_by_name(env->isolate(), groups_list->Get(i)); + gid_t gid = gid_by_name(env->isolate(), + groups_list->Get(env->context(), + i).ToLocalChecked()); if (gid == gid_not_found) { delete[] groups; diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index ca0927af662200..2ad5ea2ffafd79 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -54,8 +54,8 @@ void StatWatcher::Initialize(Environment* env, Local target) { env->SetProtoMethod(t, "start", StatWatcher::Start); - target->Set(statWatcherString, - t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), statWatcherString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc index 6530bdb04c44e8..f51db62ba38ac4 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc @@ -112,8 +112,10 @@ void Initialize(Local target, env->SetProtoMethod(category_set, "enable", NodeCategorySet::Enable); env->SetProtoMethod(category_set, "disable", NodeCategorySet::Disable); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "CategorySet"), - category_set->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "CategorySet"), + category_set->GetFunction(env->context()).ToLocalChecked()) + .FromJust(); Local isTraceCategoryEnabled = FIXED_ONE_BYTE_STRING(env->isolate(), "isTraceCategoryEnabled"); diff --git a/src/node_util.cc b/src/node_util.cc index ac39be407dd47f..62af7a1115784e 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -57,6 +57,7 @@ static void GetOwnNonIndexProperties( } static void GetPromiseDetails(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); // Return undefined if it's not a Promise. if (!args[0]->IsPromise()) return; @@ -67,14 +68,15 @@ static void GetPromiseDetails(const FunctionCallbackInfo& args) { Local ret = Array::New(isolate, 2); int state = promise->State(); - ret->Set(0, Integer::New(isolate, state)); + ret->Set(env->context(), 0, Integer::New(isolate, state)).FromJust(); if (state != Promise::PromiseState::kPending) - ret->Set(1, promise->Result()); + ret->Set(env->context(), 1, promise->Result()).FromJust(); args.GetReturnValue().Set(ret); } static void GetProxyDetails(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); // Return undefined if it's not a proxy. if (!args[0]->IsProxy()) return; @@ -82,8 +84,8 @@ static void GetProxyDetails(const FunctionCallbackInfo& args) { Local proxy = args[0].As(); Local ret = Array::New(args.GetIsolate(), 2); - ret->Set(0, proxy->GetTarget()); - ret->Set(1, proxy->GetHandler()); + ret->Set(env->context(), 0, proxy->GetTarget()).FromJust(); + ret->Set(env->context(), 1, proxy->GetHandler()).FromJust(); args.GetReturnValue().Set(ret); } diff --git a/src/node_v8.cc b/src/node_v8.cc index 2a661d95497a85..ab453134fabfc0 100644 --- a/src/node_v8.cc +++ b/src/node_v8.cc @@ -134,23 +134,27 @@ void Initialize(Local target, const size_t heap_statistics_buffer_byte_length = sizeof(*env->heap_statistics_buffer()) * kHeapStatisticsPropertiesCount; - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "heapStatisticsArrayBuffer"), ArrayBuffer::New(env->isolate(), env->heap_statistics_buffer(), - heap_statistics_buffer_byte_length)); + heap_statistics_buffer_byte_length)).FromJust(); #define V(i, _, name) \ - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), #name), \ - Uint32::NewFromUnsigned(env->isolate(), i)); + target->Set(env->context(), \ + FIXED_ONE_BYTE_STRING(env->isolate(), #name), \ + Uint32::NewFromUnsigned(env->isolate(), i)).FromJust(); HEAP_STATISTICS_PROPERTIES(V) #undef V - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "kHeapSpaceStatisticsPropertiesCount"), Uint32::NewFromUnsigned(env->isolate(), - kHeapSpaceStatisticsPropertiesCount)); + kHeapSpaceStatisticsPropertiesCount)) + .FromJust(); size_t number_of_heap_spaces = env->isolate()->NumberOfHeapSpaces(); @@ -165,10 +169,11 @@ void Initialize(Local target, s.space_name(), NewStringType::kNormal) .ToLocalChecked(); - heap_spaces->Set(i, heap_space_name); + heap_spaces->Set(env->context(), i, heap_space_name).FromJust(); } - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kHeapSpaces"), - heap_spaces); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "kHeapSpaces"), + heap_spaces).FromJust(); env->SetMethod(target, "updateHeapSpaceStatisticsArrayBuffer", @@ -182,15 +187,18 @@ void Initialize(Local target, kHeapSpaceStatisticsPropertiesCount * number_of_heap_spaces; - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "heapSpaceStatisticsArrayBuffer"), ArrayBuffer::New(env->isolate(), env->heap_space_statistics_buffer(), - heap_space_statistics_buffer_byte_length)); + heap_space_statistics_buffer_byte_length)) + .FromJust(); #define V(i, _, name) \ - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), #name), \ - Uint32::NewFromUnsigned(env->isolate(), i)); + target->Set(env->context(), \ + FIXED_ONE_BYTE_STRING(env->isolate(), #name), \ + Uint32::NewFromUnsigned(env->isolate(), i)).FromJust(); HEAP_SPACE_STATISTICS_PROPERTIES(V) #undef V diff --git a/src/node_worker.cc b/src/node_worker.cc index debec3078c55d9..38a92b34794dd2 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -492,7 +492,9 @@ void InitWorker(Local target, Local workerString = FIXED_ONE_BYTE_STRING(env->isolate(), "Worker"); w->SetClassName(workerString); - target->Set(workerString, w->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + workerString, + w->GetFunction(env->context()).ToLocalChecked()).FromJust(); } env->SetMethod(target, "getEnvMessagePort", GetEnvMessagePort); diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 8b257cf0d47934..6b050fcb40289a 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -896,10 +896,13 @@ void Initialize(Local target, Local zlibString = FIXED_ONE_BYTE_STRING(env->isolate(), "Zlib"); z->SetClassName(zlibString); - target->Set(zlibString, z->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + zlibString, + z->GetFunction(env->context()).ToLocalChecked()).FromJust(); - target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"), - FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)); + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(env->isolate(), "ZLIB_VERSION"), + FIXED_ONE_BYTE_STRING(env->isolate(), ZLIB_VERSION)).FromJust(); } } // anonymous namespace diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 66b9677cc92fec..50e80b45a42f5e 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -90,7 +90,9 @@ void PipeWrap::Initialize(Local target, env->SetProtoMethod(t, "fchmod", Fchmod); - target->Set(pipeString, t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + pipeString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_pipe_constructor_template(t); // Create FunctionTemplate for PipeConnectWrap. @@ -99,7 +101,9 @@ void PipeWrap::Initialize(Local target, Local wrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"); cwt->SetClassName(wrapString); - target->Set(wrapString, cwt->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + wrapString, + cwt->GetFunction(env->context()).ToLocalChecked()).FromJust(); // Define constants Local constants = Object::New(env->isolate()); diff --git a/src/process_wrap.cc b/src/process_wrap.cc index edf79177d32502..79d661c83fc023 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -62,8 +62,9 @@ class ProcessWrap : public HandleWrap { env->SetProtoMethod(constructor, "spawn", Spawn); env->SetProtoMethod(constructor, "kill", Kill); - target->Set(processString, - constructor->GetFunction(context).ToLocalChecked()); + target->Set(env->context(), + processString, + constructor->GetFunction(context).ToLocalChecked()).FromJust(); } SET_NO_MEMORY_INFO() diff --git a/src/signal_wrap.cc b/src/signal_wrap.cc index afdf140d8b07c3..613ee0926f5db1 100644 --- a/src/signal_wrap.cc +++ b/src/signal_wrap.cc @@ -55,8 +55,9 @@ class SignalWrap : public HandleWrap { env->SetProtoMethod(constructor, "start", Start); env->SetProtoMethod(constructor, "stop", Stop); - target->Set(signalString, - constructor->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), signalString, + constructor->GetFunction(env->context()).ToLocalChecked()) + .FromJust(); } SET_NO_MEMORY_INFO() diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h index 0209281f942e1c..1d6ec17b802f3b 100644 --- a/src/stream_base-inl.h +++ b/src/stream_base-inl.h @@ -179,7 +179,9 @@ inline int StreamBase::Shutdown(v8::Local req_wrap_obj) { const char* msg = Error(); if (msg != nullptr) { - req_wrap_obj->Set(env->error_string(), OneByteString(env->isolate(), msg)); + req_wrap_obj->Set( + env->context(), + env->error_string(), OneByteString(env->isolate(), msg)).FromJust(); ClearError(); } @@ -228,7 +230,9 @@ inline StreamWriteResult StreamBase::Write( const char* msg = Error(); if (msg != nullptr) { - req_wrap_obj->Set(env->error_string(), OneByteString(env->isolate(), msg)); + req_wrap_obj->Set(env->context(), + env->error_string(), + OneByteString(env->isolate(), msg)).FromJust(); ClearError(); } @@ -434,8 +438,10 @@ inline void StreamReq::Done(int status, const char* error_str) { AsyncWrap* async_wrap = GetAsyncWrap(); Environment* env = async_wrap->env(); if (error_str != nullptr) { - async_wrap->object()->Set(env->error_string(), - OneByteString(env->isolate(), error_str)); + async_wrap->object()->Set(env->context(), + env->error_string(), + OneByteString(env->isolate(), error_str)) + .FromJust(); } OnDone(status); diff --git a/src/stream_base.cc b/src/stream_base.cc index 670b3cbd5091d1..26efa46ba02f83 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -83,7 +83,7 @@ int StreamBase::Writev(const FunctionCallbackInfo& args) { if (!all_buffers) { // Determine storage size first for (size_t i = 0; i < count; i++) { - Local chunk = chunks->Get(i * 2); + Local chunk = chunks->Get(env->context(), i * 2).ToLocalChecked(); if (Buffer::HasInstance(chunk)) continue; @@ -92,7 +92,7 @@ int StreamBase::Writev(const FunctionCallbackInfo& args) { // String chunk Local string = chunk->ToString(env->context()).ToLocalChecked(); enum encoding encoding = ParseEncoding(env->isolate(), - chunks->Get(i * 2 + 1)); + chunks->Get(env->context(), i * 2 + 1).ToLocalChecked()); size_t chunk_size; if (encoding == UTF8 && string->Length() > 65535 && !StringBytes::Size(env->isolate(), string, encoding).To(&chunk_size)) @@ -107,7 +107,7 @@ int StreamBase::Writev(const FunctionCallbackInfo& args) { return UV_ENOBUFS; } else { for (size_t i = 0; i < count; i++) { - Local chunk = chunks->Get(i); + Local chunk = chunks->Get(env->context(), i).ToLocalChecked(); bufs[i].base = Buffer::Data(chunk); bufs[i].len = Buffer::Length(chunk); } @@ -120,7 +120,7 @@ int StreamBase::Writev(const FunctionCallbackInfo& args) { offset = 0; if (!all_buffers) { for (size_t i = 0; i < count; i++) { - Local chunk = chunks->Get(i * 2); + Local chunk = chunks->Get(env->context(), i * 2).ToLocalChecked(); // Write buffer if (Buffer::HasInstance(chunk)) { @@ -136,7 +136,7 @@ int StreamBase::Writev(const FunctionCallbackInfo& args) { Local string = chunk->ToString(env->context()).ToLocalChecked(); enum encoding encoding = ParseEncoding(env->isolate(), - chunks->Get(i * 2 + 1)); + chunks->Get(env->context(), i * 2 + 1).ToLocalChecked()); str_size = StringBytes::Write(env->isolate(), str_storage, str_size, @@ -270,7 +270,9 @@ int StreamBase::WriteString(const FunctionCallbackInfo& args) { send_handle = reinterpret_cast(wrap->GetHandle()); // Reference LibuvStreamWrap instance to prevent it from being garbage // collected before `AfterWrite` is called. - req_wrap_obj->Set(env->handle_string(), send_handle_obj); + req_wrap_obj->Set(env->context(), + env->handle_string(), + send_handle_obj).FromJust(); } StreamWriteResult res = Write(&buf, 1, send_handle, req_wrap_obj); diff --git a/src/stream_wrap.cc b/src/stream_wrap.cc index dac5ebdeb32211..c7d5e2f23ff900 100644 --- a/src/stream_wrap.cc +++ b/src/stream_wrap.cc @@ -67,7 +67,9 @@ void LibuvStreamWrap::Initialize(Local target, FIXED_ONE_BYTE_STRING(env->isolate(), "ShutdownWrap"); sw->SetClassName(wrapString); sw->Inherit(AsyncWrap::GetConstructorTemplate(env)); - target->Set(wrapString, sw->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + wrapString, + sw->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_shutdown_wrap_template(sw->InstanceTemplate()); Local ww = @@ -77,8 +79,9 @@ void LibuvStreamWrap::Initialize(Local target, FIXED_ONE_BYTE_STRING(env->isolate(), "WriteWrap"); ww->SetClassName(writeWrapString); ww->Inherit(AsyncWrap::GetConstructorTemplate(env)); - target->Set(writeWrapString, - ww->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + writeWrapString, + ww->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_write_wrap_template(ww->InstanceTemplate()); NODE_DEFINE_CONSTANT(target, kReadBytesOrError); diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index d462eff15d391c..e1316b42cd206b 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -107,7 +107,9 @@ void TCPWrap::Initialize(Local target, env->SetProtoMethod(t, "setSimultaneousAccepts", SetSimultaneousAccepts); #endif - target->Set(tcpString, t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + tcpString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_tcp_constructor_template(t); // Create FunctionTemplate for TCPConnectWrap. @@ -117,7 +119,9 @@ void TCPWrap::Initialize(Local target, Local wrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"); cwt->SetClassName(wrapString); - target->Set(wrapString, cwt->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + wrapString, + cwt->GetFunction(env->context()).ToLocalChecked()).FromJust(); // Define constants Local constants = Object::New(env->isolate()); @@ -349,22 +353,36 @@ Local AddressToJS(Environment* env, a6 = reinterpret_cast(addr); uv_inet_ntop(AF_INET6, &a6->sin6_addr, ip, sizeof ip); port = ntohs(a6->sin6_port); - info->Set(env->address_string(), OneByteString(env->isolate(), ip)); - info->Set(env->family_string(), env->ipv6_string()); - info->Set(env->port_string(), Integer::New(env->isolate(), port)); + info->Set(env->context(), + env->address_string(), + OneByteString(env->isolate(), ip)).FromJust(); + info->Set(env->context(), + env->family_string(), + env->ipv6_string()).FromJust(); + info->Set(env->context(), + env->port_string(), + Integer::New(env->isolate(), port)).FromJust(); break; case AF_INET: a4 = reinterpret_cast(addr); uv_inet_ntop(AF_INET, &a4->sin_addr, ip, sizeof ip); port = ntohs(a4->sin_port); - info->Set(env->address_string(), OneByteString(env->isolate(), ip)); - info->Set(env->family_string(), env->ipv4_string()); - info->Set(env->port_string(), Integer::New(env->isolate(), port)); + info->Set(env->context(), + env->address_string(), + OneByteString(env->isolate(), ip)).FromJust(); + info->Set(env->context(), + env->family_string(), + env->ipv4_string()).FromJust(); + info->Set(env->context(), + env->port_string(), + Integer::New(env->isolate(), port)).FromJust(); break; default: - info->Set(env->address_string(), String::Empty(env->isolate())); + info->Set(env->context(), + env->address_string(), + String::Empty(env->isolate())).FromJust(); } return scope.Escape(info); diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 1d982db28e2558..52d4e7381318bc 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -909,7 +909,9 @@ void TLSWrap::Initialize(Local target, env->set_tls_wrap_constructor_function( t->GetFunction(env->context()).ToLocalChecked()); - target->Set(tlsWrapString, t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + tlsWrapString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); } } // namespace node diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index c099b14ec4d7a1..2523f57b2d4aab 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -59,7 +59,9 @@ void TTYWrap::Initialize(Local target, env->SetMethodNoSideEffect(target, "isTTY", IsTTY); env->SetMethodNoSideEffect(target, "guessHandleType", GuessHandleType); - target->Set(ttyString, t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + ttyString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_tty_constructor_template(t); } @@ -112,8 +114,8 @@ void TTYWrap::GetWindowSize(const FunctionCallbackInfo& args) { if (err == 0) { Local a = args[0].As(); - a->Set(0, Integer::New(env->isolate(), width)); - a->Set(1, Integer::New(env->isolate(), height)); + a->Set(env->context(), 0, Integer::New(env->isolate(), width)).FromJust(); + a->Set(env->context(), 1, Integer::New(env->isolate(), height)).FromJust(); } args.GetReturnValue().Set(err); diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index aa29f6973e35e0..4c7072f2a2b981 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -133,7 +133,9 @@ void UDPWrap::Initialize(Local target, t->Inherit(HandleWrap::GetConstructorTemplate(env)); - target->Set(udpString, t->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + udpString, + t->GetFunction(env->context()).ToLocalChecked()).FromJust(); env->set_udp_constructor_function( t->GetFunction(env->context()).ToLocalChecked()); @@ -144,8 +146,9 @@ void UDPWrap::Initialize(Local target, Local sendWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"); swt->SetClassName(sendWrapString); - target->Set(sendWrapString, - swt->GetFunction(env->context()).ToLocalChecked()); + target->Set(env->context(), + sendWrapString, + swt->GetFunction(env->context()).ToLocalChecked()).FromJust(); } @@ -373,7 +376,7 @@ void UDPWrap::DoSend(const FunctionCallbackInfo& args, int family) { // construct uv_buf_t array for (size_t i = 0; i < count; i++) { - Local chunk = chunks->Get(i); + Local chunk = chunks->Get(env->context(), i).ToLocalChecked(); size_t length = Buffer::Length(chunk); diff --git a/src/uv.cc b/src/uv.cc index 354acee4c01fc6..5628719c784653 100644 --- a/src/uv.cc +++ b/src/uv.cc @@ -63,10 +63,11 @@ void Initialize(Local target, Local context) { Environment* env = Environment::GetCurrent(context); Isolate* isolate = env->isolate(); - target->Set(FIXED_ONE_BYTE_STRING(isolate, "errname"), + target->Set(env->context(), + FIXED_ONE_BYTE_STRING(isolate, "errname"), env->NewFunctionTemplate(ErrName) ->GetFunction(env->context()) - .ToLocalChecked()); + .ToLocalChecked()).FromJust(); #define V(name, _) NODE_DEFINE_CONSTANT(target, UV_##name); UV_ERRNO_MAP(V) @@ -76,8 +77,8 @@ void Initialize(Local target, #define V(name, msg) do { \ Local arr = Array::New(isolate, 2); \ - arr->Set(0, OneByteString(isolate, #name)); \ - arr->Set(1, OneByteString(isolate, msg)); \ + arr->Set(env->context(), 0, OneByteString(isolate, #name)).FromJust(); \ + arr->Set(env->context(), 1, OneByteString(isolate, msg)).FromJust(); \ err_map->Set(context, \ Integer::New(isolate, UV_##name), \ arr).ToLocalChecked(); \ From 26c625c3d2a04637cf340ed2bd954494db3393c8 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 8 Nov 2018 11:43:50 +0100 Subject: [PATCH 176/249] test: fix v8 Set/Get compiler warnings PR-URL: https://github.com/nodejs/node/pull/24246 Reviewed-By: Anna Henningsen Reviewed-By: Refael Ackermann --- benchmark/napi/function_args/binding.cc | 3 ++- doc/api/addons.md | 14 +++++++++----- test/addons/async-hello-world/binding.cc | 3 ++- test/addons/heap-profiler/binding.cc | 4 ++-- test/addons/new-target/binding.cc | 4 ++-- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/benchmark/napi/function_args/binding.cc b/benchmark/napi/function_args/binding.cc index d0c1a079210532..9f250aaa83db50 100644 --- a/benchmark/napi/function_args/binding.cc +++ b/benchmark/napi/function_args/binding.cc @@ -33,7 +33,8 @@ void CallWithArray(const FunctionCallbackInfo& args) { uint32_t length = array->Length(); for (uint32_t i = 0; i < length; ++ i) { Local v; - v = array->Get(i); + v = array->Get(args.GetIsolate()->GetCurrentContext(), + i).ToLocalChecked(); } } } diff --git a/doc/api/addons.md b/doc/api/addons.md index e2530acb77d5e0..d993c72d346495 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -537,6 +537,7 @@ to invoke such callbacks: namespace demo { +using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::Isolate; @@ -549,13 +550,14 @@ using v8::Value; void RunCallback(const FunctionCallbackInfo& args) { Isolate* isolate = args.GetIsolate(); + Local context = isolate->GetCurrentContext(); Local cb = Local::Cast(args[0]); const unsigned argc = 1; Local argv[argc] = { String::NewFromUtf8(isolate, "hello world", NewStringType::kNormal).ToLocalChecked() }; - cb->Call(Null(isolate), argc, argv); + cb->Call(context, Null(isolate), argc, argv).ToLocalChecked(); } void Init(Local exports, Local module) { @@ -612,10 +614,12 @@ void CreateObject(const FunctionCallbackInfo& args) { Local context = isolate->GetCurrentContext(); Local obj = Object::New(isolate); - obj->Set(String::NewFromUtf8(isolate, + obj->Set(context, + String::NewFromUtf8(isolate, "msg", NewStringType::kNormal).ToLocalChecked(), - args[0]->ToString(context).ToLocalChecked()); + args[0]->ToString(context).ToLocalChecked()) + .FromJust(); args.GetReturnValue().Set(obj); } @@ -803,9 +807,9 @@ void MyObject::Init(Local exports) { Local context = isolate->GetCurrentContext(); constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked()); - exports->Set(String::NewFromUtf8( + exports->Set(context, String::NewFromUtf8( isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(), - tpl->GetFunction(context).ToLocalChecked()); + tpl->GetFunction(context).ToLocalChecked()).FromJust(); } void MyObject::New(const FunctionCallbackInfo& args) { diff --git a/test/addons/async-hello-world/binding.cc b/test/addons/async-hello-world/binding.cc index 3a584a88a07bc9..1bf94ddd1d70bc 100644 --- a/test/addons/async-hello-world/binding.cc +++ b/test/addons/async-hello-world/binding.cc @@ -53,7 +53,8 @@ void AfterAsync(uv_work_t* r) { // This should be changed to an empty handle. assert(!ret.IsEmpty()); } else { - callback->Call(global, 2, argv); + callback->Call(isolate->GetCurrentContext(), + global, 2, argv).ToLocalChecked(); } // cleanup diff --git a/test/addons/heap-profiler/binding.cc b/test/addons/heap-profiler/binding.cc index 29f58a5920825a..9e1e97e9fc2afc 100644 --- a/test/addons/heap-profiler/binding.cc +++ b/test/addons/heap-profiler/binding.cc @@ -19,11 +19,11 @@ inline void Test(const v8::FunctionCallbackInfo& args) { inline void Initialize(v8::Local binding) { v8::Isolate* const isolate = binding->GetIsolate(); v8::Local context = isolate->GetCurrentContext(); - binding->Set(v8::String::NewFromUtf8( + binding->Set(context, v8::String::NewFromUtf8( isolate, "test", v8::NewStringType::kNormal).ToLocalChecked(), v8::FunctionTemplate::New(isolate, Test) ->GetFunction(context) - .ToLocalChecked()); + .ToLocalChecked()).FromJust(); } NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) diff --git a/test/addons/new-target/binding.cc b/test/addons/new-target/binding.cc index c2777c831e484a..48ceeb55ca1aae 100644 --- a/test/addons/new-target/binding.cc +++ b/test/addons/new-target/binding.cc @@ -12,11 +12,11 @@ inline void NewClass(const v8::FunctionCallbackInfo& args) { inline void Initialize(v8::Local binding) { auto isolate = binding->GetIsolate(); auto context = isolate->GetCurrentContext(); - binding->Set(v8::String::NewFromUtf8( + binding->Set(context, v8::String::NewFromUtf8( isolate, "Class", v8::NewStringType::kNormal).ToLocalChecked(), v8::FunctionTemplate::New(isolate, NewClass) ->GetFunction(context) - .ToLocalChecked()); + .ToLocalChecked()).FromJust(); } NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) From 2593b40f5c84837f3111cfacde229ae3844f26d5 Mon Sep 17 00:00:00 2001 From: Marie Terrier Date: Tue, 6 Nov 2018 17:37:47 +0100 Subject: [PATCH 177/249] test : compare objects not identical by reference PR-URL: https://github.com/nodejs/node/pull/24189 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca --- test/parallel/test-assert-deep.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/parallel/test-assert-deep.js b/test/parallel/test-assert-deep.js index 3a5fca74d4c287..ddbc5e78eafcaf 100644 --- a/test/parallel/test-assert-deep.js +++ b/test/parallel/test-assert-deep.js @@ -915,6 +915,27 @@ assert.deepStrictEqual(obj1, obj2); ); } +// Strict equal with identical objects that are not identical +// by reference and longer than 30 elements +// E.g., assert.deepStrictEqual({ a: Symbol() }, { a: Symbol() }) +{ + const a = {}; + const b = {}; + for (let i = 0; i < 35; i++) { + a[`symbol${i}`] = Symbol(); + b[`symbol${i}`] = Symbol(); + } + + assert.throws( + () => assert.deepStrictEqual(a, b), + { + code: 'ERR_ASSERTION', + name: 'AssertionError [ERR_ASSERTION]', + message: /\.\.\./g + } + ); +} + // Basic valueOf check. { const a = new String(1); From 768425f21a623af23a952084ccf05286f1738b37 Mon Sep 17 00:00:00 2001 From: John Mc Quillan Date: Tue, 6 Nov 2018 16:12:21 +0000 Subject: [PATCH 178/249] test: fix assert.strictEqual argument order The arguments to assert.strictEqual in a number of calls were in the wrong order. It is preferred that literal values are in the second argument. Updates test/parallel/test-fs-readStream.js PR-URL: https://github.com/nodejs/node/pull/24172 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- test/parallel/test-fs-read-stream.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-fs-read-stream.js b/test/parallel/test-fs-read-stream.js index 793b474c9b8292..2a07a09c976574 100644 --- a/test/parallel/test-fs-read-stream.js +++ b/test/parallel/test-fs-read-stream.js @@ -42,7 +42,7 @@ const rangeFile = fixtures.path('x.txt'); file.on('open', common.mustCall(function(fd) { file.length = 0; - assert.strictEqual('number', typeof fd); + assert.strictEqual(typeof fd, 'number'); assert.strictEqual(file.bytesRead, 0); assert.ok(file.readable); @@ -91,12 +91,12 @@ const rangeFile = fixtures.path('x.txt'); const file = fs.createReadStream(fn, { encoding: 'utf8' }); file.length = 0; file.on('data', function(data) { - assert.strictEqual('string', typeof data); + assert.strictEqual(typeof data, 'string'); file.length += data.length; for (let i = 0; i < data.length; i++) { // http://www.fileformat.info/info/unicode/char/2026/index.htm - assert.strictEqual('\u2026', data[i]); + assert.strictEqual(data[i], '\u2026'); } }); @@ -162,7 +162,7 @@ common.expectsError( }); stream.on('end', common.mustCall(function() { - assert.strictEqual('x', stream.data); + assert.strictEqual(stream.data, 'x'); })); } @@ -176,7 +176,7 @@ common.expectsError( }); stream.on('end', common.mustCall(function() { - assert.strictEqual('xy', stream.data); + assert.strictEqual(stream.data, 'xy'); })); } @@ -197,7 +197,7 @@ if (!common.isWindows) { }); stream.on('end', common.mustCall(function() { - assert.strictEqual('xy', stream.data); + assert.strictEqual(stream.data, 'xy'); fs.unlinkSync(filename); })); } else { From b02eed5e3b5e1f7bf7d52f98688018a7c8008a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulises=20Santana=20Su=C3=A1rez?= Date: Tue, 6 Nov 2018 16:38:36 +0000 Subject: [PATCH 179/249] test: fix arguments order in assert.strictEqual() PR-URL: https://github.com/nodejs/node/pull/24192 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- test/parallel/test-http-1.0.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/parallel/test-http-1.0.js b/test/parallel/test-http-1.0.js index 47df50e2897b79..134a5bb9853102 100644 --- a/test/parallel/test-http-1.0.js +++ b/test/parallel/test-http-1.0.js @@ -58,9 +58,9 @@ function test(handler, request_generator, response_validator) { { function handler(req, res) { - assert.strictEqual('1.0', req.httpVersion); - assert.strictEqual(1, req.httpVersionMajor); - assert.strictEqual(0, req.httpVersionMinor); + assert.strictEqual(req.httpVersion, '1.0'); + assert.strictEqual(req.httpVersionMajor, 1); + assert.strictEqual(req.httpVersionMinor, 0); res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end(body); } @@ -72,8 +72,8 @@ function test(handler, request_generator, response_validator) { function response_validator(server_response, client_got_eof, timed_out) { const m = server_response.split('\r\n\r\n'); assert.strictEqual(m[1], body); - assert.strictEqual(true, client_got_eof); - assert.strictEqual(false, timed_out); + assert.strictEqual(client_got_eof, true); + assert.strictEqual(timed_out, false); } test(handler, request_generator, response_validator); @@ -86,9 +86,9 @@ function test(handler, request_generator, response_validator) { // { function handler(req, res) { - assert.strictEqual('1.0', req.httpVersion); - assert.strictEqual(1, req.httpVersionMajor); - assert.strictEqual(0, req.httpVersionMinor); + assert.strictEqual(req.httpVersion, '1.0'); + assert.strictEqual(req.httpVersionMajor, 1); + assert.strictEqual(req.httpVersionMinor, 0); res.sendDate = false; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('Hello, '); res._send(''); @@ -112,9 +112,9 @@ function test(handler, request_generator, response_validator) { '\r\n' + 'Hello, world!'; - assert.strictEqual(expected_response, server_response); - assert.strictEqual(true, client_got_eof); - assert.strictEqual(false, timed_out); + assert.strictEqual(server_response, expected_response); + assert.strictEqual(client_got_eof, true); + assert.strictEqual(timed_out, false); } test(handler, request_generator, response_validator); @@ -122,9 +122,9 @@ function test(handler, request_generator, response_validator) { { function handler(req, res) { - assert.strictEqual('1.1', req.httpVersion); - assert.strictEqual(1, req.httpVersionMajor); - assert.strictEqual(1, req.httpVersionMinor); + assert.strictEqual(req.httpVersion, '1.1'); + assert.strictEqual(req.httpVersionMajor, 1); + assert.strictEqual(req.httpVersionMinor, 1); res.sendDate = false; res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write('Hello, '); res._send(''); @@ -155,9 +155,9 @@ function test(handler, request_generator, response_validator) { '0\r\n' + '\r\n'; - assert.strictEqual(expected_response, server_response); - assert.strictEqual(true, client_got_eof); - assert.strictEqual(false, timed_out); + assert.strictEqual(server_response, expected_response); + assert.strictEqual(client_got_eof, true); + assert.strictEqual(timed_out, false); } test(handler, request_generator, response_validator); From 991d066338f7dd4f2e3197ec0b3513a42a2777af Mon Sep 17 00:00:00 2001 From: Ouyang Yadong Date: Sun, 11 Nov 2018 16:59:41 +0800 Subject: [PATCH 180/249] doc: add oyyd to collaborators PR-URL: https://github.com/nodejs/node/pull/24300 Fixes: https://github.com/nodejs/node/issues/23955 Reviewed-By: Gireesh Punathil Reviewed-By: Joyee Cheung Reviewed-By: Anna Henningsen --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 79b12e289a58f4..533b36bf8dbd58 100644 --- a/README.md +++ b/README.md @@ -401,6 +401,8 @@ For information about the governance of the Node.js project, see **Alexis Campailla** <orangemocha@nodejs.org> * [othiym23](https://github.com/othiym23) - **Forrest L Norvell** <ogd@aoaioxxysz.net> (he/him) +* [oyyd](https://github.com/oyyd) - +**Ouyang Yadong** <oyydoibh@gmail.com> (he/him) * [pmq20](https://github.com/pmq20) - **Minqi Pan** <pmq2001@gmail.com> * [princejwesley](https://github.com/princejwesley) - From afcfdec2893f6ab7a8e4a92ab215fbfa23fadd5f Mon Sep 17 00:00:00 2001 From: Yehiyam Livneh Date: Tue, 6 Nov 2018 17:41:19 +0200 Subject: [PATCH 181/249] test: add test for deepEqual Float32Array PR-URL: https://github.com/nodejs/node/pull/24164 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- test/parallel/test-assert-typedarray-deepequal.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/parallel/test-assert-typedarray-deepequal.js b/test/parallel/test-assert-typedarray-deepequal.js index 78394bb91facde..1e9c8c8d1c247d 100644 --- a/test/parallel/test-assert-typedarray-deepequal.js +++ b/test/parallel/test-assert-typedarray-deepequal.js @@ -47,6 +47,7 @@ const notEqualArrayPairs = [ [new Int16Array([-256]), new Uint16Array([0xff00])], // same bits [new Int32Array([-256]), new Uint32Array([0xffffff00])], // ditto [new Float32Array([0.1]), new Float32Array([0.0])], + [new Float32Array([0.1]), new Float32Array([0.1, 0.2])], [new Float64Array([0.1]), new Float64Array([0.0])], [new Uint8Array([1, 2, 3]).buffer, new Uint8Array([4, 5, 6]).buffer], [ From 762bb94d7203a42c0e4bccd03939de57dc5ce7d8 Mon Sep 17 00:00:00 2001 From: Aivo Paas Date: Tue, 6 Nov 2018 15:52:09 +0000 Subject: [PATCH 182/249] test: add test case for completion bash flag This test case verifies that starting Node.js with the completion bash flag prints out the expected result and ends right after. PR-URL: https://github.com/nodejs/node/pull/24168 Reviewed-By: Bryan English Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- test/parallel/test-bash-completion.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 test/parallel/test-bash-completion.js diff --git a/test/parallel/test-bash-completion.js b/test/parallel/test-bash-completion.js new file mode 100644 index 00000000000000..50378a7b0f8028 --- /dev/null +++ b/test/parallel/test-bash-completion.js @@ -0,0 +1,23 @@ +'use strict'; +require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); + +const p = child_process.spawnSync( + process.execPath, [ '--completion-bash' ]); +assert.ifError(p.error); +assert.ok(p.stdout.toString().includes( + `_node_complete() { + local cur_word options + cur_word="\${COMP_WORDS[COMP_CWORD]}" + if [[ "\${cur_word}" == -* ]] ; then + COMPREPLY=( $(compgen -W '`)); +assert.ok(p.stdout.toString().includes( + `' -- "\${cur_word}") ) + return 0 + else + COMPREPLY=( $(compgen -f "\${cur_word}") ) + return 0 + fi +} +complete -F _node_complete node node_g`)); From 0c9d86f58c5f5b4e502712717c735877f4d7c8ec Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 2 Nov 2018 07:53:57 +0100 Subject: [PATCH 183/249] build: use BUILDTYPE in bench-addons-build targets This commit uses the BUILDTYPE for the benchmark targets that currently explicitly use Release as the build type. The motivation for this change is allows switching between debug builds and release builds using the bench-addons-clean/bench-addons-build targets. PR-URL: https://github.com/nodejs/node/pull/24033 Reviewed-By: Richard Lau Reviewed-By: Refael Ackermann Reviewed-By: James M Snell --- Makefile | 8 ++++---- benchmark/common.js | 2 ++ benchmark/napi/function_args/index.js | 4 ++-- benchmark/napi/function_call/index.js | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 6a426384f2d4b7..2c6efa7b9afb44 100644 --- a/Makefile +++ b/Makefile @@ -308,7 +308,7 @@ test-valgrind: all test-check-deopts: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) --mode=$(BUILDTYPE_LOWER) --check-deopts parallel sequential -benchmark/napi/function_call/build/Release/binding.node: \ +benchmark/napi/function_call/build/$(BUILDTYPE)/binding.node: \ benchmark/napi/function_call/napi_binding.c \ benchmark/napi/function_call/binding.cc \ benchmark/napi/function_call/binding.gyp | all @@ -317,7 +317,7 @@ benchmark/napi/function_call/build/Release/binding.node: \ --directory="$(shell pwd)/benchmark/napi/function_call" \ --nodedir="$(shell pwd)" -benchmark/napi/function_args/build/Release/binding.node: \ +benchmark/napi/function_args/build/$(BUILDTYPE)/binding.node: \ benchmark/napi/function_args/napi_binding.c \ benchmark/napi/function_args/binding.cc \ benchmark/napi/function_args/binding.gyp | all @@ -1050,8 +1050,8 @@ bench: bench-addons-build # Build required addons for benchmark before running it. .PHONY: bench-addons-build -bench-addons-build: benchmark/napi/function_call/build/Release/binding.node \ - benchmark/napi/function_args/build/Release/binding.node +bench-addons-build: benchmark/napi/function_call/build/$(BUILDTYPE)/binding.node \ + benchmark/napi/function_args/build/$(BUILDTYPE)/binding.node .PHONY: bench-addons-clean bench-addons-clean: diff --git a/benchmark/common.js b/benchmark/common.js index 79aef5a55f9bcd..c76831b573dde6 100644 --- a/benchmark/common.js +++ b/benchmark/common.js @@ -3,6 +3,8 @@ const child_process = require('child_process'); const http_benchmarkers = require('./_http-benchmarkers.js'); +exports.buildType = process.features.debug ? 'Debug' : 'Release'; + exports.createBenchmark = function(fn, configs, options) { return new Benchmark(fn, configs, options); }; diff --git a/benchmark/napi/function_args/index.js b/benchmark/napi/function_args/index.js index c41b5d78abadd9..df567dcfcc55bc 100644 --- a/benchmark/napi/function_args/index.js +++ b/benchmark/napi/function_args/index.js @@ -10,14 +10,14 @@ let v8; let napi; try { - v8 = require('./build/Release/binding'); + v8 = require(`./build/${common.buildType}/binding`); } catch { console.error(`${__filename}: V8 Binding failed to load`); process.exit(0); } try { - napi = require('./build/Release/napi_binding'); + napi = require(`./build/${common.buildType}/napi_binding`); } catch { console.error(`${__filename}: NAPI-Binding failed to load`); process.exit(0); diff --git a/benchmark/napi/function_call/index.js b/benchmark/napi/function_call/index.js index 272c41662d2830..59063e500f7a84 100644 --- a/benchmark/napi/function_call/index.js +++ b/benchmark/napi/function_call/index.js @@ -12,7 +12,7 @@ const common = require('../../common.js'); // abort quietly. try { - var binding = require('./build/Release/binding'); + var binding = require(`./build/${common.buildType}/binding`); } catch { console.error('misc/function_call.js Binding failed to load'); process.exit(0); @@ -21,7 +21,7 @@ const cxx = binding.hello; let napi_binding; try { - napi_binding = require('./build/Release/napi_binding'); + napi_binding = require(`./build/${common.buildType}/napi_binding`); } catch { console.error('misc/function_call/index.js NAPI-Binding failed to load'); process.exit(0); From c83b650a10aaae491a2f077a36860ffefb9925d2 Mon Sep 17 00:00:00 2001 From: James Herrington Date: Tue, 6 Nov 2018 15:19:21 +0000 Subject: [PATCH 184/249] test: add tests for process.initgroups - test argument validation - test function throws if provided group is invalid PR-URL: https://github.com/nodejs/node/pull/24154 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- test/parallel/test-process-initgroups.js | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/parallel/test-process-initgroups.js diff --git a/test/parallel/test-process-initgroups.js b/test/parallel/test-process-initgroups.js new file mode 100644 index 00000000000000..49b8833f61a7bc --- /dev/null +++ b/test/parallel/test-process-initgroups.js @@ -0,0 +1,54 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); + +if (common.isWindows || !common.isMainThread) { + assert.strictEqual(process.initgroups, undefined); + return; +} + +[undefined, null, true, {}, [], () => {}].forEach((val) => { + assert.throws( + () => { + process.initgroups(val); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError [ERR_INVALID_ARG_TYPE]', + message: + 'The "user" argument must be ' + + 'one of type number or string. ' + + `Received type ${typeof val}` + } + ); +}); + +[undefined, null, true, {}, [], () => {}].forEach((val) => { + assert.throws( + () => { + process.initgroups('foo', val); + }, + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError [ERR_INVALID_ARG_TYPE]', + message: + 'The "extraGroup" argument must be ' + + 'one of type number or string. ' + + `Received type ${typeof val}` + } + ); +}); + +assert.throws( + () => { + process.initgroups( + 'fhqwhgadshgnsdhjsdbkhsdabkfabkveyb', + 'fhqwhgadshgnsdhjsdbkhsdabkfabkveyb' + ); + }, + { + code: 'ERR_UNKNOWN_CREDENTIAL', + message: + 'Group identifier does not exist: fhqwhgadshgnsdhjsdbkhsdabkfabkveyb' + } +); From 82c64d00086a41cbf2866e4fc84e5d0326fde89a Mon Sep 17 00:00:00 2001 From: Gerhard Stoebich Date: Fri, 2 Nov 2018 23:58:37 +0100 Subject: [PATCH 185/249] doc: correct async_hooks sample outputs Correct the output of async_hooks samples * `TIMERWRAP` has been removed in #20894 * `console.log()` doesn't issue `TTYWRAP` nor `SIGNALWRAP` I don't know which PR caused that `console.log()` is no longer using `TTYWRAP` and `SIGNALWRAP`; I think it was between 8.4.0 and 8.5.0. PR-URL: https://github.com/nodejs/node/pull/24050 Refs: https://github.com/nodejs/node/pull/20894 Reviewed-By: James M Snell --- doc/api/async_hooks.md | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 06343aaf7f716c..1529e33e474084 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -276,8 +276,8 @@ require('net').createServer((conn) => {}).listen(8080); Output when hitting the server with `nc localhost 8080`: ```console -TCPSERVERWRAP(2): trigger: 1 execution: 1 -TCPWRAP(4): trigger: 2 execution: 0 +TCPSERVERWRAP(5): trigger: 1 execution: 1 +TCPWRAP(7): trigger: 5 execution: 0 ``` The `TCPSERVERWRAP` is the server which receives the connections. @@ -355,27 +355,18 @@ require('net').createServer(() => {}).listen(8080, () => { Output from only starting the server: ```console -TCPSERVERWRAP(2): trigger: 1 execution: 1 -TickObject(3): trigger: 2 execution: 1 -before: 3 - Timeout(4): trigger: 3 execution: 3 - TIMERWRAP(5): trigger: 3 execution: 3 -after: 3 -destroy: 3 -before: 5 - before: 4 - TTYWRAP(6): trigger: 4 execution: 4 - SIGNALWRAP(7): trigger: 4 execution: 4 - TTYWRAP(8): trigger: 4 execution: 4 ->>> 4 - TickObject(9): trigger: 4 execution: 4 - after: 4 -after: 5 -before: 9 -after: 9 -destroy: 4 -destroy: 9 -destroy: 5 +TCPSERVERWRAP(5): trigger: 1 execution: 1 +TickObject(6): trigger: 5 execution: 1 +before: 6 + Timeout(7): trigger: 6 execution: 6 +after: 6 +destroy: 6 +before: 7 +>>> 7 + TickObject(8): trigger: 7 execution: 7 +after: 7 +before: 8 +after: 8 ``` As illustrated in the example, `executionAsyncId()` and `execution` each specify @@ -385,7 +376,7 @@ the value of the current execution context; which is delineated by calls to Only using `execution` to graph resource allocation results in the following: ```console -TTYWRAP(6) -> Timeout(4) -> TIMERWRAP(5) -> TickObject(3) -> root(1) +Timeout(7) -> TickObject(6) -> root(1) ``` The `TCPSERVERWRAP` is not part of this graph, even though it was the reason for From 09a8f4713de0dfe2fd4d1c31a71320af9dca01b4 Mon Sep 17 00:00:00 2001 From: Natalie Cluer Date: Tue, 6 Nov 2018 15:15:40 +0000 Subject: [PATCH 186/249] test: correct order of args in assert.strictEqual() Ensure literal values are passed in as second argument PR-URL: https://github.com/nodejs/node/pull/24157 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- test/parallel/test-buffer-fill.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-buffer-fill.js b/test/parallel/test-buffer-fill.js index 6a0a8adb7ae2b9..61ff6bbb501f4d 100644 --- a/test/parallel/test-buffer-fill.js +++ b/test/parallel/test-buffer-fill.js @@ -303,19 +303,19 @@ Buffer.alloc(8, ''); buf.fill(0); for (let i = 0; i < buf.length; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); buf.fill(null); for (let i = 0; i < buf.length; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); buf.fill(1, 16, 32); for (let i = 0; i < 16; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); for (let i = 16; i < 32; i++) - assert.strictEqual(1, buf[i]); + assert.strictEqual(buf[i], 1); for (let i = 32; i < buf.length; i++) - assert.strictEqual(0, buf[i]); + assert.strictEqual(buf[i], 0); } { From 2b48c7169a10afccdffc8aa43bbd8528bba80af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Fri, 9 Nov 2018 09:48:48 +0100 Subject: [PATCH 187/249] crypto: put legacy _handle accessors on prototypes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Creating deprecated accessors each time an object is created is very time consuming. Refs: https://github.com/nodejs/node/pull/22747 Fixes: https://github.com/nodejs/node/issues/24266 PR-URL: https://github.com/nodejs/node/pull/24269 Reviewed-By: Tobias Nießen Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- lib/internal/crypto/cipher.js | 7 ++++++- lib/internal/crypto/diffiehellman.js | 11 ++++++++--- lib/internal/crypto/hash.js | 8 ++++++-- lib/internal/crypto/sig.js | 8 ++++++-- lib/internal/crypto/util.js | 17 ++++++++--------- 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/lib/internal/crypto/cipher.js b/lib/internal/crypto/cipher.js index a2e973ed849f10..a3f28c183a46b7 100644 --- a/lib/internal/crypto/cipher.js +++ b/lib/internal/crypto/cipher.js @@ -74,7 +74,7 @@ function getUIntOption(options, key) { function createCipherBase(cipher, credential, options, decipher, iv) { const authTagLength = getUIntOption(options, 'authTagLength'); - legacyNativeHandle(this, new CipherBase(decipher)); + this[kHandle] = new CipherBase(decipher); if (iv === undefined) { this[kHandle].init(cipher, credential, authTagLength); } else { @@ -219,6 +219,8 @@ Cipher.prototype.setAAD = function setAAD(aadbuf, options) { return this; }; +legacyNativeHandle(Cipher); + function Cipheriv(cipher, key, iv, options) { if (!(this instanceof Cipheriv)) return new Cipheriv(cipher, key, iv, options); @@ -254,6 +256,7 @@ function addCipherPrototypeFunctions(constructor) { inherits(Cipheriv, LazyTransform); addCipherPrototypeFunctions(Cipheriv); +legacyNativeHandle(Cipheriv); function Decipher(cipher, password, options) { if (!(this instanceof Decipher)) @@ -264,6 +267,7 @@ function Decipher(cipher, password, options) { inherits(Decipher, LazyTransform); addCipherPrototypeFunctions(Decipher); +legacyNativeHandle(Decipher); function Decipheriv(cipher, key, iv, options) { @@ -275,6 +279,7 @@ function Decipheriv(cipher, key, iv, options) { inherits(Decipheriv, LazyTransform); addCipherPrototypeFunctions(Decipheriv); +legacyNativeHandle(Decipheriv); module.exports = { Cipher, diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js index 4f5bcbad972b26..81204cfda3e676 100644 --- a/lib/internal/crypto/diffiehellman.js +++ b/lib/internal/crypto/diffiehellman.js @@ -61,7 +61,7 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { else if (typeof generator !== 'number') generator = toBuf(generator, genEncoding); - legacyNativeHandle(this, new _DiffieHellman(sizeOrKey, generator)); + this[kHandle] = new _DiffieHellman(sizeOrKey, generator); Object.defineProperty(this, 'verifyError', { enumerable: true, value: this[kHandle].verifyError, @@ -73,7 +73,7 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { function DiffieHellmanGroup(name) { if (!(this instanceof DiffieHellmanGroup)) return new DiffieHellmanGroup(name); - legacyNativeHandle(this, new _DiffieHellmanGroup(name)); + this[kHandle] = new _DiffieHellmanGroup(name); Object.defineProperty(this, 'verifyError', { enumerable: true, value: this[kHandle].verifyError, @@ -165,13 +165,16 @@ DiffieHellman.prototype.setPrivateKey = function setPrivateKey(key, encoding) { return this; }; +legacyNativeHandle(DiffieHellman); +legacyNativeHandle(DiffieHellmanGroup); + function ECDH(curve) { if (!(this instanceof ECDH)) return new ECDH(curve); validateString(curve, 'curve'); - legacyNativeHandle(this, new _ECDH(curve)); + this[kHandle] = new _ECDH(curve); } ECDH.prototype.computeSecret = DiffieHellman.prototype.computeSecret; @@ -192,6 +195,8 @@ ECDH.prototype.getPublicKey = function getPublicKey(encoding, format) { return encode(key, encoding); }; +legacyNativeHandle(ECDH); + ECDH.convertKey = function convertKey(key, curve, inEnc, outEnc, format) { if (typeof key !== 'string' && !isArrayBufferView(key)) { throw new ERR_INVALID_ARG_TYPE( diff --git a/lib/internal/crypto/hash.js b/lib/internal/crypto/hash.js index 308c16f9a88b93..6803d8fa954e73 100644 --- a/lib/internal/crypto/hash.js +++ b/lib/internal/crypto/hash.js @@ -32,7 +32,7 @@ function Hash(algorithm, options) { if (!(this instanceof Hash)) return new Hash(algorithm, options); validateString(algorithm, 'algorithm'); - legacyNativeHandle(this, new _Hash(algorithm)); + this[kHandle] = new _Hash(algorithm); this[kState] = { [kFinalized]: false }; @@ -81,6 +81,8 @@ Hash.prototype.digest = function digest(outputEncoding) { return ret; }; +legacyNativeHandle(Hash); + function Hmac(hmac, key, options) { if (!(this instanceof Hmac)) @@ -90,7 +92,7 @@ function Hmac(hmac, key, options) { throw new ERR_INVALID_ARG_TYPE('key', ['string', 'TypedArray', 'DataView'], key); } - legacyNativeHandle(this, new _Hmac()); + this[kHandle] = new _Hmac(); this[kHandle].init(hmac, toBuf(key)); this[kState] = { [kFinalized]: false @@ -122,6 +124,8 @@ Hmac.prototype.digest = function digest(outputEncoding) { Hmac.prototype._flush = Hash.prototype._flush; Hmac.prototype._transform = Hash.prototype._transform; +legacyNativeHandle(Hmac); + module.exports = { Hash, Hmac diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 43033345afa545..9f02c866739f24 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -24,7 +24,7 @@ function Sign(algorithm, options) { if (!(this instanceof Sign)) return new Sign(algorithm, options); validateString(algorithm, 'algorithm'); - legacyNativeHandle(this, new _Sign()); + this[kHandle] = new _Sign(); this[kHandle].init(algorithm); Writable.call(this, options); @@ -45,6 +45,8 @@ Sign.prototype.update = function update(data, encoding) { return this; }; +legacyNativeHandle(Sign); + function getPadding(options) { return getIntOption('padding', RSA_PKCS1_PADDING, options); } @@ -93,7 +95,7 @@ function Verify(algorithm, options) { if (!(this instanceof Verify)) return new Verify(algorithm, options); validateString(algorithm, 'algorithm'); - legacyNativeHandle(this, new _Verify()); + this[kHandle] = new _Verify(); this[kHandle].init(algorithm); Writable.call(this, options); @@ -121,6 +123,8 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { return this[kHandle].verify(key, signature, rsaPadding, pssSaltLength); }; +legacyNativeHandle(Verify); + module.exports = { Sign, Verify diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index ff5bfce4a76a49..6746f2a66c818a 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -30,15 +30,14 @@ const { const kHandle = Symbol('kHandle'); -function legacyNativeHandle(obj, handle) { - obj[kHandle] = handle; - Object.defineProperty(obj, '_handle', { - get: deprecate(() => handle, - `${obj.constructor.name}._handle is deprecated. Use the ` + - 'public API instead.', 'DEP0117'), - set: deprecate((h) => obj[kHandle] = handle = h, - `${obj.constructor.name}._handle is deprecated. Use the ` + - 'public API instead.', 'DEP0117'), +function legacyNativeHandle(clazz) { + Object.defineProperty(clazz.prototype, '_handle', { + get: deprecate(function() { return this[kHandle]; }, + `${clazz.name}._handle is deprecated. Use the public API ` + + 'instead.', 'DEP0117'), + set: deprecate(function(h) { this[kHandle] = h; }, + `${clazz.name}._handle is deprecated. Use the public API ` + + 'instead.', 'DEP0117'), enumerable: false }); } From 9cefbba5d7ea1d9258a5d32b44c71e1bdb264ddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Fri, 9 Nov 2018 12:12:17 +0100 Subject: [PATCH 188/249] deps: patch V8 to 7.0.276.38 Refs: https://github.com/v8/v8/compare/7.0.276.36...7.0.276.38 PR-URL: https://github.com/nodejs/node/pull/24271 Reviewed-By: Ali Ijaz Sheikh Reviewed-By: Matheus Marchini Reviewed-By: Refael Ackermann Reviewed-By: James M Snell --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/wasm/module-compiler.cc | 58 ++++++----- deps/v8/src/wasm/module-compiler.h | 4 + .../v8/test/mjsunit/regress/regress-897366.js | 15 +++ deps/v8/test/mjsunit/wasm/async-compile.js | 7 ++ deps/v8/third_party/v8/builtins/array-sort.tq | 97 ++++++++----------- 6 files changed, 101 insertions(+), 82 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-897366.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index f43a776eac99d3..63dc5e7a7bab0f 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 7 #define V8_MINOR_VERSION 0 #define V8_BUILD_NUMBER 276 -#define V8_PATCH_LEVEL 36 +#define V8_PATCH_LEVEL 38 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/wasm/module-compiler.cc b/deps/v8/src/wasm/module-compiler.cc index b950c590b5c6b2..892a4e980e8b55 100644 --- a/deps/v8/src/wasm/module-compiler.cc +++ b/deps/v8/src/wasm/module-compiler.cc @@ -2329,12 +2329,6 @@ void AsyncCompileJob::CancelPendingForegroundTask() { pending_foreground_task_ = nullptr; } -template -void AsyncCompileJob::DoSync(Args&&... args) { - NextStep(std::forward(args)...); - StartForegroundTask(); -} - void AsyncCompileJob::StartBackgroundTask() { auto task = base::make_unique(this, false); @@ -2347,6 +2341,18 @@ void AsyncCompileJob::StartBackgroundTask() { } } +template +void AsyncCompileJob::DoSync(Args&&... args) { + NextStep(std::forward(args)...); + StartForegroundTask(); +} + +template +void AsyncCompileJob::DoImmediately(Args&&... args) { + NextStep(std::forward(args)...); + ExecuteForegroundTaskImmediately(); +} + template void AsyncCompileJob::DoAsync(Args&&... args) { NextStep(std::forward(args)...); @@ -2686,11 +2692,10 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(size_t functions_count, FinishAsyncCompileJobWithError(decoder_.FinishDecoding(false)); return false; } - job_->NextStep( - decoder_.shared_module(), false); // Execute the PrepareAndStartCompile step immediately and not in a separate // task. - job_->ExecuteForegroundTaskImmediately(); + job_->DoImmediately( + decoder_.shared_module(), false); job_->native_module_->compilation_state()->SetNumberOfFunctionsToCompile( functions_count); @@ -2734,25 +2739,26 @@ void AsyncStreamingProcessor::OnFinishedChunk() { // Finish the processing of the stream. void AsyncStreamingProcessor::OnFinishedStream(OwnedVector bytes) { TRACE_STREAMING("Finish stream...\n"); - if (job_->native_module_) { - job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); - job_->native_module_->set_wire_bytes(std::move(bytes)); - } ModuleResult result = decoder_.FinishDecoding(false); DCHECK(result.ok()); - if (job_->DecrementAndCheckFinisherCount()) { - if (job_->native_module_ == nullptr) { - // We are processing a WebAssembly module without code section. We need to - // prepare compilation first before we can finish it. - // {PrepareAndStartCompile} will call {FinishCompile} by itself if there - // is no code section. - job_->DoSync(result.val, true); - } else { - HandleScope scope(job_->isolate_); - SaveContext saved_context(job_->isolate_); - job_->isolate_->set_context(*job_->native_context_); - job_->FinishCompile(); - } + bool needs_finish = job_->DecrementAndCheckFinisherCount(); + if (job_->native_module_ == nullptr) { + // We are processing a WebAssembly module without code section. We need to + // prepare compilation first before we can finish it. + // {PrepareAndStartCompile} will call {FinishCompile} by itself if there + // is no code section. + DCHECK(needs_finish); + needs_finish = false; + job_->DoImmediately(result.val, + true); + } + job_->wire_bytes_ = ModuleWireBytes(bytes.as_vector()); + job_->native_module_->set_wire_bytes(std::move(bytes)); + if (needs_finish) { + HandleScope scope(job_->isolate_); + SaveContext saved_context(job_->isolate_); + job_->isolate_->set_context(*job_->native_context_); + job_->FinishCompile(); } } diff --git a/deps/v8/src/wasm/module-compiler.h b/deps/v8/src/wasm/module-compiler.h index 57bbd883e21f30..934c978d491109 100644 --- a/deps/v8/src/wasm/module-compiler.h +++ b/deps/v8/src/wasm/module-compiler.h @@ -126,6 +126,10 @@ class AsyncCompileJob { template void DoSync(Args&&... args); + // Switches to the compilation step {Step} and immediately executes that step. + template + void DoImmediately(Args&&... args); + // Switches to the compilation step {Step} and starts a background task to // execute it. template diff --git a/deps/v8/test/mjsunit/regress/regress-897366.js b/deps/v8/test/mjsunit/regress/regress-897366.js new file mode 100644 index 00000000000000..990e21590e5a7f --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-897366.js @@ -0,0 +1,15 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --gc-interval=100 + +let xs = []; +for (let i = 0; i < 205; ++i) { + xs.push(i); +} +xs.sort((a, b) => { + xs.shift(); + xs[xs.length] = -246; + return a - b; +}); diff --git a/deps/v8/test/mjsunit/wasm/async-compile.js b/deps/v8/test/mjsunit/wasm/async-compile.js index e7f87c30e9e418..39a339aae63209 100644 --- a/deps/v8/test/mjsunit/wasm/async-compile.js +++ b/deps/v8/test/mjsunit/wasm/async-compile.js @@ -70,3 +70,10 @@ assertPromiseResult(async function badFunctionInTheMiddle() { let buffer = builder.toBuffer(); await assertCompileError(buffer); }()); + +assertPromiseResult(async function importWithoutCode() { + // Regression test for https://crbug.com/898310. + let builder = new WasmModuleBuilder(); + builder.addImport('m', 'q', kSig_i_i); + await builder.asyncInstantiate({'m': {'q': i => i}}); +}()); diff --git a/deps/v8/third_party/v8/builtins/array-sort.tq b/deps/v8/third_party/v8/builtins/array-sort.tq index 3f5a3b19b7af8c..65d0b8348bd210 100644 --- a/deps/v8/third_party/v8/builtins/array-sort.tq +++ b/deps/v8/third_party/v8/builtins/array-sort.tq @@ -826,7 +826,7 @@ module array { assert(i >= 0); assert(i == stack_size - 2 || i == stack_size - 3); - const elements: HeapObject = ReloadElements(sortState); + let elements: HeapObject = ReloadElements(sortState); const Load: LoadFn = GetLoadFn(sortState); const pending_runs: FixedArray = @@ -859,6 +859,7 @@ module array { const k: Smi = CallGallopRight( context, sortState, Load, key_right, base_a, length_a, 0, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(k >= 0); base_a = base_a + k; @@ -874,6 +875,7 @@ module array { length_b = CallGallopLeft( context, sortState, Load, key_left, base_b, length_b, length_b - 1, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(length_b >= 0); if (length_b == 0) return kSuccess; @@ -893,6 +895,12 @@ module array { } } + macro LoadElementsOrTempArray( + useTempArray: Boolean, sortState: FixedArray): HeapObject { + return useTempArray == True ? GetTempArray(sortState) : + ReloadElements(sortState); + } + // Locates the proper position of key in a sorted array; if the array contains // an element equal to key, return the position immediately to the left of // the leftmost equal element. (GallopRight does the same except returns the @@ -916,25 +924,17 @@ module array { assert(length > 0 && base >= 0); assert(0 <= hint && hint < length); - // We cannot leave a pointer to elements on the stack (see comment at - // ReloadElements). For this reason we pass a flag whether to reload - // and which array to use. - let elements: HeapObject = useTempArray == True ? GetTempArray(sortState) : - ReloadElements(sortState); - let last_ofs: Smi = 0; let offset: Smi = 1; try { - const base_hint_element: Object = - CallLoad(context, sortState, Load, elements, base + hint) + const base_hint_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + hint) otherwise Bailout; let order: Number = CallCompareFn(context, sortState, base_hint_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { // a[base + hint] < key: gallop right, until @@ -943,14 +943,13 @@ module array { // a[base + length - 1] is highest. let max_ofs: Smi = length - hint; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint + offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint + offset) otherwise Bailout; order = CallCompareFn(context, sortState, offset_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } // a[base + hint + offset] >= key? Break. if (order >= 0) break; @@ -975,14 +974,13 @@ module array { // a[base + hint] is lowest. let max_ofs: Smi = hint + 1; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint - offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint - offset) otherwise Bailout; order = CallCompareFn(context, sortState, offset_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) break; @@ -1011,14 +1009,12 @@ module array { while (last_ofs < offset) { const m: Smi = last_ofs + ((offset - last_ofs) >>> 1); - const base_m_element: Object = - CallLoad(context, sortState, Load, elements, base + m) + const base_m_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + m) otherwise Bailout; order = CallCompareFn(context, sortState, base_m_element, key) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { last_ofs = m + 1; // a[base + m] < key. @@ -1051,25 +1047,17 @@ module array { assert(length > 0 && base >= 0); assert(0 <= hint && hint < length); - // We cannot leave a pointer to elements on the stack (see comment at - // ReloadElements). For this reason we pass a flag whether to reload - // and which array to use. - let elements: HeapObject = useTempArray == True ? GetTempArray(sortState) : - ReloadElements(sortState); - let last_ofs: Smi = 0; let offset: Smi = 1; try { - const base_hint_element: Object = - CallLoad(context, sortState, Load, elements, base + hint) + const base_hint_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + hint) otherwise Bailout; let order: Number = CallCompareFn(context, sortState, key, base_hint_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { // key < a[base + hint]: gallop left, until @@ -1078,14 +1066,13 @@ module array { // a[base + hint] is lowest. let max_ofs: Smi = hint + 1; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint - offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint - offset) otherwise Bailout; order = CallCompareFn(context, sortState, key, offset_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order >= 0) break; @@ -1109,14 +1096,13 @@ module array { // a[base + length - 1] is highest. let max_ofs: Smi = length - hint; while (offset < max_ofs) { - const offset_element: Object = - CallLoad(context, sortState, Load, elements, base + hint + offset) + const offset_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), + base + hint + offset) otherwise Bailout; order = CallCompareFn(context, sortState, key, offset_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } // a[base + hint + ofs] <= key. if (order < 0) break; @@ -1144,14 +1130,12 @@ module array { while (last_ofs < offset) { const m: Smi = last_ofs + ((offset - last_ofs) >>> 1); - const base_m_element: Object = - CallLoad(context, sortState, Load, elements, base + m) + const base_m_element: Object = CallLoad( + context, sortState, Load, + LoadElementsOrTempArray(useTempArray, sortState), base + m) otherwise Bailout; order = CallCompareFn(context, sortState, key, base_m_element) otherwise Bailout; - if (useTempArray == False) { - elements = ReloadElements(sortState); - } if (order < 0) { offset = m; // key < a[base + m]. @@ -1288,6 +1272,7 @@ module array { nof_wins_a = CallGallopRight( context, sortState, Load, key_right, cursor_temp, length_a, 0, True) otherwise Bailout; + elements = ReloadElements(sortState); assert(nof_wins_a >= 0); if (nof_wins_a > 0) { @@ -1313,6 +1298,7 @@ module array { context, sortState, LoadF, temp_array[cursor_temp], cursor_b, length_b, 0, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(nof_wins_b >= 0); if (nof_wins_b > 0) { CallCopyWithinSortArray( @@ -1461,6 +1447,7 @@ module array { context, sortState, LoadF, temp_array[cursor_temp], baseA, length_a, length_a - 1, False) otherwise Bailout; + elements = ReloadElements(sortState); assert(k >= 0); nof_wins_a = length_a - k; @@ -1487,6 +1474,7 @@ module array { k = CallGallopLeft( context, sortState, Load, key, 0, length_b, length_b - 1, True) otherwise Bailout; + elements = ReloadElements(sortState); assert(k >= 0); nof_wins_b = length_b - k; @@ -1743,8 +1731,7 @@ module array { // 2. Let obj be ? ToObject(this value). const obj: JSReceiver = ToObject(context, receiver); - const sort_state: FixedArray = - AllocateZeroedFixedArray(kSortStateSize); + const sort_state: FixedArray = AllocateZeroedFixedArray(kSortStateSize); FillFixedArrayWithSmiZero(sort_state, SmiTag(kSortStateSize)); sort_state[kReceiverIdx] = obj; From 6b7e69875d4b9e9db354813ccddcb924543d1e36 Mon Sep 17 00:00:00 2001 From: Dmitry Igrishin Date: Sun, 11 Nov 2018 13:55:43 +0300 Subject: [PATCH 189/249] doc: add links to Stream section PR-URL: https://github.com/nodejs/node/pull/24301 Reviewed-By: Vse Mozhet Byt Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig --- doc/api/http.md | 1 + doc/api/http2.md | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/api/http.md b/doc/api/http.md index 4f526b36aaea8e..442cfc22ded97c 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -2112,3 +2112,4 @@ not abort the request or do anything besides add a `'timeout'` event. [`socket.unref()`]: net.html#net_socket_unref [`url.parse()`]: url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost [Readable Stream]: stream.html#stream_class_stream_readable +[Stream]: stream.html#stream_stream diff --git a/doc/api/http2.md b/doc/api/http2.md index 2cd39437362326..25fc0972244a98 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -3402,6 +3402,7 @@ following additional properties: [HTTPS]: https.html [Performance Observer]: perf_hooks.html [Readable Stream]: stream.html#stream_class_stream_readable +[Stream]: stream.html#stream_stream [RFC 7838]: https://tools.ietf.org/html/rfc7838 [RFC 8336]: https://tools.ietf.org/html/rfc8336 [RFC 8441]: https://tools.ietf.org/html/rfc8441 From 9e891327b7e2220e5a8b575930b9de11ea95d9d2 Mon Sep 17 00:00:00 2001 From: Morgan Roderick Date: Tue, 6 Nov 2018 16:52:42 +0000 Subject: [PATCH 190/249] console: cover .assert with single argument PR-URL: https://github.com/nodejs/node/pull/24188 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- test/parallel/test-console.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/parallel/test-console.js b/test/parallel/test-console.js index 5ecc0bd834bde4..1a914b78f936af 100644 --- a/test/parallel/test-console.js +++ b/test/parallel/test-console.js @@ -180,6 +180,8 @@ assert.strictEqual(errStrings[errStrings.length - 1], console.assert(true, 'this should not throw'); +console.assert(true); + assert.strictEqual(strings.length, process.stdout.writeTimes); assert.strictEqual(errStrings.length, process.stderr.writeTimes); restoreStdout(); From c68b0ae46ead8e1eeb25cb4ee8193a0859b13885 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Thu, 8 Nov 2018 11:45:33 +1100 Subject: [PATCH 191/249] doc: update fs.open() changes record for optional 'flags' Was missed on original PR. Ref: https://github.com/nodejs/node/pull/23767 PR-URL: https://github.com/nodejs/node/pull/24240 Refs: https://github.com/nodejs/node/pull/23767 Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- doc/api/fs.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/api/fs.md b/doc/api/fs.md index 9de798c6ff7ca2..240ba585671619 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -2313,6 +2313,9 @@ object with an `encoding` property specifying the character encoding to use. * `path` {string|Buffer|URL} * `flags` {string|number} See [support of file system `flags`][]. + **Default:** `'r'`. * `mode` {integer} **Default:** `0o666` (readable and writable) * Returns: {Promise} From 75e4f7db40cca4fab55786ca0b276441feae1abd Mon Sep 17 00:00:00 2001 From: Martin Kask Date: Tue, 6 Nov 2018 16:59:38 +0200 Subject: [PATCH 192/249] test: fix strictEqual argument order Fix the order of assert.strictEqual() arguments. It should have first argument as the calculated/tested value. PR-URL: https://github.com/nodejs/node/pull/24153 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- test/parallel/test-buffer-slice.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-buffer-slice.js b/test/parallel/test-buffer-slice.js index 6175370a9bccee..f40a495b206079 100644 --- a/test/parallel/test-buffer-slice.js +++ b/test/parallel/test-buffer-slice.js @@ -24,8 +24,8 @@ require('../common'); const assert = require('assert'); -assert.strictEqual(0, Buffer.from('hello', 'utf8').slice(0, 0).length); -assert.strictEqual(0, Buffer('hello', 'utf8').slice(0, 0).length); +assert.strictEqual(Buffer.from('hello', 'utf8').slice(0, 0).length, 0); +assert.strictEqual(Buffer('hello', 'utf8').slice(0, 0).length, 0); const buf = Buffer.from('0123456789', 'utf8'); const expectedSameBufs = [ @@ -72,7 +72,7 @@ for (let i = 0, s = buf.toString(); i < buf.length; ++i) { } expectedSameBufs.forEach(([buf1, buf2]) => { - assert.strictEqual(0, Buffer.compare(buf1, buf2)); + assert.strictEqual(Buffer.compare(buf1, buf2), 0); }); const utf16Buf = Buffer.from('0123456789', 'utf16le'); @@ -83,12 +83,12 @@ assert.strictEqual(Buffer.alloc(0).slice(0, 1).length, 0); { // Single argument slice - assert.strictEqual('bcde', - Buffer.from('abcde', 'utf8').slice(1).toString('utf8')); + assert.strictEqual(Buffer.from('abcde', 'utf8').slice(1).toString('utf8'), + 'bcde'); } // slice(0,0).length === 0 -assert.strictEqual(0, Buffer.from('hello', 'utf8').slice(0, 0).length); +assert.strictEqual(Buffer.from('hello', 'utf8').slice(0, 0).length, 0); { // Regression tests for https://github.com/nodejs/node/issues/9096 From f805db362055e03c2b1fd2574b6dd707edfecd59 Mon Sep 17 00:00:00 2001 From: Alessandro Gatti Date: Tue, 6 Nov 2018 17:16:52 +0100 Subject: [PATCH 193/249] test: check control characters replacing Add test that creates an error with a control character in the message. PR-URL: https://github.com/nodejs/node/pull/24182 Reviewed-By: Ruben Bridgewater Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- test/parallel/test-assert.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index e5a7d1aaaa90d8..695d890f4c5f6f 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -862,6 +862,14 @@ common.expectsError( }); { + + assert.throws(() => { + assert.ok((() => Boolean('' === false))()); + }, { + message: 'The expression evaluated to a falsy value:\n\n' + + " assert.ok((() => Boolean('\\u0001' === false))())\n" + }); + const errFn = () => { const err = new TypeError('Wrong value'); err.code = 404; From 02e9fa01f371339ce81687e79cb49275c8c3a470 Mon Sep 17 00:00:00 2001 From: Vladyslav Kopylash Date: Tue, 6 Nov 2018 16:59:46 +0000 Subject: [PATCH 194/249] test: fix args order in process-getactiverequests PR-URL: https://github.com/nodejs/node/pull/24186 Reviewed-By: Ruben Bridgewater Reviewed-By: Gireesh Punathil Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- test/parallel/test-process-getactiverequests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-process-getactiverequests.js b/test/parallel/test-process-getactiverequests.js index f55f298298d446..41883d35aa7dbc 100644 --- a/test/parallel/test-process-getactiverequests.js +++ b/test/parallel/test-process-getactiverequests.js @@ -7,4 +7,4 @@ const fs = require('fs'); for (let i = 0; i < 12; i++) fs.open(__filename, 'r', () => {}); -assert.strictEqual(12, process._getActiveRequests().length); +assert.strictEqual(process._getActiveRequests().length, 12); From fe7ef1ad11b10ebb35f1b796c80ddc2a7abdfb76 Mon Sep 17 00:00:00 2001 From: Daijiro Wachi Date: Tue, 6 Nov 2018 20:42:37 +0900 Subject: [PATCH 195/249] test: add test for autoDestroy in stream PR-URL: https://github.com/nodejs/node/pull/24127 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Mathias Buus --- test/parallel/test-stream-auto-destroy.js | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/parallel/test-stream-auto-destroy.js b/test/parallel/test-stream-auto-destroy.js index 7bce8a56368313..2a1a5190debb57 100644 --- a/test/parallel/test-stream-auto-destroy.js +++ b/test/parallel/test-stream-auto-destroy.js @@ -82,3 +82,31 @@ const assert = require('assert'); assert(finished); })); } + +{ + const r = new stream.Readable({ + read() { + r2.emit('error', new Error('fail')); + } + }); + const r2 = new stream.Readable({ + autoDestroy: true, + destroy: common.mustCall((err, cb) => cb()) + }); + + r.pipe(r2); +} + +{ + const r = new stream.Readable({ + read() { + w.emit('error', new Error('fail')); + } + }); + const w = new stream.Writable({ + autoDestroy: true, + destroy: common.mustCall((err, cb) => cb()) + }); + + r.pipe(w); +} From a39493f4aa003b4fcc6f401e8ef2ae95ff8eb9eb Mon Sep 17 00:00:00 2001 From: Peter Marshall Date: Fri, 9 Nov 2018 13:06:07 +0100 Subject: [PATCH 196/249] deps: cherry-pick b87d408 from upstream V8 Original commit message: [heap-profiler] Fix a use-after-free when snapshots are deleted If a caller starts the sampling heap profiler and takes a snapshot, and then deletes the snapshot before the sampling has completed, a use-after-free will occur on the StringsStorage pointer. The same issue applies for StartTrackingHeapObjects which shares the same StringsStorage object. Bug: v8:8373 Change-Id: I5d69d60d3f9465f9dd3b3bef107c204e0fda0643 Reviewed-on: https://chromium-review.googlesource.com/c/1301477 Commit-Queue: Peter Marshall Reviewed-by: Alexei Filippov Cr-Commit-Position: refs/heads/master@{#57114} PR-URL: https://github.com/nodejs/node/pull/24272 Refs: https://github.com/v8/v8/commit/b87d408f65b9ab49a4d199e850d2358995deaeb2 Reviewed-By: Colin Ihrig Reviewed-By: Daniel Bevenius --- common.gypi | 2 +- deps/v8/src/profiler/heap-profiler.cc | 9 ++++- deps/v8/src/profiler/heap-profiler.h | 2 ++ deps/v8/test/cctest/test-heap-profiler.cc | 42 +++++++++++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/common.gypi b/common.gypi index fde75cb2b512ad..445a70daed146c 100644 --- a/common.gypi +++ b/common.gypi @@ -30,7 +30,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.10', + 'v8_embedder_string': '-node.11', # Enable disassembler for `--print-code` v8 options 'v8_enable_disassembler': 1, diff --git a/deps/v8/src/profiler/heap-profiler.cc b/deps/v8/src/profiler/heap-profiler.cc index 71e297c4bf1501..3a1df29bd47b54 100644 --- a/deps/v8/src/profiler/heap-profiler.cc +++ b/deps/v8/src/profiler/heap-profiler.cc @@ -23,9 +23,14 @@ HeapProfiler::~HeapProfiler() = default; void HeapProfiler::DeleteAllSnapshots() { snapshots_.clear(); - names_.reset(new StringsStorage()); + MaybeClearStringsStorage(); } +void HeapProfiler::MaybeClearStringsStorage() { + if (snapshots_.empty() && !sampling_heap_profiler_ && !allocation_tracker_) { + names_.reset(new StringsStorage()); + } +} void HeapProfiler::RemoveSnapshot(HeapSnapshot* snapshot) { snapshots_.erase( @@ -126,6 +131,7 @@ bool HeapProfiler::StartSamplingHeapProfiler( void HeapProfiler::StopSamplingHeapProfiler() { sampling_heap_profiler_.reset(); + MaybeClearStringsStorage(); } @@ -159,6 +165,7 @@ void HeapProfiler::StopHeapObjectsTracking() { ids_->StopHeapObjectsTracking(); if (allocation_tracker_) { allocation_tracker_.reset(); + MaybeClearStringsStorage(); heap()->RemoveHeapObjectAllocationTracker(this); } } diff --git a/deps/v8/src/profiler/heap-profiler.h b/deps/v8/src/profiler/heap-profiler.h index 8ce379d59df6ca..099c0e24fad7d8 100644 --- a/deps/v8/src/profiler/heap-profiler.h +++ b/deps/v8/src/profiler/heap-profiler.h @@ -92,6 +92,8 @@ class HeapProfiler : public HeapObjectAllocationTracker { v8::PersistentValueVector* objects); private: + void MaybeClearStringsStorage(); + Heap* heap() const; // Mapping from HeapObject addresses to objects' uids. diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index 5d8094d6351f6b..e4e5f4c8dc0845 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -3900,3 +3900,45 @@ TEST(WeakReference) { const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); CHECK(ValidateSnapshot(snapshot)); } + +TEST(Bug8373_1) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + heap_profiler->StartSamplingHeapProfiler(100); + + heap_profiler->TakeHeapSnapshot(); + // Causes the StringsStorage to be deleted. + heap_profiler->DeleteAllHeapSnapshots(); + + // Triggers an allocation sample that tries to use the StringsStorage. + for (int i = 0; i < 2 * 1024; ++i) { + CompileRun( + "new Array(64);" + "new Uint8Array(16);"); + } + + heap_profiler->StopSamplingHeapProfiler(); +} + +TEST(Bug8373_2) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + + heap_profiler->StartTrackingHeapObjects(true); + + heap_profiler->TakeHeapSnapshot(); + // Causes the StringsStorage to be deleted. + heap_profiler->DeleteAllHeapSnapshots(); + + // Triggers an allocations that try to use the StringsStorage. + for (int i = 0; i < 2 * 1024; ++i) { + CompileRun( + "new Array(64);" + "new Uint8Array(16);"); + } + + heap_profiler->StopTrackingHeapObjects(); +} From 1c8b4d7c89f41b6781dc4b5a73ba38a7f34bc696 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Fri, 9 Nov 2018 11:55:37 +0100 Subject: [PATCH 197/249] build: disable openssl asm on arm64 for now There is reason to believe the generated assembly isn't working correctly so let's disable it for now pending further investigation. PR-URL: https://github.com/nodejs/node/pull/24270 Refs: https://github.com/nodejs/node/issues/23913 Reviewed-By: Daniel Bevenius Reviewed-By: Refael Ackermann Reviewed-By: James M Snell --- common.gypi | 6 ++++++ configure.py | 4 +++- deps/openssl/openssl.gyp | 3 --- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/common.gypi b/common.gypi index 445a70daed146c..4b732704ba2618 100644 --- a/common.gypi +++ b/common.gypi @@ -50,6 +50,12 @@ 'icu_use_data_file_flag%': 0, 'conditions': [ + ['target_arch=="arm64"', { + # Disabled pending https://github.com/nodejs/node/issues/23913. + 'openssl_no_asm%': 1, + }, { + 'openssl_no_asm%': 0, + }], ['GENERATOR=="ninja"', { 'obj_dir': '<(PRODUCT_DIR)/obj', 'conditions': [ diff --git a/configure.py b/configure.py index 0df8e12bf3a3c3..065e31fd9cac51 100755 --- a/configure.py +++ b/configure.py @@ -1183,9 +1183,11 @@ def configure_openssl(o): variables = o['variables'] variables['node_use_openssl'] = b(not options.without_ssl) variables['node_shared_openssl'] = b(options.shared_openssl) - variables['openssl_no_asm'] = 1 if options.openssl_no_asm else 0 variables['openssl_fips'] = '' + if options.openssl_no_asm: + variables['openssl_no_asm'] = 1 + if options.without_ssl: def without_ssl_error(option): error('--without-ssl is incompatible with %s' % option) diff --git a/deps/openssl/openssl.gyp b/deps/openssl/openssl.gyp index 6b0770ebbc1b0e..4a6b55686679d4 100644 --- a/deps/openssl/openssl.gyp +++ b/deps/openssl/openssl.gyp @@ -1,7 +1,4 @@ { - 'variables': { - 'openssl_no_asm%': 0, - }, 'targets': [ { 'target_name': 'openssl', From 0a104ef33cf4ddfaf20dd18adf81d446e6891fd5 Mon Sep 17 00:00:00 2001 From: Petar Dodev Date: Tue, 6 Nov 2018 18:36:17 +0300 Subject: [PATCH 198/249] test: test add and remove for lib/domain Testing some of the more specific cases of using domain.add and domain.remove. For example, calling domain.add twice with same event emmiter and actually removing an event emitter from the domain. PR-URL: https://github.com/nodejs/node/pull/24163 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater --- test/parallel/test-domain-add-remove.js | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 test/parallel/test-domain-add-remove.js diff --git a/test/parallel/test-domain-add-remove.js b/test/parallel/test-domain-add-remove.js new file mode 100644 index 00000000000000..8e1d082125cb0b --- /dev/null +++ b/test/parallel/test-domain-add-remove.js @@ -0,0 +1,26 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const domain = require('domain'); +const EventEmitter = require('events'); + +const d = new domain.Domain(); +const e = new EventEmitter(); +const e2 = new EventEmitter(); + +d.add(e); +assert.strictEqual(e.domain, d); + +// Adding the same event to a domain should not change the member count +let previousMemberCount = d.members.length; +d.add(e); +assert.strictEqual(previousMemberCount, d.members.length); + +d.add(e2); +assert.strictEqual(e2.domain, d); + +previousMemberCount = d.members.length; +d.remove(e2); +assert.notStrictEqual(e2.domain, d); +assert.strictEqual(previousMemberCount - 1, d.members.length); From 366529654efaa023e39d1a986e3282629f2719d8 Mon Sep 17 00:00:00 2001 From: Osmond van Hemert Date: Thu, 8 Nov 2018 21:21:13 +0100 Subject: [PATCH 199/249] test: url format path ending hashchar not covered PR-URL: https://github.com/nodejs/node/pull/24259 Reviewed-By: Weijia Wang Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- test/parallel/test-url-format.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/parallel/test-url-format.js b/test/parallel/test-url-format.js index 1f62792dfbcd78..571895832a3ffb 100644 --- a/test/parallel/test-url-format.js +++ b/test/parallel/test-url-format.js @@ -173,6 +173,16 @@ const formatTests = { hash: '#bar' }, + // `#` in path end + `#` in query + '/path/to/%%23?foo=the%231#bar': { + href: '/path/to/%%23?foo=the%231#bar', + pathname: '/path/to/%#', + query: { + foo: 'the#1' + }, + hash: '#bar' + }, + // `?` and `#` in path and search 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag': { href: 'http://ex.com/foo%3F100%m%23r?abc=the%231?&foo=bar#frag', From d8d93442aa96504e9f401a7ead8bf6c6022904c9 Mon Sep 17 00:00:00 2001 From: msmichellegar Date: Tue, 6 Nov 2018 14:38:37 +0000 Subject: [PATCH 200/249] lib: adjust params from uvExceptionWithHostPort PR-URL: https://github.com/nodejs/node/pull/24159 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater --- lib/internal/errors.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 044303be5a560d..5fec67d6c721af 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -294,10 +294,9 @@ function uvException(ctx) { * @param {string} syscall * @param {string} address * @param {number} [port] - * @param {string} [additional] * @returns {Error} */ -function uvExceptionWithHostPort(err, syscall, address, port, additional) { +function uvExceptionWithHostPort(err, syscall, address, port) { const [ code, uvmsg ] = errmap.get(err); const message = `${syscall} ${code}: ${uvmsg}`; let details = ''; @@ -307,9 +306,6 @@ function uvExceptionWithHostPort(err, syscall, address, port, additional) { } else if (address) { details = ` ${address}`; } - if (additional) { - details += ` - Local (${additional})`; - } // eslint-disable-next-line no-restricted-syntax const ex = new Error(`${message}${details}`); From 44ebdbb860a75f303f80c16b132d404743d43039 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 11 Nov 2018 09:02:48 -0800 Subject: [PATCH 201/249] build: fix benchmark tests on CI PR-URL: https://github.com/nodejs/node/pull/24307 Refs: https://github.com/nodejs/build/issues/1568#issuecomment-437681599 Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2c6efa7b9afb44..7c2afde30a3d28 100644 --- a/Makefile +++ b/Makefile @@ -455,7 +455,7 @@ test-ci-js: | clear-stalled .PHONY: test-ci # Related CI jobs: most CI tests, excluding node-test-commit-arm-fanned test-ci: LOGLEVEL := info -test-ci: | clear-stalled build-addons build-addons-napi doc-only +test-ci: | clear-stalled build-addons build-addons-napi doc-only bench-addons-build out/Release/cctest --gtest_output=tap:cctest.tap $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ --mode=$(BUILDTYPE_LOWER) --flaky-tests=$(FLAKY_TESTS) \ From e5e9c6427b449bc6e4c2321dccf30526a6b59b3b Mon Sep 17 00:00:00 2001 From: Robert Pamely Date: Tue, 6 Nov 2018 16:01:19 +0000 Subject: [PATCH 202/249] test: dgram socket prints deprecation warnings Adds tests assert the deprecated properties and methods in the dgram socket warn. It runs each test in a separate child process since each deprecation will only warn once. PR-URL: https://github.com/nodejs/node/pull/24177 Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- test/parallel/test-dgram-deprecation-error.js | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 test/parallel/test-dgram-deprecation-error.js diff --git a/test/parallel/test-dgram-deprecation-error.js b/test/parallel/test-dgram-deprecation-error.js new file mode 100644 index 00000000000000..89cde12fd37cf1 --- /dev/null +++ b/test/parallel/test-dgram-deprecation-error.js @@ -0,0 +1,84 @@ +'use strict'; + +const assert = require('assert'); +const common = require('../common'); +const dgram = require('dgram'); +const fork = require('child_process').fork; + +const sock = dgram.createSocket('udp4'); + +const testNumber = parseInt(process.argv[2], 10); + +const propertiesToTest = [ + '_handle', + '_receiving', + '_bindState', + '_queue', + '_reuseAddr' +]; + +const methodsToTest = [ + '_healthCheck', + '_stopReceiving' +]; + +const propertyCases = propertiesToTest.map((propName) => { + return [ + () => { + // Test property getter + common.expectWarning( + 'DeprecationWarning', + `Socket.prototype.${propName} is deprecated`, + 'DEP0112' + ); + sock[propName]; + }, + () => { + // Test property setter + common.expectWarning( + 'DeprecationWarning', + `Socket.prototype.${propName} is deprecated`, + 'DEP0112' + ); + sock[propName] = null; + } + ]; +}); + +const methodCases = methodsToTest.map((propName) => { + return () => { + common.expectWarning( + 'DeprecationWarning', + `Socket.prototype.${propName}() is deprecated`, + 'DEP0112' + ); + sock[propName](); + }; +}); + +const cases = [].concat( + ...propertyCases, + ...methodCases +); + +// If we weren't passed a test ID then we need to spawn all of the cases. +// We run the cases in child processes since deprecations print once. +if (Number.isNaN(testNumber)) { + const children = cases.map((_case, i) => + fork(process.argv[1], [ String(i) ])); + + children.forEach((child) => { + child.on('close', (code) => { + // Pass on child exit code + if (code > 0) { + process.exit(code); + } + }); + }); + + return; +} + +// We were passed a test ID - run the test case +assert.ok(cases[testNumber]); +cases[testNumber](); From 77163a9dee8418e843483829be686f6c048f0026 Mon Sep 17 00:00:00 2001 From: Lauri Piisang Date: Tue, 6 Nov 2018 15:29:11 +0000 Subject: [PATCH 203/249] test: add else and error case for TextDecoder add test for tinyurl.com/codeandlearn-encoding-1 add test for tinyurl.com/codeandlearn-encoding-2 PR-URL: https://github.com/nodejs/node/pull/24162 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater --- .../test-whatwg-encoding-textdecoder-fatal.js | 12 ++++++++++++ test/parallel/test-whatwg-encoding-textdecoder.js | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/test/parallel/test-whatwg-encoding-textdecoder-fatal.js b/test/parallel/test-whatwg-encoding-textdecoder-fatal.js index be37f5097c504e..aa945b61b10e72 100644 --- a/test/parallel/test-whatwg-encoding-textdecoder-fatal.js +++ b/test/parallel/test-whatwg-encoding-textdecoder-fatal.js @@ -88,3 +88,15 @@ bad.forEach((t) => { assert(!new TextDecoder().fatal); assert(new TextDecoder('utf-8', { fatal: true }).fatal); } + +{ + const notArrayBufferViewExamples = [false, {}, 1, '', new Error()]; + notArrayBufferViewExamples.forEach((invalidInputType) => { + common.expectsError(() => { + new TextDecoder(undefined, null).decode(invalidInputType); + }, { + code: 'ERR_INVALID_ARG_TYPE', + type: TypeError + }); + }); +} diff --git a/test/parallel/test-whatwg-encoding-textdecoder.js b/test/parallel/test-whatwg-encoding-textdecoder.js index 37fbe12757134e..6d1db2ec33faad 100644 --- a/test/parallel/test-whatwg-encoding-textdecoder.js +++ b/test/parallel/test-whatwg-encoding-textdecoder.js @@ -75,6 +75,14 @@ if (common.hasIntl) { }); } +// Test TextDecoder, label undefined, options null +{ + const dec = new TextDecoder(undefined, null); + assert.strictEqual(dec.encoding, 'utf-8'); + assert.strictEqual(dec.fatal, false); + assert.strictEqual(dec.ignoreBOM, false); +} + // Test TextDecoder, UTF-16le { const dec = new TextDecoder('utf-16le'); From 1a864999479f7412067769dd0e9dd50858348c35 Mon Sep 17 00:00:00 2001 From: kiyomizumia Date: Tue, 6 Nov 2018 16:21:23 +0000 Subject: [PATCH 204/249] test: fixed order of actual and expected arguments PR-URL: https://github.com/nodejs/node/pull/24178 Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater --- test/parallel/test-event-emitter-modify-in-emit.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-event-emitter-modify-in-emit.js b/test/parallel/test-event-emitter-modify-in-emit.js index 9c28fecbdd8c4c..995fa01d11a1a8 100644 --- a/test/parallel/test-event-emitter-modify-in-emit.js +++ b/test/parallel/test-event-emitter-modify-in-emit.js @@ -74,7 +74,7 @@ callbacks_called = []; e.on('foo', callback2); e.on('foo', callback3); -assert.strictEqual(2, e.listeners('foo').length); +assert.strictEqual(e.listeners('foo').length, 2); e.emit('foo'); assert.deepStrictEqual(['callback2', 'callback3'], callbacks_called); -assert.strictEqual(0, e.listeners('foo').length); +assert.strictEqual(e.listeners('foo').length, 0); From cb4c2dd33e7c7c1735ea3806af13a39ebe9ed8a8 Mon Sep 17 00:00:00 2001 From: Fran Herrero Date: Tue, 6 Nov 2018 16:36:32 +0000 Subject: [PATCH 205/249] test: esm loader unknown builtin module PR-URL: https://github.com/nodejs/node/pull/24183 Reviewed-By: James M Snell Reviewed-By: Gus Caplan Reviewed-By: Ruben Bridgewater --- .../loader-unknown-builtin-module.mjs | 6 ++++++ .../parallel/test-loaders-unknown-builtin-module.mjs | 12 ++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs create mode 100644 test/parallel/test-loaders-unknown-builtin-module.mjs diff --git a/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs new file mode 100644 index 00000000000000..e7c6c8ff345617 --- /dev/null +++ b/test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs @@ -0,0 +1,6 @@ +export async function resolve(specifier, parent, defaultResolve) { + if (specifier === 'unknown-builtin-module') { + return { url: 'unknown-builtin-module', format: 'builtin' }; + } + return defaultResolve(specifier, parent); +} \ No newline at end of file diff --git a/test/parallel/test-loaders-unknown-builtin-module.mjs b/test/parallel/test-loaders-unknown-builtin-module.mjs new file mode 100644 index 00000000000000..db3cfa3582e9e2 --- /dev/null +++ b/test/parallel/test-loaders-unknown-builtin-module.mjs @@ -0,0 +1,12 @@ +// Flags: --experimental-modules --loader ./test/fixtures/es-module-loaders/loader-unknown-builtin-module.mjs +import { expectsError, mustCall } from '../common'; +import assert from 'assert'; + +const unknownBuiltinModule = 'unknown-builtin-module'; + +import(unknownBuiltinModule) +.then(assert.fail, expectsError({ + code: 'ERR_UNKNOWN_BUILTIN_MODULE', + message: `No such built-in module: ${unknownBuiltinModule}` +})) +.then(mustCall()); From ad72e40e5b6c037b7e810f32f71213ddc1a1632c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 9 Nov 2018 14:00:16 -0500 Subject: [PATCH 206/249] tools: update ESLint to 5.9.0 Update ESLint to 5.9.0. PR-URL: https://github.com/nodejs/node/pull/24280 Reviewed-By: Rich Trott Reviewed-By: Ruben Bridgewater --- tools/node_modules/eslint/lib/cli-engine.js | 159 ++++++++-- tools/node_modules/eslint/lib/cli.js | 7 +- tools/node_modules/eslint/lib/options.js | 5 + .../eslint/lib/rules/accessor-pairs.js | 4 + .../eslint/lib/rules/array-bracket-newline.js | 5 + .../eslint/lib/rules/array-bracket-spacing.js | 5 + .../eslint/lib/rules/array-callback-return.js | 2 + .../eslint/lib/rules/array-element-newline.js | 4 + .../eslint/lib/rules/arrow-body-style.js | 2 + .../eslint/lib/rules/arrow-parens.js | 2 + .../eslint/lib/rules/arrow-spacing.js | 2 + .../eslint/lib/rules/block-scoped-var.js | 2 + .../eslint/lib/rules/block-spacing.js | 2 + .../eslint/lib/rules/brace-style.js | 2 + .../eslint/lib/rules/callback-return.js | 2 + .../eslint/lib/rules/camelcase.js | 2 + .../eslint/lib/rules/capitalized-comments.js | 4 + .../lib/rules/class-methods-use-this.js | 3 + .../eslint/lib/rules/comma-dangle.js | 4 + .../eslint/lib/rules/comma-spacing.js | 2 + .../eslint/lib/rules/comma-style.js | 5 + .../eslint/lib/rules/complexity.js | 2 + .../lib/rules/computed-property-spacing.js | 2 + .../eslint/lib/rules/consistent-return.js | 2 + .../eslint/lib/rules/consistent-this.js | 2 + .../eslint/lib/rules/constructor-super.js | 2 + tools/node_modules/eslint/lib/rules/curly.js | 2 + .../eslint/lib/rules/default-case.js | 2 + .../eslint/lib/rules/dot-location.js | 2 + .../eslint/lib/rules/dot-notation.js | 2 + .../node_modules/eslint/lib/rules/eol-last.js | 5 + tools/node_modules/eslint/lib/rules/eqeqeq.js | 2 + .../eslint/lib/rules/for-direction.js | 4 + .../eslint/lib/rules/func-call-spacing.js | 4 + .../eslint/lib/rules/func-name-matching.js | 3 + .../eslint/lib/rules/func-names.js | 3 + .../eslint/lib/rules/func-style.js | 3 + .../lib/rules/function-paren-newline.js | 5 + .../lib/rules/generator-star-spacing.js | 3 + .../eslint/lib/rules/getter-return.js | 5 + .../eslint/lib/rules/global-require.js | 2 + .../eslint/lib/rules/guard-for-in.js | 2 + .../eslint/lib/rules/handle-callback-err.js | 2 + .../eslint/lib/rules/id-blacklist.js | 2 + .../eslint/lib/rules/id-length.js | 2 + .../node_modules/eslint/lib/rules/id-match.js | 128 ++++++-- .../lib/rules/implicit-arrow-linebreak.js | 4 + .../eslint/lib/rules/indent-legacy.js | 5 +- tools/node_modules/eslint/lib/rules/indent.js | 2 + .../eslint/lib/rules/init-declarations.js | 2 + .../eslint/lib/rules/jsx-quotes.js | 2 + .../eslint/lib/rules/key-spacing.js | 7 +- .../eslint/lib/rules/keyword-spacing.js | 2 + .../eslint/lib/rules/line-comment-position.js | 2 + .../eslint/lib/rules/linebreak-style.js | 2 + .../eslint/lib/rules/lines-around-comment.js | 2 + .../lib/rules/lines-around-directive.js | 8 +- .../lib/rules/lines-between-class-members.js | 2 + .../eslint/lib/rules/max-classes-per-file.js | 4 + .../eslint/lib/rules/max-depth.js | 2 + .../node_modules/eslint/lib/rules/max-len.js | 2 + .../lib/rules/max-lines-per-function.js | 2 + .../eslint/lib/rules/max-lines.js | 2 + .../eslint/lib/rules/max-nested-callbacks.js | 2 + .../eslint/lib/rules/max-params.js | 2 + .../lib/rules/max-statements-per-line.js | 2 + .../eslint/lib/rules/max-statements.js | 2 + .../lib/rules/multiline-comment-style.js | 3 + .../eslint/lib/rules/multiline-ternary.js | 3 + .../node_modules/eslint/lib/rules/new-cap.js | 2 + .../eslint/lib/rules/new-parens.js | 3 +- .../eslint/lib/rules/newline-after-var.js | 7 +- .../eslint/lib/rules/newline-before-return.js | 7 +- .../lib/rules/newline-per-chained-call.js | 4 + .../node_modules/eslint/lib/rules/no-alert.js | 2 + .../eslint/lib/rules/no-array-constructor.js | 2 + .../lib/rules/no-async-promise-executor.js | 3 + .../eslint/lib/rules/no-await-in-loop.js | 4 + .../eslint/lib/rules/no-bitwise.js | 2 + .../eslint/lib/rules/no-buffer-constructor.js | 4 + .../eslint/lib/rules/no-caller.js | 2 + .../eslint/lib/rules/no-case-declarations.js | 2 + .../eslint/lib/rules/no-catch-shadow.js | 9 +- .../eslint/lib/rules/no-class-assign.js | 2 + .../eslint/lib/rules/no-compare-neg-zero.js | 4 + .../eslint/lib/rules/no-cond-assign.js | 2 + .../eslint/lib/rules/no-confusing-arrow.js | 2 + .../eslint/lib/rules/no-console.js | 2 + .../eslint/lib/rules/no-const-assign.js | 2 + .../eslint/lib/rules/no-constant-condition.js | 2 + .../eslint/lib/rules/no-continue.js | 2 + .../eslint/lib/rules/no-control-regex.js | 6 +- .../eslint/lib/rules/no-debugger.js | 4 + .../eslint/lib/rules/no-delete-var.js | 2 + .../eslint/lib/rules/no-div-regex.js | 2 + .../eslint/lib/rules/no-dupe-args.js | 2 + .../eslint/lib/rules/no-dupe-class-members.js | 2 + .../eslint/lib/rules/no-dupe-keys.js | 2 + .../eslint/lib/rules/no-duplicate-case.js | 2 + .../eslint/lib/rules/no-duplicate-imports.js | 2 + .../eslint/lib/rules/no-else-return.js | 2 + .../lib/rules/no-empty-character-class.js | 2 + .../eslint/lib/rules/no-empty-function.js | 2 + .../eslint/lib/rules/no-empty-pattern.js | 2 + .../node_modules/eslint/lib/rules/no-empty.js | 2 + .../eslint/lib/rules/no-eq-null.js | 2 + .../node_modules/eslint/lib/rules/no-eval.js | 2 + .../eslint/lib/rules/no-ex-assign.js | 2 + .../eslint/lib/rules/no-extend-native.js | 2 + .../eslint/lib/rules/no-extra-bind.js | 3 +- .../eslint/lib/rules/no-extra-boolean-cast.js | 3 +- .../eslint/lib/rules/no-extra-label.js | 3 +- .../eslint/lib/rules/no-extra-parens.js | 11 +- .../eslint/lib/rules/no-extra-semi.js | 2 + .../eslint/lib/rules/no-fallthrough.js | 2 + .../eslint/lib/rules/no-floating-decimal.js | 3 +- .../eslint/lib/rules/no-func-assign.js | 2 + .../eslint/lib/rules/no-global-assign.js | 2 + .../eslint/lib/rules/no-implicit-coercion.js | 3 + .../eslint/lib/rules/no-implicit-globals.js | 2 + .../eslint/lib/rules/no-implied-eval.js | 2 + .../eslint/lib/rules/no-inline-comments.js | 2 + .../eslint/lib/rules/no-inner-declarations.js | 2 + .../eslint/lib/rules/no-invalid-regexp.js | 2 + .../eslint/lib/rules/no-invalid-this.js | 2 + .../lib/rules/no-irregular-whitespace.js | 2 + .../eslint/lib/rules/no-iterator.js | 2 + .../eslint/lib/rules/no-label-var.js | 2 + .../eslint/lib/rules/no-labels.js | 2 + .../eslint/lib/rules/no-lone-blocks.js | 2 + .../eslint/lib/rules/no-lonely-if.js | 3 +- .../eslint/lib/rules/no-loop-func.js | 2 + .../eslint/lib/rules/no-magic-numbers.js | 3 + .../rules/no-misleading-character-class.js | 4 + .../eslint/lib/rules/no-mixed-operators.js | 3 + .../eslint/lib/rules/no-mixed-requires.js | 2 + .../lib/rules/no-mixed-spaces-and-tabs.js | 2 + .../eslint/lib/rules/no-multi-assign.js | 3 + .../eslint/lib/rules/no-multi-spaces.js | 2 + .../eslint/lib/rules/no-multi-str.js | 2 + .../lib/rules/no-multiple-empty-lines.js | 2 + .../eslint/lib/rules/no-native-reassign.js | 5 +- .../eslint/lib/rules/no-negated-condition.js | 2 + .../eslint/lib/rules/no-negated-in-lhs.js | 7 +- .../eslint/lib/rules/no-nested-ternary.js | 2 + .../eslint/lib/rules/no-new-func.js | 2 + .../eslint/lib/rules/no-new-object.js | 2 + .../eslint/lib/rules/no-new-require.js | 2 + .../eslint/lib/rules/no-new-symbol.js | 2 + .../eslint/lib/rules/no-new-wrappers.js | 2 + tools/node_modules/eslint/lib/rules/no-new.js | 2 + .../eslint/lib/rules/no-obj-calls.js | 2 + .../eslint/lib/rules/no-octal-escape.js | 2 + .../node_modules/eslint/lib/rules/no-octal.js | 2 + .../eslint/lib/rules/no-param-reassign.js | 2 + .../eslint/lib/rules/no-path-concat.js | 2 + .../eslint/lib/rules/no-plusplus.js | 2 + .../eslint/lib/rules/no-process-env.js | 2 + .../eslint/lib/rules/no-process-exit.js | 2 + .../node_modules/eslint/lib/rules/no-proto.js | 2 + .../eslint/lib/rules/no-prototype-builtins.js | 2 + .../eslint/lib/rules/no-redeclare.js | 2 + .../eslint/lib/rules/no-regex-spaces.js | 3 +- .../eslint/lib/rules/no-restricted-globals.js | 2 + .../eslint/lib/rules/no-restricted-imports.js | 62 ++-- .../eslint/lib/rules/no-restricted-modules.js | 2 + .../lib/rules/no-restricted-properties.js | 2 + .../eslint/lib/rules/no-restricted-syntax.js | 2 + .../eslint/lib/rules/no-return-assign.js | 2 + .../eslint/lib/rules/no-return-await.js | 4 + .../eslint/lib/rules/no-script-url.js | 2 + .../eslint/lib/rules/no-self-assign.js | 2 + .../eslint/lib/rules/no-self-compare.js | 2 + .../eslint/lib/rules/no-sequences.js | 2 + .../lib/rules/no-shadow-restricted-names.js | 2 + .../eslint/lib/rules/no-shadow.js | 2 + .../eslint/lib/rules/no-spaced-func.js | 5 +- .../eslint/lib/rules/no-sparse-arrays.js | 2 + .../node_modules/eslint/lib/rules/no-sync.js | 2 + .../node_modules/eslint/lib/rules/no-tabs.js | 2 + .../lib/rules/no-template-curly-in-string.js | 2 + .../eslint/lib/rules/no-ternary.js | 2 + .../eslint/lib/rules/no-this-before-super.js | 2 + .../eslint/lib/rules/no-throw-literal.js | 2 + .../eslint/lib/rules/no-trailing-spaces.js | 2 + .../eslint/lib/rules/no-undef-init.js | 3 +- .../node_modules/eslint/lib/rules/no-undef.js | 2 + .../eslint/lib/rules/no-undefined.js | 2 + .../eslint/lib/rules/no-underscore-dangle.js | 2 + .../lib/rules/no-unexpected-multiline.js | 2 + .../lib/rules/no-unmodified-loop-condition.js | 2 + .../eslint/lib/rules/no-unneeded-ternary.js | 2 + .../eslint/lib/rules/no-unreachable.js | 3 +- .../eslint/lib/rules/no-unsafe-finally.js | 2 + .../eslint/lib/rules/no-unsafe-negation.js | 3 + .../eslint/lib/rules/no-unused-expressions.js | 2 + .../eslint/lib/rules/no-unused-labels.js | 3 +- .../eslint/lib/rules/no-unused-vars.js | 48 ++- .../eslint/lib/rules/no-use-before-define.js | 2 + .../eslint/lib/rules/no-useless-call.js | 2 + .../lib/rules/no-useless-computed-key.js | 3 +- .../eslint/lib/rules/no-useless-concat.js | 2 + .../lib/rules/no-useless-constructor.js | 2 + .../eslint/lib/rules/no-useless-escape.js | 2 + .../eslint/lib/rules/no-useless-rename.js | 4 + .../eslint/lib/rules/no-useless-return.js | 3 + tools/node_modules/eslint/lib/rules/no-var.js | 2 + .../node_modules/eslint/lib/rules/no-void.js | 2 + .../eslint/lib/rules/no-warning-comments.js | 2 + .../rules/no-whitespace-before-property.js | 2 + .../node_modules/eslint/lib/rules/no-with.js | 2 + .../rules/nonblock-statement-body-position.js | 4 + .../eslint/lib/rules/object-curly-newline.js | 4 + .../eslint/lib/rules/object-curly-spacing.js | 2 + .../lib/rules/object-property-newline.js | 5 +- .../eslint/lib/rules/object-shorthand.js | 2 + .../lib/rules/one-var-declaration-per-line.js | 2 + .../node_modules/eslint/lib/rules/one-var.js | 2 + .../eslint/lib/rules/operator-assignment.js | 2 + .../eslint/lib/rules/operator-linebreak.js | 2 + .../eslint/lib/rules/padded-blocks.js | 2 + .../rules/padding-line-between-statements.js | 4 + .../eslint/lib/rules/prefer-arrow-callback.js | 2 + .../eslint/lib/rules/prefer-const.js | 60 +++- .../eslint/lib/rules/prefer-destructuring.js | 3 + .../lib/rules/prefer-numeric-literals.js | 3 +- .../eslint/lib/rules/prefer-object-spread.js | 4 + .../lib/rules/prefer-promise-reject-errors.js | 4 + .../eslint/lib/rules/prefer-reflect.js | 5 +- .../eslint/lib/rules/prefer-rest-params.js | 2 + .../eslint/lib/rules/prefer-spread.js | 3 +- .../eslint/lib/rules/prefer-template.js | 3 +- .../eslint/lib/rules/quote-props.js | 2 + tools/node_modules/eslint/lib/rules/quotes.js | 2 + tools/node_modules/eslint/lib/rules/radix.js | 2 + .../lib/rules/require-atomic-updates.js | 4 + .../eslint/lib/rules/require-await.js | 3 + .../eslint/lib/rules/require-jsdoc.js | 2 + .../lib/rules/require-unicode-regexp.js | 4 + .../eslint/lib/rules/require-yield.js | 2 + .../eslint/lib/rules/rest-spread-spacing.js | 4 + .../eslint/lib/rules/semi-spacing.js | 2 + .../eslint/lib/rules/semi-style.js | 3 + tools/node_modules/eslint/lib/rules/semi.js | 2 + .../eslint/lib/rules/sort-imports.js | 2 + .../eslint/lib/rules/sort-keys.js | 3 + .../eslint/lib/rules/sort-vars.js | 2 + .../eslint/lib/rules/space-before-blocks.js | 81 ++--- .../lib/rules/space-before-function-paren.js | 2 + .../eslint/lib/rules/space-in-parens.js | 2 + .../eslint/lib/rules/space-infix-ops.js | 2 + .../eslint/lib/rules/space-unary-ops.js | 2 + .../eslint/lib/rules/spaced-comment.js | 2 + tools/node_modules/eslint/lib/rules/strict.js | 2 + .../eslint/lib/rules/switch-colon-spacing.js | 4 + .../eslint/lib/rules/symbol-description.js | 2 + .../lib/rules/template-curly-spacing.js | 2 + .../eslint/lib/rules/template-tag-spacing.js | 2 + .../eslint/lib/rules/unicode-bom.js | 2 + .../eslint/lib/rules/use-isnan.js | 2 + .../eslint/lib/rules/valid-jsdoc.js | 2 + .../eslint/lib/rules/valid-typeof.js | 2 + .../eslint/lib/rules/vars-on-top.js | 2 + .../eslint/lib/rules/wrap-iife.js | 2 + .../eslint/lib/rules/wrap-regex.js | 4 +- .../eslint/lib/rules/yield-star-spacing.js | 2 + tools/node_modules/eslint/lib/rules/yoda.js | 2 + .../eslint/node_modules/acorn/dist/acorn.js | 50 +++- .../node_modules/acorn/dist/acorn.js.map | 2 +- .../eslint/node_modules/acorn/dist/acorn.mjs | 50 +++- .../node_modules/acorn/dist/acorn.mjs.map | 2 +- .../eslint/node_modules/acorn/package.json | 2 +- .../node_modules/ajv/dist/ajv.bundle.js | 2 +- .../eslint/node_modules/ajv/dist/ajv.min.js | 4 +- .../node_modules/ajv/dist/ajv.min.js.map | 2 +- .../eslint/node_modules/ajv/lib/ajv.d.ts | 7 + .../node_modules/ajv/lib/compile/formats.js | 2 +- .../eslint/node_modules/ajv/package.json | 8 +- .../eslint/node_modules/arrify/index.js | 8 - .../eslint/node_modules/arrify/package.json | 42 --- .../eslint/node_modules/arrify/readme.md | 36 --- .../eslint/node_modules/del/index.js | 63 ++-- .../eslint/node_modules/del/license | 20 +- .../eslint/node_modules/del/package.json | 22 +- .../eslint/node_modules/del/readme.md | 33 ++- .../eslint-plugin-markdown/README.md | 31 ++ .../eslint-plugin-markdown/lib/processor.js | 177 ++++++++++- .../eslint-plugin-markdown/package.json | 21 +- .../eslint/node_modules/flat-cache/cache.js | 12 +- .../node_modules/flat-cache/changelog.md | 95 +++++- .../node_modules/flat-cache/package.json | 14 +- .../eslint/node_modules/function-bind/LICENSE | 20 -- .../node_modules/function-bind/README.md | 48 --- .../function-bind/implementation.js | 52 ---- .../node_modules/function-bind/index.js | 5 - .../node_modules/function-bind/package.json | 71 ----- .../eslint/node_modules/globby/index.js | 29 +- .../globby/node_modules/pify/index.js | 68 +++++ .../node_modules/pify}/license | 0 .../globby/node_modules/pify/package.json | 57 ++++ .../globby/node_modules/pify/readme.md | 119 ++++++++ .../eslint/node_modules/globby/package.json | 9 +- .../eslint/node_modules/globby/readme.md | 10 +- .../graceful-fs/{fs.js => clone.js} | 4 +- .../node_modules/graceful-fs/graceful-fs.js | 39 ++- .../node_modules/graceful-fs/package.json | 14 +- .../node_modules/graceful-fs/polyfills.js | 277 +++++++++--------- .../eslint/node_modules/has/LICENSE-MIT | 22 -- .../eslint/node_modules/has/README.md | 18 -- .../eslint/node_modules/has/package.json | 50 ---- .../eslint/node_modules/has/src/index.js | 5 - .../eslint/node_modules/p-map/index.js | 67 +++++ .../eslint/node_modules/p-map/license | 9 + .../eslint/node_modules/p-map/package.json | 56 ++++ .../eslint/node_modules/p-map/readme.md | 81 +++++ .../eslint/node_modules/pify/index.js | 102 ++++--- .../eslint/node_modules/pify/license | 20 +- .../eslint/node_modules/pify/package.json | 13 +- .../eslint/node_modules/pify/readme.md | 62 ++-- .../node_modules/remark-parse/lib/decode.js | 15 +- .../node_modules/remark-parse/lib/defaults.js | 13 +- .../remark-parse/lib/locate/break.js | 8 - .../remark-parse/lib/locate/code-inline.js | 8 - .../remark-parse/lib/locate/delete.js | 8 - .../remark-parse/lib/locate/emphasis.js | 8 - .../remark-parse/lib/locate/escape.js | 8 - .../remark-parse/lib/locate/link.js | 8 - .../remark-parse/lib/locate/strong.js | 8 - .../remark-parse/lib/locate/tag.js | 8 - .../remark-parse/lib/locate/url.js | 8 - .../node_modules/remark-parse/lib/parse.js | 8 - .../node_modules/remark-parse/lib/parser.js | 12 +- .../remark-parse/lib/set-options.js | 14 +- .../remark-parse/lib/tokenize/auto-link.js | 26 +- .../remark-parse/lib/tokenize/blockquote.js | 8 - .../remark-parse/lib/tokenize/break.js | 13 +- .../remark-parse/lib/tokenize/code-fenced.js | 9 - .../lib/tokenize/code-indented.js | 8 - .../remark-parse/lib/tokenize/code-inline.js | 8 - .../remark-parse/lib/tokenize/definition.js | 11 +- .../remark-parse/lib/tokenize/delete.js | 9 - .../remark-parse/lib/tokenize/emphasis.js | 9 - .../remark-parse/lib/tokenize/escape.js | 9 - .../lib/tokenize/footnote-definition.js | 9 - .../remark-parse/lib/tokenize/heading-atx.js | 9 - .../lib/tokenize/heading-setext.js | 9 - .../remark-parse/lib/tokenize/html-block.js | 9 - .../remark-parse/lib/tokenize/html-inline.js | 9 - .../remark-parse/lib/tokenize/link.js | 23 +- .../remark-parse/lib/tokenize/list.js | 20 -- .../remark-parse/lib/tokenize/newline.js | 8 - .../remark-parse/lib/tokenize/paragraph.js | 8 - .../remark-parse/lib/tokenize/reference.js | 31 +- .../remark-parse/lib/tokenize/strong.js | 9 - .../remark-parse/lib/tokenize/table.js | 10 - .../remark-parse/lib/tokenize/text.js | 9 - .../lib/tokenize/thematic-break.js | 9 - .../remark-parse/lib/tokenize/url.js | 11 +- .../remark-parse/lib/tokenize/yaml.js | 74 ----- .../remark-parse/lib/tokenizer.js | 166 ++--------- .../node_modules/remark-parse/lib/unescape.js | 9 - .../remark-parse/lib/util/get-indentation.js | 16 +- .../remark-parse/lib/util/html.js | 8 - .../remark-parse/lib/util/interrupt.js | 8 - .../remark-parse/lib/util/normalize.js | 22 +- .../lib/util/remove-indentation.js | 28 +- .../node_modules/remark-parse/package.json | 9 +- .../node_modules/remark-parse/readme.md | 167 ++++++----- tools/node_modules/eslint/package.json | 8 +- 369 files changed, 2464 insertions(+), 1741 deletions(-) delete mode 100644 tools/node_modules/eslint/node_modules/arrify/index.js delete mode 100644 tools/node_modules/eslint/node_modules/arrify/package.json delete mode 100644 tools/node_modules/eslint/node_modules/arrify/readme.md delete mode 100644 tools/node_modules/eslint/node_modules/function-bind/LICENSE delete mode 100644 tools/node_modules/eslint/node_modules/function-bind/README.md delete mode 100644 tools/node_modules/eslint/node_modules/function-bind/implementation.js delete mode 100644 tools/node_modules/eslint/node_modules/function-bind/index.js delete mode 100644 tools/node_modules/eslint/node_modules/function-bind/package.json create mode 100644 tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js rename tools/node_modules/eslint/node_modules/{arrify => globby/node_modules/pify}/license (100%) create mode 100644 tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json create mode 100644 tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md rename tools/node_modules/eslint/node_modules/graceful-fs/{fs.js => clone.js} (88%) delete mode 100644 tools/node_modules/eslint/node_modules/has/LICENSE-MIT delete mode 100644 tools/node_modules/eslint/node_modules/has/README.md delete mode 100644 tools/node_modules/eslint/node_modules/has/package.json delete mode 100644 tools/node_modules/eslint/node_modules/has/src/index.js create mode 100644 tools/node_modules/eslint/node_modules/p-map/index.js create mode 100644 tools/node_modules/eslint/node_modules/p-map/license create mode 100644 tools/node_modules/eslint/node_modules/p-map/package.json create mode 100644 tools/node_modules/eslint/node_modules/p-map/readme.md delete mode 100644 tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js diff --git a/tools/node_modules/eslint/lib/cli-engine.js b/tools/node_modules/eslint/lib/cli-engine.js index 5b52459ac830dc..652d68b59b4953 100644 --- a/tools/node_modules/eslint/lib/cli-engine.js +++ b/tools/node_modules/eslint/lib/cli-engine.js @@ -19,8 +19,10 @@ const fs = require("fs"), path = require("path"), defaultOptions = require("../conf/default-cli-options"), Linter = require("./linter"), + lodash = require("lodash"), IgnoredPaths = require("./ignored-paths"), Config = require("./config"), + ConfigOps = require("./config/config-ops"), LintResultCache = require("./util/lint-result-cache"), globUtils = require("./util/glob-utils"), validator = require("./config/config-validator"), @@ -31,6 +33,7 @@ const fs = require("fs"), const debug = require("debug")("eslint:cli-engine"); const resolver = new ModuleResolver(); +const validFixTypes = new Set(["problem", "suggestion", "layout"]); //------------------------------------------------------------------------------ // Typedefs @@ -48,6 +51,7 @@ const resolver = new ModuleResolver(); * @property {string[]} envs An array of environments to load. * @property {string[]} extensions An array of file extensions to check. * @property {boolean|Function} fix Execute in autofix mode. If a function, should return a boolean. + * @property {string[]} fixTypes Array of rule types to apply fixes for. * @property {string[]} globals An array of global variables to declare. * @property {boolean} ignore False disables use of .eslintignore. * @property {string} ignorePath The ignore file to use instead of .eslintignore. @@ -84,6 +88,21 @@ const resolver = new ModuleResolver(); // Helpers //------------------------------------------------------------------------------ +/** + * Determines if each fix type in an array is supported by ESLint and throws + * an error if not. + * @param {string[]} fixTypes An array of fix types to check. + * @returns {void} + * @throws {Error} If an invalid fix type is found. + */ +function validateFixTypes(fixTypes) { + for (const fixType of fixTypes) { + if (!validFixTypes.has(fixType)) { + throw new Error(`Invalid fix type "${fixType}" found.`); + } + } +} + /** * It will calculate the error and warning count for collection of messages per file * @param {Object[]} messages - Collection of messages @@ -142,7 +161,7 @@ function calculateStatsPerRun(results) { * @param {boolean} allowInlineConfig Allow/ignore comments that change config. * @param {boolean} reportUnusedDisableDirectives Allow/ignore comments that change config. * @param {Linter} linter Linter context - * @returns {LintResult} The results for linting on this text. + * @returns {{rules: LintResult, config: Object}} The results for linting on this text and the fully-resolved config for it. * @private */ function processText(text, configHelper, filename, fix, allowInlineConfig, reportUnusedDisableDirectives, linter) { @@ -174,7 +193,6 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor } const autofixingEnabled = typeof fix !== "undefined" && (!processor || processor.supportsAutofix); - const fixedResult = linter.verifyAndFix(text, config, { filename: effectiveFilename, allowInlineConfig, @@ -183,7 +201,6 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor preprocess: processor && (rawText => processor.preprocess(rawText, effectiveFilename)), postprocess: processor && (problemLists => processor.postprocess(problemLists, effectiveFilename)) }); - const stats = calculateStatsPerFile(fixedResult.messages); const result = { @@ -203,7 +220,7 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor result.source = text; } - return result; + return { result, config }; } /** @@ -213,24 +230,22 @@ function processText(text, configHelper, filename, fix, allowInlineConfig, repor * @param {Object} configHelper The configuration options for ESLint. * @param {Object} options The CLIEngine options object. * @param {Linter} linter Linter context - * @returns {LintResult} The results for linting on this file. + * @returns {{rules: LintResult, config: Object}} The results for linting on this text and the fully-resolved config for it. * @private */ function processFile(filename, configHelper, options, linter) { - const text = fs.readFileSync(path.resolve(filename), "utf8"), - result = processText( - text, - configHelper, - filename, - options.fix, - options.allowInlineConfig, - options.reportUnusedDisableDirectives, - linter - ); - - return result; - + const text = fs.readFileSync(path.resolve(filename), "utf8"); + + return processText( + text, + configHelper, + filename, + options.fix, + options.allowInlineConfig, + options.reportUnusedDisableDirectives, + linter + ); } /** @@ -272,6 +287,33 @@ function createIgnoreResult(filePath, baseDir) { }; } +/** + * Produces rule warnings (i.e. deprecation) from configured rules + * @param {(Array|Set)} usedRules - Rules configured + * @param {Map} loadedRules - Map of loaded rules + * @returns {Array} Contains rule warnings + * @private + */ +function createRuleDeprecationWarnings(usedRules, loadedRules) { + const usedDeprecatedRules = []; + + usedRules.forEach(name => { + const loadedRule = loadedRules.get(name); + + if (loadedRule && loadedRule.meta && loadedRule.meta.deprecated) { + const deprecatedRule = { ruleId: name }; + const replacedBy = lodash.get(loadedRule, "meta.replacedBy", []); + + if (replacedBy.every(newRule => lodash.isString(newRule))) { + deprecatedRule.replacedBy = replacedBy; + } + + usedDeprecatedRules.push(deprecatedRule); + } + }); + + return usedDeprecatedRules; +} /** * Checks if the given message is an error message. @@ -429,6 +471,33 @@ class CLIEngine { */ this._lintResultCache = new LintResultCache(cacheFile, this.config); } + + // setup special filter for fixes + if (this.options.fix && this.options.fixTypes && this.options.fixTypes.length > 0) { + + debug(`Using fix types ${this.options.fixTypes}`); + + // throw an error if any invalid fix types are found + validateFixTypes(this.options.fixTypes); + + // convert to Set for faster lookup + const fixTypes = new Set(this.options.fixTypes); + + // save original value of options.fix in case it's a function + const originalFix = (typeof this.options.fix === "function") + ? this.options.fix : () => this.options.fix; + + // create a cache of rules (but don't populate until needed) + this._rulesCache = null; + + this.options.fix = lintResult => { + const rule = this._rulesCache.get(lintResult.ruleId); + const matches = rule.meta && fixTypes.has(rule.meta.type); + + return matches && originalFix(lintResult); + }; + } + } getRules() { @@ -511,6 +580,7 @@ class CLIEngine { const startTime = Date.now(); const fileList = globUtils.listFilesToProcess(patterns, options); + const allUsedRules = new Set(); const results = fileList.map(fileInfo => { if (fileInfo.ignored) { return createIgnoreResult(fileInfo.filename, options.cwd); @@ -532,9 +602,20 @@ class CLIEngine { } } + // if there's a cache, populate it + if ("_rulesCache" in this) { + this._rulesCache = this.getRules(); + } + debug(`Processing ${fileInfo.filename}`); - return processFile(fileInfo.filename, configHelper, options, this.linter); + const { result, config } = processFile(fileInfo.filename, configHelper, options, this.linter); + + Object.keys(config.rules) + .filter(ruleId => ConfigOps.getRuleSeverity(config.rules[ruleId])) + .forEach(ruleId => allUsedRules.add(ruleId)); + + return result; }); if (options.cache) { @@ -555,6 +636,8 @@ class CLIEngine { const stats = calculateStatsPerRun(results); + const usedDeprecatedRules = createRuleDeprecationWarnings(allUsedRules, this.getRules()); + debug(`Linting complete in: ${Date.now() - startTime}ms`); return { @@ -562,7 +645,8 @@ class CLIEngine { errorCount: stats.errorCount, warningCount: stats.warningCount, fixableErrorCount: stats.fixableErrorCount, - fixableWarningCount: stats.fixableWarningCount + fixableWarningCount: stats.fixableWarningCount, + usedDeprecatedRules }; } @@ -585,22 +669,34 @@ class CLIEngine { const resolvedFilename = filename && !path.isAbsolute(filename) ? path.resolve(options.cwd, filename) : filename; + let usedDeprecatedRules; if (resolvedFilename && ignoredPaths.contains(resolvedFilename)) { if (warnIgnored) { results.push(createIgnoreResult(resolvedFilename, options.cwd)); } + usedDeprecatedRules = []; } else { - results.push( - processText( - text, - configHelper, - resolvedFilename, - options.fix, - options.allowInlineConfig, - options.reportUnusedDisableDirectives, - this.linter - ) + + // if there's a cache, populate it + if ("_rulesCache" in this) { + this._rulesCache = this.getRules(); + } + + const { result, config } = processText( + text, + configHelper, + resolvedFilename, + options.fix, + options.allowInlineConfig, + options.reportUnusedDisableDirectives, + this.linter + ); + + results.push(result); + usedDeprecatedRules = createRuleDeprecationWarnings( + Object.keys(config.rules).filter(rule => ConfigOps.getRuleSeverity(config.rules[rule])), + this.getRules() ); } @@ -611,7 +707,8 @@ class CLIEngine { errorCount: stats.errorCount, warningCount: stats.warningCount, fixableErrorCount: stats.fixableErrorCount, - fixableWarningCount: stats.fixableWarningCount + fixableWarningCount: stats.fixableWarningCount, + usedDeprecatedRules }; } diff --git a/tools/node_modules/eslint/lib/cli.js b/tools/node_modules/eslint/lib/cli.js index f854015fe9c056..f67eb7274ffa64 100644 --- a/tools/node_modules/eslint/lib/cli.js +++ b/tools/node_modules/eslint/lib/cli.js @@ -64,6 +64,7 @@ function translateOptions(cliOptions) { cacheFile: cliOptions.cacheFile, cacheLocation: cliOptions.cacheLocation, fix: (cliOptions.fix || cliOptions.fixDryRun) && (cliOptions.quiet ? quietFixPredicate : true), + fixTypes: cliOptions.fixType, allowInlineConfig: cliOptions.inlineConfig, reportUnusedDisableDirectives: cliOptions.reportUnusedDisableDirectives }; @@ -187,8 +188,12 @@ const cli = { return 2; } - const engine = new CLIEngine(translateOptions(currentOptions)); + if (currentOptions.fixType && !currentOptions.fix && !currentOptions.fixDryRun) { + log.error("The --fix-type option requires either --fix or --fix-dry-run."); + return 2; + } + const engine = new CLIEngine(translateOptions(currentOptions)); const report = useStdin ? engine.executeOnText(text, currentOptions.stdinFilename, true) : engine.executeOnFiles(files); if (currentOptions.fix) { diff --git a/tools/node_modules/eslint/lib/options.js b/tools/node_modules/eslint/lib/options.js index 9265d151d5c592..ee7357a296aa05 100644 --- a/tools/node_modules/eslint/lib/options.js +++ b/tools/node_modules/eslint/lib/options.js @@ -97,6 +97,11 @@ module.exports = optionator({ default: false, description: "Automatically fix problems without saving the changes to the file system" }, + { + option: "fix-type", + type: "Array", + description: "Specify the types of fixes to apply (problem, suggestion, layout)" + }, { heading: "Ignoring files" }, diff --git a/tools/node_modules/eslint/lib/rules/accessor-pairs.js b/tools/node_modules/eslint/lib/rules/accessor-pairs.js index 68607295438594..032e89430571fa 100644 --- a/tools/node_modules/eslint/lib/rules/accessor-pairs.js +++ b/tools/node_modules/eslint/lib/rules/accessor-pairs.js @@ -72,12 +72,15 @@ function isPropertyDescriptor(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce getter and setter pairs in objects", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/accessor-pairs" }, + schema: [{ type: "object", properties: { @@ -90,6 +93,7 @@ module.exports = { }, additionalProperties: false }], + messages: { getter: "Getter is not present.", setter: "Setter is not present." diff --git a/tools/node_modules/eslint/lib/rules/array-bracket-newline.js b/tools/node_modules/eslint/lib/rules/array-bracket-newline.js index e8f7c502ef493d..a458e69f761687 100644 --- a/tools/node_modules/eslint/lib/rules/array-bracket-newline.js +++ b/tools/node_modules/eslint/lib/rules/array-bracket-newline.js @@ -13,13 +13,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce linebreaks after opening and before closing array brackets", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/array-bracket-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ @@ -42,6 +46,7 @@ module.exports = { ] } ], + messages: { unexpectedOpeningLinebreak: "There should be no linebreak after '['.", unexpectedClosingLinebreak: "There should be no linebreak before ']'.", diff --git a/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js b/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js index f46c3978dfa468..4bead37a12f51e 100644 --- a/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js +++ b/tools/node_modules/eslint/lib/rules/array-bracket-spacing.js @@ -12,13 +12,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside array brackets", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/array-bracket-spacing" }, + fixable: "whitespace", + schema: [ { enum: ["always", "never"] @@ -39,6 +43,7 @@ module.exports = { additionalProperties: false } ], + messages: { unexpectedSpaceAfter: "There should be no space after '{{tokenValue}}'.", unexpectedSpaceBefore: "There should be no space before '{{tokenValue}}'.", diff --git a/tools/node_modules/eslint/lib/rules/array-callback-return.js b/tools/node_modules/eslint/lib/rules/array-callback-return.js index 4d374cf22404d4..bfee39b037bc7d 100644 --- a/tools/node_modules/eslint/lib/rules/array-callback-return.js +++ b/tools/node_modules/eslint/lib/rules/array-callback-return.js @@ -141,6 +141,8 @@ function isCallbackOfArrayMethod(node) { module.exports = { meta: { + type: "problem", + docs: { description: "enforce `return` statements in callbacks of array methods", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/array-element-newline.js b/tools/node_modules/eslint/lib/rules/array-element-newline.js index c4caf8c71c0aac..440290917d39b0 100644 --- a/tools/node_modules/eslint/lib/rules/array-element-newline.js +++ b/tools/node_modules/eslint/lib/rules/array-element-newline.js @@ -13,13 +13,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce line breaks after each array element", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/array-element-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ diff --git a/tools/node_modules/eslint/lib/rules/arrow-body-style.js b/tools/node_modules/eslint/lib/rules/arrow-body-style.js index 92068c75c42463..c2ce3b59e4f436 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-body-style.js +++ b/tools/node_modules/eslint/lib/rules/arrow-body-style.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require braces around arrow function bodies", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/arrow-parens.js b/tools/node_modules/eslint/lib/rules/arrow-parens.js index 7a6ef6f8bed781..637a0c1f1f13a5 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-parens.js +++ b/tools/node_modules/eslint/lib/rules/arrow-parens.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require parentheses around arrow function arguments", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/arrow-spacing.js b/tools/node_modules/eslint/lib/rules/arrow-spacing.js index a1db18fc910bbc..87d381840a95dc 100644 --- a/tools/node_modules/eslint/lib/rules/arrow-spacing.js +++ b/tools/node_modules/eslint/lib/rules/arrow-spacing.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after the arrow in arrow functions", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/block-scoped-var.js b/tools/node_modules/eslint/lib/rules/block-scoped-var.js index 1000fbc83c6557..053cfc334cd11a 100644 --- a/tools/node_modules/eslint/lib/rules/block-scoped-var.js +++ b/tools/node_modules/eslint/lib/rules/block-scoped-var.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the use of variables within the scope they are defined", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/block-spacing.js b/tools/node_modules/eslint/lib/rules/block-spacing.js index 838c2c7016b62f..6496f8596d31b7 100644 --- a/tools/node_modules/eslint/lib/rules/block-spacing.js +++ b/tools/node_modules/eslint/lib/rules/block-spacing.js @@ -13,6 +13,8 @@ const util = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow or enforce spaces inside of blocks after opening block and before closing block", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/brace-style.js b/tools/node_modules/eslint/lib/rules/brace-style.js index 236a01096ab196..d172124d2f48f7 100644 --- a/tools/node_modules/eslint/lib/rules/brace-style.js +++ b/tools/node_modules/eslint/lib/rules/brace-style.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent brace style for blocks", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/callback-return.js b/tools/node_modules/eslint/lib/rules/callback-return.js index f55fed87db0598..c5263cde46b752 100644 --- a/tools/node_modules/eslint/lib/rules/callback-return.js +++ b/tools/node_modules/eslint/lib/rules/callback-return.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `return` statements after callbacks", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/camelcase.js b/tools/node_modules/eslint/lib/rules/camelcase.js index 41040450f94294..8aeb4b5bd0df92 100644 --- a/tools/node_modules/eslint/lib/rules/camelcase.js +++ b/tools/node_modules/eslint/lib/rules/camelcase.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce camelcase naming convention", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/capitalized-comments.js b/tools/node_modules/eslint/lib/rules/capitalized-comments.js index 8fabde287cc9be..86427ba7acc5d0 100644 --- a/tools/node_modules/eslint/lib/rules/capitalized-comments.js +++ b/tools/node_modules/eslint/lib/rules/capitalized-comments.js @@ -108,13 +108,17 @@ function createRegExpForIgnorePatterns(normalizedOptions) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce or disallow capitalization of the first letter of a comment", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/capitalized-comments" }, + fixable: "code", + schema: [ { enum: ["always", "never"] }, { diff --git a/tools/node_modules/eslint/lib/rules/class-methods-use-this.js b/tools/node_modules/eslint/lib/rules/class-methods-use-this.js index b7d94135bb70dc..a15ab6b89e480f 100644 --- a/tools/node_modules/eslint/lib/rules/class-methods-use-this.js +++ b/tools/node_modules/eslint/lib/rules/class-methods-use-this.js @@ -11,12 +11,15 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce that class methods utilize `this`", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/class-methods-use-this" }, + schema: [{ type: "object", properties: { diff --git a/tools/node_modules/eslint/lib/rules/comma-dangle.js b/tools/node_modules/eslint/lib/rules/comma-dangle.js index 9bc6c3fa8cc7bd..96799b30796349 100644 --- a/tools/node_modules/eslint/lib/rules/comma-dangle.js +++ b/tools/node_modules/eslint/lib/rules/comma-dangle.js @@ -76,13 +76,17 @@ function normalizeOptions(optionValue) { module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow trailing commas", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/comma-dangle" }, + fixable: "code", + schema: { definitions: { value: { diff --git a/tools/node_modules/eslint/lib/rules/comma-spacing.js b/tools/node_modules/eslint/lib/rules/comma-spacing.js index d3f82b3a4b9f14..2db0035b545348 100644 --- a/tools/node_modules/eslint/lib/rules/comma-spacing.js +++ b/tools/node_modules/eslint/lib/rules/comma-spacing.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after commas", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/comma-style.js b/tools/node_modules/eslint/lib/rules/comma-style.js index 7f996b344d4c16..2586cf66e9226b 100644 --- a/tools/node_modules/eslint/lib/rules/comma-style.js +++ b/tools/node_modules/eslint/lib/rules/comma-style.js @@ -13,13 +13,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent comma style", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/comma-style" }, + fixable: "code", + schema: [ { enum: ["first", "last"] @@ -37,6 +41,7 @@ module.exports = { additionalProperties: false } ], + messages: { unexpectedLineBeforeAndAfterComma: "Bad line breaking before and after ','.", expectedCommaFirst: "',' should be placed first.", diff --git a/tools/node_modules/eslint/lib/rules/complexity.js b/tools/node_modules/eslint/lib/rules/complexity.js index bc66d303b6340f..af583c02791dd0 100644 --- a/tools/node_modules/eslint/lib/rules/complexity.js +++ b/tools/node_modules/eslint/lib/rules/complexity.js @@ -20,6 +20,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum cyclomatic complexity allowed in a program", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js index 060b2c5b40d5a2..188d863d0d0f83 100644 --- a/tools/node_modules/eslint/lib/rules/computed-property-spacing.js +++ b/tools/node_modules/eslint/lib/rules/computed-property-spacing.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside computed property brackets", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/consistent-return.js b/tools/node_modules/eslint/lib/rules/consistent-return.js index 6185d094fb59c0..ffd7ef20589490 100644 --- a/tools/node_modules/eslint/lib/rules/consistent-return.js +++ b/tools/node_modules/eslint/lib/rules/consistent-return.js @@ -53,6 +53,8 @@ function isClassConstructor(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `return` statements to either always or never specify values", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/consistent-this.js b/tools/node_modules/eslint/lib/rules/consistent-this.js index 5cc3a647dab551..4bdcdfdc10e8f0 100644 --- a/tools/node_modules/eslint/lib/rules/consistent-this.js +++ b/tools/node_modules/eslint/lib/rules/consistent-this.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce consistent naming when capturing the current execution context", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/constructor-super.js b/tools/node_modules/eslint/lib/rules/constructor-super.js index 3cbc2f59f894b4..e4cdb099b3bf52 100644 --- a/tools/node_modules/eslint/lib/rules/constructor-super.js +++ b/tools/node_modules/eslint/lib/rules/constructor-super.js @@ -92,6 +92,8 @@ function isPossibleConstructor(node) { module.exports = { meta: { + type: "problem", + docs: { description: "require `super()` calls in constructors", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/curly.js b/tools/node_modules/eslint/lib/rules/curly.js index ad8da821c1cba4..ee12da71352372 100644 --- a/tools/node_modules/eslint/lib/rules/curly.js +++ b/tools/node_modules/eslint/lib/rules/curly.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce consistent brace style for all control statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/default-case.js b/tools/node_modules/eslint/lib/rules/default-case.js index cf123198f4ae87..3061265ed8ec4f 100644 --- a/tools/node_modules/eslint/lib/rules/default-case.js +++ b/tools/node_modules/eslint/lib/rules/default-case.js @@ -12,6 +12,8 @@ const DEFAULT_COMMENT_PATTERN = /^no default$/i; module.exports = { meta: { + type: "suggestion", + docs: { description: "require `default` cases in `switch` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/dot-location.js b/tools/node_modules/eslint/lib/rules/dot-location.js index 34d2d4eaab8d78..0eefec2eaffee0 100644 --- a/tools/node_modules/eslint/lib/rules/dot-location.js +++ b/tools/node_modules/eslint/lib/rules/dot-location.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent newlines before and after dots", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/dot-notation.js b/tools/node_modules/eslint/lib/rules/dot-notation.js index a7062df8a5babc..55ccea4ce38f4c 100644 --- a/tools/node_modules/eslint/lib/rules/dot-notation.js +++ b/tools/node_modules/eslint/lib/rules/dot-notation.js @@ -19,6 +19,8 @@ const keywords = require("../util/keywords"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce dot notation whenever possible", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/eol-last.js b/tools/node_modules/eslint/lib/rules/eol-last.js index 3ecf4227399307..84f4d45f176bbc 100644 --- a/tools/node_modules/eslint/lib/rules/eol-last.js +++ b/tools/node_modules/eslint/lib/rules/eol-last.js @@ -16,18 +16,23 @@ const lodash = require("lodash"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow newline at the end of files", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/eol-last" }, + fixable: "whitespace", + schema: [ { enum: ["always", "never", "unix", "windows"] } ], + messages: { missing: "Newline required at end of file but not found.", unexpected: "Newline not allowed at end of file." diff --git a/tools/node_modules/eslint/lib/rules/eqeqeq.js b/tools/node_modules/eslint/lib/rules/eqeqeq.js index 2c5e9ae9e4fdad..715c5ce7c027c7 100644 --- a/tools/node_modules/eslint/lib/rules/eqeqeq.js +++ b/tools/node_modules/eslint/lib/rules/eqeqeq.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require the use of `===` and `!==`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/for-direction.js b/tools/node_modules/eslint/lib/rules/for-direction.js index b93c4c2caa4b66..db079b267935cb 100644 --- a/tools/node_modules/eslint/lib/rules/for-direction.js +++ b/tools/node_modules/eslint/lib/rules/for-direction.js @@ -11,14 +11,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "enforce \"for\" loop update clause moving the counter in the right direction.", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/for-direction" }, + fixable: null, schema: [], + messages: { incorrectDirection: "The update clause in this loop moves the variable in the wrong direction." } diff --git a/tools/node_modules/eslint/lib/rules/func-call-spacing.js b/tools/node_modules/eslint/lib/rules/func-call-spacing.js index 9aae3e2517e05b..c49aa9e59f7e9c 100644 --- a/tools/node_modules/eslint/lib/rules/func-call-spacing.js +++ b/tools/node_modules/eslint/lib/rules/func-call-spacing.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing between function identifiers and their invocations", category: "Stylistic Issues", @@ -25,6 +27,7 @@ module.exports = { }, fixable: "whitespace", + schema: { anyOf: [ { @@ -58,6 +61,7 @@ module.exports = { } ] }, + messages: { unexpected: "Unexpected newline between function name and paren.", missing: "Missing space between function name and paren." diff --git a/tools/node_modules/eslint/lib/rules/func-name-matching.js b/tools/node_modules/eslint/lib/rules/func-name-matching.js index 89c07c3514c6b2..f14c998dc7fb90 100644 --- a/tools/node_modules/eslint/lib/rules/func-name-matching.js +++ b/tools/node_modules/eslint/lib/rules/func-name-matching.js @@ -70,6 +70,8 @@ const optionsObject = { module.exports = { meta: { + type: "suggestion", + docs: { description: "require function names to match the name of the variable or property to which they are assigned", category: "Stylistic Issues", @@ -88,6 +90,7 @@ module.exports = { items: [optionsObject] }] }, + messages: { matchProperty: "Function name `{{funcName}}` should match property name `{{name}}`", matchVariable: "Function name `{{funcName}}` should match variable name `{{name}}`", diff --git a/tools/node_modules/eslint/lib/rules/func-names.js b/tools/node_modules/eslint/lib/rules/func-names.js index 31f302918116e6..4ccbae0f0cb849 100644 --- a/tools/node_modules/eslint/lib/rules/func-names.js +++ b/tools/node_modules/eslint/lib/rules/func-names.js @@ -26,6 +26,8 @@ function isFunctionName(variable) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow named `function` expressions", category: "Stylistic Issues", @@ -58,6 +60,7 @@ module.exports = { } ] }, + messages: { unnamed: "Unexpected unnamed {{name}}.", named: "Unexpected named {{name}}." diff --git a/tools/node_modules/eslint/lib/rules/func-style.js b/tools/node_modules/eslint/lib/rules/func-style.js index ff48792d29af5d..b7e368cbd2ea08 100644 --- a/tools/node_modules/eslint/lib/rules/func-style.js +++ b/tools/node_modules/eslint/lib/rules/func-style.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the consistent use of either `function` declarations or expressions", category: "Stylistic Issues", @@ -31,6 +33,7 @@ module.exports = { additionalProperties: false } ], + messages: { expression: "Expected a function expression.", declaration: "Expected a function declaration." diff --git a/tools/node_modules/eslint/lib/rules/function-paren-newline.js b/tools/node_modules/eslint/lib/rules/function-paren-newline.js index d78e88038e2030..37256484f4a16e 100644 --- a/tools/node_modules/eslint/lib/rules/function-paren-newline.js +++ b/tools/node_modules/eslint/lib/rules/function-paren-newline.js @@ -16,13 +16,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent line breaks inside function parentheses", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/function-paren-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ @@ -42,6 +46,7 @@ module.exports = { ] } ], + messages: { expectedBefore: "Expected newline before ')'.", expectedAfter: "Expected newline after '('.", diff --git a/tools/node_modules/eslint/lib/rules/generator-star-spacing.js b/tools/node_modules/eslint/lib/rules/generator-star-spacing.js index 97868dd3fa980e..6f860290cec8b6 100644 --- a/tools/node_modules/eslint/lib/rules/generator-star-spacing.js +++ b/tools/node_modules/eslint/lib/rules/generator-star-spacing.js @@ -27,6 +27,8 @@ const OVERRIDE_SCHEMA = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing around `*` operators in generator functions", category: "ECMAScript 6", @@ -56,6 +58,7 @@ module.exports = { ] } ], + messages: { missingBefore: "Missing space before *.", missingAfter: "Missing space after *.", diff --git a/tools/node_modules/eslint/lib/rules/getter-return.js b/tools/node_modules/eslint/lib/rules/getter-return.js index 452ba49f595783..dc3d9d6b627e62 100644 --- a/tools/node_modules/eslint/lib/rules/getter-return.js +++ b/tools/node_modules/eslint/lib/rules/getter-return.js @@ -44,13 +44,17 @@ function getId(node) { module.exports = { meta: { + type: "problem", + docs: { description: "enforce `return` statements in getters", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/getter-return" }, + fixable: null, + schema: [ { type: "object", @@ -62,6 +66,7 @@ module.exports = { additionalProperties: false } ], + messages: { expected: "Expected to return a value in {{name}}.", expectedAlways: "Expected {{name}} to always return a value." diff --git a/tools/node_modules/eslint/lib/rules/global-require.js b/tools/node_modules/eslint/lib/rules/global-require.js index a5f5335d01dc12..6576cfb6a1f5ad 100644 --- a/tools/node_modules/eslint/lib/rules/global-require.js +++ b/tools/node_modules/eslint/lib/rules/global-require.js @@ -48,6 +48,8 @@ function isShadowed(scope, node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `require()` calls to be placed at top-level module scope", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/guard-for-in.js b/tools/node_modules/eslint/lib/rules/guard-for-in.js index 0f85e4984aa2cf..6e8452a4844a6e 100644 --- a/tools/node_modules/eslint/lib/rules/guard-for-in.js +++ b/tools/node_modules/eslint/lib/rules/guard-for-in.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `for-in` loops to include an `if` statement", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/handle-callback-err.js b/tools/node_modules/eslint/lib/rules/handle-callback-err.js index f6e6c108ce15c2..c62016d5895dcc 100644 --- a/tools/node_modules/eslint/lib/rules/handle-callback-err.js +++ b/tools/node_modules/eslint/lib/rules/handle-callback-err.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require error handling in callbacks", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/id-blacklist.js b/tools/node_modules/eslint/lib/rules/id-blacklist.js index ba9b5d4b398261..7b8facbabe0868 100644 --- a/tools/node_modules/eslint/lib/rules/id-blacklist.js +++ b/tools/node_modules/eslint/lib/rules/id-blacklist.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified identifiers", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/id-length.js b/tools/node_modules/eslint/lib/rules/id-length.js index eaed26217ddf65..d72eb08876ab37 100644 --- a/tools/node_modules/eslint/lib/rules/id-length.js +++ b/tools/node_modules/eslint/lib/rules/id-length.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce minimum and maximum identifier lengths", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/id-match.js b/tools/node_modules/eslint/lib/rules/id-match.js index 608ef17d11485b..4755c779ca96a0 100644 --- a/tools/node_modules/eslint/lib/rules/id-match.js +++ b/tools/node_modules/eslint/lib/rules/id-match.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require identifiers to match a specified regular expression", category: "Stylistic Issues", @@ -27,6 +29,12 @@ module.exports = { properties: { properties: { type: "boolean" + }, + onlyDeclarations: { + type: "boolean" + }, + ignoreDestructuring: { + type: "boolean" } } } @@ -36,15 +44,25 @@ module.exports = { create(context) { //-------------------------------------------------------------------------- - // Helpers + // Options //-------------------------------------------------------------------------- - const pattern = context.options[0] || "^.+$", regexp = new RegExp(pattern); const options = context.options[1] || {}, properties = !!options.properties, - onlyDeclarations = !!options.onlyDeclarations; + onlyDeclarations = !!options.onlyDeclarations, + ignoreDestructuring = !!options.ignoreDestructuring; + + //-------------------------------------------------------------------------- + // Helpers + //-------------------------------------------------------------------------- + + // contains reported nodes to avoid reporting twice on destructuring with shorthand notation + const reported = new Map(); + const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]); + const DECLARATION_TYPES = new Set(["FunctionDeclaration", "VariableDeclarator"]); + const IMPORT_TYPES = new Set(["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"]); /** * Checks if a string matches the provided pattern @@ -56,6 +74,26 @@ module.exports = { return !regexp.test(name); } + /** + * Checks if a parent of a node is an ObjectPattern. + * @param {ASTNode} node The node to check. + * @returns {boolean} if the node is inside an ObjectPattern + * @private + */ + function isInsideObjectPattern(node) { + let { parent } = node; + + while (parent) { + if (parent.type === "ObjectPattern") { + return true; + } + + parent = parent.parent; + } + + return false; + } + /** * Verifies if we should report an error or not based on the effective * parent node and the identifier name. @@ -64,9 +102,8 @@ module.exports = { * @returns {boolean} whether an error should be reported or not */ function shouldReport(effectiveParent, name) { - return effectiveParent.type !== "CallExpression" && - effectiveParent.type !== "NewExpression" && - isInvalid(name); + return (!onlyDeclarations || DECLARATION_TYPES.has(effectiveParent.type)) && + !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && isInvalid(name); } /** @@ -76,14 +113,17 @@ module.exports = { * @private */ function report(node) { - context.report({ - node, - message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", - data: { - name: node.name, - pattern - } - }); + if (!reported.has(node)) { + context.report({ + node, + message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", + data: { + name: node.name, + pattern + } + }); + reported.set(node, true); + } } return { @@ -106,36 +146,70 @@ module.exports = { report(node); } - // Report AssignmentExpressions only if they are the left side of the assignment + // Report AssignmentExpressions left side's assigned variable id } else if (effectiveParent.type === "AssignmentExpression" && - (effectiveParent.right.type !== "MemberExpression" || effectiveParent.left.type === "MemberExpression" && - effectiveParent.left.property.name === name)) { + effectiveParent.left.property.name === node.name) { + if (isInvalid(name)) { + report(node); + } + + // Report AssignmentExpressions only if they are the left side of the assignment + } else if (effectiveParent.type === "AssignmentExpression" && effectiveParent.right.type !== "MemberExpression") { if (isInvalid(name)) { report(node); } } - } else if (parent.type === "Property") { + /* + * Properties have their own rules, and + * AssignmentPattern nodes can be treated like Properties: + * e.g.: const { no_camelcased = false } = bar; + */ + } else if (parent.type === "Property" || parent.type === "AssignmentPattern") { + + if (parent.parent && parent.parent.type === "ObjectPattern") { + if (parent.shorthand && parent.value.left && isInvalid(name)) { + + report(node); + } + + const assignmentKeyEqualsValue = parent.key.name === parent.value.name; - if (!properties || parent.key.name !== name) { + // prevent checking righthand side of destructured object + if (!assignmentKeyEqualsValue && parent.key === node) { + return; + } + + const valueIsInvalid = parent.value.name && isInvalid(name); + + // ignore destructuring if the option is set, unless a new identifier is created + if (valueIsInvalid && !(assignmentKeyEqualsValue && ignoreDestructuring)) { + report(node); + } + } + + // never check properties or always ignore destructuring + if (!properties || (ignoreDestructuring && isInsideObjectPattern(node))) { return; } - if (shouldReport(effectiveParent, name)) { + // don't check right hand side of AssignmentExpression to prevent duplicate warnings + if (parent.right !== node && shouldReport(effectiveParent, name)) { report(node); } - } else { - const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator"; + // Check if it's an import specifier + } else if (IMPORT_TYPES.has(parent.type)) { - if (onlyDeclarations && !isDeclaration) { - return; - } - - if (shouldReport(effectiveParent, name)) { + // Report only if the local imported identifier is invalid + if (parent.local && parent.local.name === node.name && isInvalid(name)) { report(node); } + + // Report anything that is invalid that isn't a CallExpression + } else if (shouldReport(effectiveParent, name)) { + report(node); } } diff --git a/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js b/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js index a7ad1122b50544..cd729f8ad931ee 100644 --- a/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js +++ b/tools/node_modules/eslint/lib/rules/implicit-arrow-linebreak.js @@ -9,13 +9,17 @@ //------------------------------------------------------------------------------ module.exports = { meta: { + type: "layout", + docs: { description: "enforce the location of arrow function bodies", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/implicit-arrow-linebreak" }, + fixable: "whitespace", + schema: [ { enum: ["beside", "below"] diff --git a/tools/node_modules/eslint/lib/rules/indent-legacy.js b/tools/node_modules/eslint/lib/rules/indent-legacy.js index e6dc92163b0bbb..16687b521ed31a 100644 --- a/tools/node_modules/eslint/lib/rules/indent-legacy.js +++ b/tools/node_modules/eslint/lib/rules/indent-legacy.js @@ -21,16 +21,19 @@ const astUtils = require("../util/ast-utils"); /* istanbul ignore next: this rule has known coverage issues, but it's deprecated and shouldn't be updated in the future anyway. */ module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent indentation", category: "Stylistic Issues", recommended: false, - replacedBy: ["indent"], url: "https://eslint.org/docs/rules/indent-legacy" }, deprecated: true, + replacedBy: ["indent"], + fixable: "whitespace", schema: [ diff --git a/tools/node_modules/eslint/lib/rules/indent.js b/tools/node_modules/eslint/lib/rules/indent.js index 940c080a0378d4..dc9fbaf908b815 100644 --- a/tools/node_modules/eslint/lib/rules/indent.js +++ b/tools/node_modules/eslint/lib/rules/indent.js @@ -490,6 +490,8 @@ const ELEMENT_LIST_SCHEMA = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent indentation", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/init-declarations.js b/tools/node_modules/eslint/lib/rules/init-declarations.js index 412b96dc0abff9..755090917f909b 100644 --- a/tools/node_modules/eslint/lib/rules/init-declarations.js +++ b/tools/node_modules/eslint/lib/rules/init-declarations.js @@ -44,6 +44,8 @@ function isInitialized(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow initialization in variable declarations", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/jsx-quotes.js b/tools/node_modules/eslint/lib/rules/jsx-quotes.js index 3dd9567d7374e4..603d55330b536c 100644 --- a/tools/node_modules/eslint/lib/rules/jsx-quotes.js +++ b/tools/node_modules/eslint/lib/rules/jsx-quotes.js @@ -38,6 +38,8 @@ const QUOTE_SETTINGS = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce the consistent use of either double or single quotes in JSX attributes", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/key-spacing.js b/tools/node_modules/eslint/lib/rules/key-spacing.js index 75578b2c747c3b..2d1315fde09271 100644 --- a/tools/node_modules/eslint/lib/rules/key-spacing.js +++ b/tools/node_modules/eslint/lib/rules/key-spacing.js @@ -128,6 +128,8 @@ const messages = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing between keys and values in object literal properties", category: "Stylistic Issues", @@ -360,10 +362,9 @@ module.exports = { */ function isKeyValueProperty(property) { return !( - property.method || + (property.method || property.shorthand || - property.kind !== "init" || - property.type !== "Property" // Could be "ExperimentalSpreadProperty" or "SpreadElement" + property.kind !== "init" || property.type !== "Property") // Could be "ExperimentalSpreadProperty" or "SpreadElement" ); } diff --git a/tools/node_modules/eslint/lib/rules/keyword-spacing.js b/tools/node_modules/eslint/lib/rules/keyword-spacing.js index 2a66779e7aaad1..66ce2cb34c0e2b 100644 --- a/tools/node_modules/eslint/lib/rules/keyword-spacing.js +++ b/tools/node_modules/eslint/lib/rules/keyword-spacing.js @@ -65,6 +65,8 @@ function isCloseParenOfTemplate(token) { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after keywords", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/line-comment-position.js b/tools/node_modules/eslint/lib/rules/line-comment-position.js index 7f45a94b6b5679..7c791d5f2778bd 100644 --- a/tools/node_modules/eslint/lib/rules/line-comment-position.js +++ b/tools/node_modules/eslint/lib/rules/line-comment-position.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce position of line comments", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/linebreak-style.js b/tools/node_modules/eslint/lib/rules/linebreak-style.js index cd432dbcca160c..5345d53f2887f6 100644 --- a/tools/node_modules/eslint/lib/rules/linebreak-style.js +++ b/tools/node_modules/eslint/lib/rules/linebreak-style.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent linebreak style", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/lines-around-comment.js b/tools/node_modules/eslint/lib/rules/lines-around-comment.js index 67fd2032b3ea0d..30175cd3663509 100644 --- a/tools/node_modules/eslint/lib/rules/lines-around-comment.js +++ b/tools/node_modules/eslint/lib/rules/lines-around-comment.js @@ -52,6 +52,8 @@ function getCommentLineNums(comments) { module.exports = { meta: { + type: "layout", + docs: { description: "require empty lines around comments", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/lines-around-directive.js b/tools/node_modules/eslint/lib/rules/lines-around-directive.js index e8d613a41f03af..02bbe13b4fc589 100644 --- a/tools/node_modules/eslint/lib/rules/lines-around-directive.js +++ b/tools/node_modules/eslint/lib/rules/lines-around-directive.js @@ -14,13 +14,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow newlines around directives", category: "Stylistic Issues", recommended: false, - replacedBy: ["padding-line-between-statements"], url: "https://eslint.org/docs/rules/lines-around-directive" }, + schema: [{ oneOf: [ { @@ -41,8 +43,10 @@ module.exports = { } ] }], + fixable: "whitespace", - deprecated: true + deprecated: true, + replacedBy: ["padding-line-between-statements"] }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/lines-between-class-members.js b/tools/node_modules/eslint/lib/rules/lines-between-class-members.js index 8d4e6dd8c18268..5c1e69277a52f3 100644 --- a/tools/node_modules/eslint/lib/rules/lines-between-class-members.js +++ b/tools/node_modules/eslint/lib/rules/lines-between-class-members.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow an empty line between class members", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-classes-per-file.js b/tools/node_modules/eslint/lib/rules/max-classes-per-file.js index bf6b4ba31c6c1e..3193a731c94e33 100644 --- a/tools/node_modules/eslint/lib/rules/max-classes-per-file.js +++ b/tools/node_modules/eslint/lib/rules/max-classes-per-file.js @@ -15,18 +15,22 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of classes per file", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/max-classes-per-file" }, + schema: [ { type: "integer", minimum: 1 } ], + messages: { maximumExceeded: "Number of classes per file must not exceed {{ max }}" } diff --git a/tools/node_modules/eslint/lib/rules/max-depth.js b/tools/node_modules/eslint/lib/rules/max-depth.js index 368dcfa6681a77..34d58b0d31e10e 100644 --- a/tools/node_modules/eslint/lib/rules/max-depth.js +++ b/tools/node_modules/eslint/lib/rules/max-depth.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum depth that blocks can be nested", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-len.js b/tools/node_modules/eslint/lib/rules/max-len.js index 88a388309b2cdf..13dd72160cc879 100644 --- a/tools/node_modules/eslint/lib/rules/max-len.js +++ b/tools/node_modules/eslint/lib/rules/max-len.js @@ -65,6 +65,8 @@ const OPTIONS_OR_INTEGER_SCHEMA = { module.exports = { meta: { + type: "layout", + docs: { description: "enforce a maximum line length", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js index ccf6304e4b27ea..8c64a20bcc34c3 100644 --- a/tools/node_modules/eslint/lib/rules/max-lines-per-function.js +++ b/tools/node_modules/eslint/lib/rules/max-lines-per-function.js @@ -69,6 +69,8 @@ function getCommentLineNumbers(comments) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of line of code in a function", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-lines.js b/tools/node_modules/eslint/lib/rules/max-lines.js index 7eb959795abea7..730e05ab41cf11 100644 --- a/tools/node_modules/eslint/lib/rules/max-lines.js +++ b/tools/node_modules/eslint/lib/rules/max-lines.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of lines per file", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js b/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js index 8cc80ae7aab41a..d4ecb4e2a5c2c3 100644 --- a/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js +++ b/tools/node_modules/eslint/lib/rules/max-nested-callbacks.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum depth that callbacks can be nested", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-params.js b/tools/node_modules/eslint/lib/rules/max-params.js index 4089e8ae899359..f678974acf33d2 100644 --- a/tools/node_modules/eslint/lib/rules/max-params.js +++ b/tools/node_modules/eslint/lib/rules/max-params.js @@ -19,6 +19,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of parameters in function definitions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-statements-per-line.js b/tools/node_modules/eslint/lib/rules/max-statements-per-line.js index 566f04ab53b056..f3fb8e9d5cff3c 100644 --- a/tools/node_modules/eslint/lib/rules/max-statements-per-line.js +++ b/tools/node_modules/eslint/lib/rules/max-statements-per-line.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce a maximum number of statements allowed per line", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/max-statements.js b/tools/node_modules/eslint/lib/rules/max-statements.js index 525790df80623e..e32dedad632f3f 100644 --- a/tools/node_modules/eslint/lib/rules/max-statements.js +++ b/tools/node_modules/eslint/lib/rules/max-statements.js @@ -19,6 +19,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a maximum number of statements allowed in function blocks", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/multiline-comment-style.js b/tools/node_modules/eslint/lib/rules/multiline-comment-style.js index 5dd39e00a7723a..73eab7c5741bb6 100644 --- a/tools/node_modules/eslint/lib/rules/multiline-comment-style.js +++ b/tools/node_modules/eslint/lib/rules/multiline-comment-style.js @@ -12,12 +12,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce a particular style for multiline comments", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/multiline-comment-style" }, + fixable: "whitespace", schema: [{ enum: ["starred-block", "separate-lines", "bare-block"] }] }, diff --git a/tools/node_modules/eslint/lib/rules/multiline-ternary.js b/tools/node_modules/eslint/lib/rules/multiline-ternary.js index 6a22a1113c1580..d1d577a4ffaca1 100644 --- a/tools/node_modules/eslint/lib/rules/multiline-ternary.js +++ b/tools/node_modules/eslint/lib/rules/multiline-ternary.js @@ -13,12 +13,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce newlines between operands of ternary expressions", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/multiline-ternary" }, + schema: [ { enum: ["always", "always-multiline", "never"] diff --git a/tools/node_modules/eslint/lib/rules/new-cap.js b/tools/node_modules/eslint/lib/rules/new-cap.js index cc33e3b8175483..834f4605ed2838 100644 --- a/tools/node_modules/eslint/lib/rules/new-cap.js +++ b/tools/node_modules/eslint/lib/rules/new-cap.js @@ -74,6 +74,8 @@ function calculateCapIsNewExceptions(config) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require constructor names to begin with a capital letter", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/new-parens.js b/tools/node_modules/eslint/lib/rules/new-parens.js index fab302000c9c19..0637a8fbca24c7 100644 --- a/tools/node_modules/eslint/lib/rules/new-parens.js +++ b/tools/node_modules/eslint/lib/rules/new-parens.js @@ -21,6 +21,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require parentheses when invoking a constructor with no arguments", category: "Stylistic Issues", @@ -29,7 +31,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/newline-after-var.js b/tools/node_modules/eslint/lib/rules/newline-after-var.js index 62ccb3db29e97e..83fd420d733234 100644 --- a/tools/node_modules/eslint/lib/rules/newline-after-var.js +++ b/tools/node_modules/eslint/lib/rules/newline-after-var.js @@ -18,11 +18,12 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow an empty line after variable declarations", category: "Stylistic Issues", recommended: false, - replacedBy: ["padding-line-between-statements"], url: "https://eslint.org/docs/rules/newline-after-var" }, @@ -34,7 +35,9 @@ module.exports = { fixable: "whitespace", - deprecated: true + deprecated: true, + + replacedBy: ["padding-line-between-statements"] }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/newline-before-return.js b/tools/node_modules/eslint/lib/rules/newline-before-return.js index 5bc1f7031b057a..2743bf7a8bea34 100644 --- a/tools/node_modules/eslint/lib/rules/newline-before-return.js +++ b/tools/node_modules/eslint/lib/rules/newline-before-return.js @@ -11,16 +11,19 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require an empty line before `return` statements", category: "Stylistic Issues", recommended: false, - replacedBy: ["padding-line-between-statements"], url: "https://eslint.org/docs/rules/newline-before-return" }, + fixable: "whitespace", schema: [], - deprecated: true + deprecated: true, + replacedBy: ["padding-line-between-statements"] }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js b/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js index 2adcdfe45a6009..9d9931376829a6 100644 --- a/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js +++ b/tools/node_modules/eslint/lib/rules/newline-per-chained-call.js @@ -14,13 +14,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require a newline after each call in a method chain", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/newline-per-chained-call" }, + fixable: "whitespace", + schema: [{ type: "object", properties: { diff --git a/tools/node_modules/eslint/lib/rules/no-alert.js b/tools/node_modules/eslint/lib/rules/no-alert.js index 1c08460f340b91..21f10b3c399397 100644 --- a/tools/node_modules/eslint/lib/rules/no-alert.js +++ b/tools/node_modules/eslint/lib/rules/no-alert.js @@ -74,6 +74,8 @@ function isGlobalThisReferenceOrGlobalWindow(scope, node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `alert`, `confirm`, and `prompt`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-array-constructor.js b/tools/node_modules/eslint/lib/rules/no-array-constructor.js index 51676f782119a6..90c6d6bbd59281 100644 --- a/tools/node_modules/eslint/lib/rules/no-array-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-array-constructor.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `Array` constructors", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js b/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js index 55d489eb6dd586..fc65f539a3e6aa 100644 --- a/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js +++ b/tools/node_modules/eslint/lib/rules/no-async-promise-executor.js @@ -10,12 +10,15 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow using an async function as a Promise executor", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-async-promise-executor" }, + fixable: null, schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-await-in-loop.js b/tools/node_modules/eslint/lib/rules/no-await-in-loop.js index ef0bda90bf95e5..9ca89866a6e114 100644 --- a/tools/node_modules/eslint/lib/rules/no-await-in-loop.js +++ b/tools/node_modules/eslint/lib/rules/no-await-in-loop.js @@ -55,13 +55,17 @@ function isLooped(node, parent) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow `await` inside of loops", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-await-in-loop" }, + schema: [], + messages: { unexpectedAwait: "Unexpected `await` inside a loop." } diff --git a/tools/node_modules/eslint/lib/rules/no-bitwise.js b/tools/node_modules/eslint/lib/rules/no-bitwise.js index 36bbdaf349cfdf..df492937c0b5bb 100644 --- a/tools/node_modules/eslint/lib/rules/no-bitwise.js +++ b/tools/node_modules/eslint/lib/rules/no-bitwise.js @@ -22,6 +22,8 @@ const BITWISE_OPERATORS = [ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow bitwise operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js b/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js index 51f78edb1fee62..bf4c8891ad1adf 100644 --- a/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-buffer-constructor.js @@ -10,13 +10,17 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow use of the `Buffer()` constructor", category: "Node.js and CommonJS", recommended: false, url: "https://eslint.org/docs/rules/no-buffer-constructor" }, + schema: [], + messages: { deprecated: "{{expr}} is deprecated. Use Buffer.from(), Buffer.alloc(), or Buffer.allocUnsafe() instead." } diff --git a/tools/node_modules/eslint/lib/rules/no-caller.js b/tools/node_modules/eslint/lib/rules/no-caller.js index 9756b212ffe5f8..1703ad867dc0a6 100644 --- a/tools/node_modules/eslint/lib/rules/no-caller.js +++ b/tools/node_modules/eslint/lib/rules/no-caller.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `arguments.caller` or `arguments.callee`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-case-declarations.js b/tools/node_modules/eslint/lib/rules/no-case-declarations.js index c05795200e6679..1d54e221625e70 100644 --- a/tools/node_modules/eslint/lib/rules/no-case-declarations.js +++ b/tools/node_modules/eslint/lib/rules/no-case-declarations.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow lexical declarations in case clauses", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-catch-shadow.js b/tools/node_modules/eslint/lib/rules/no-catch-shadow.js index f749490f31e463..60a0493b3431a8 100644 --- a/tools/node_modules/eslint/lib/rules/no-catch-shadow.js +++ b/tools/node_modules/eslint/lib/rules/no-catch-shadow.js @@ -18,15 +18,18 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `catch` clause parameters from shadowing variables in the outer scope", category: "Variables", recommended: false, - url: "https://eslint.org/docs/rules/no-catch-shadow", - replacedBy: ["no-shadow"] + url: "https://eslint.org/docs/rules/no-catch-shadow" }, - deprecated: true, + replacedBy: ["no-shadow"], + + deprecated: true, schema: [], messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-class-assign.js b/tools/node_modules/eslint/lib/rules/no-class-assign.js index 9b28d40d4a3801..7bc65df1ba6004 100644 --- a/tools/node_modules/eslint/lib/rules/no-class-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-class-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning class members", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js b/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js index 6903bd06544edd..f5c8d5f417b20a 100644 --- a/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js +++ b/tools/node_modules/eslint/lib/rules/no-compare-neg-zero.js @@ -10,14 +10,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow comparing against -0", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/no-compare-neg-zero" }, + fixable: null, schema: [], + messages: { unexpected: "Do not use the '{{operator}}' operator to compare against -0." } diff --git a/tools/node_modules/eslint/lib/rules/no-cond-assign.js b/tools/node_modules/eslint/lib/rules/no-cond-assign.js index caf9563e9521bc..aed3e4a7a9b642 100644 --- a/tools/node_modules/eslint/lib/rules/no-cond-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-cond-assign.js @@ -19,6 +19,8 @@ const NODE_DESCRIPTIONS = { module.exports = { meta: { + type: "problem", + docs: { description: "disallow assignment operators in conditional expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js b/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js index 503174e9a67eeb..f18ec194530c19 100644 --- a/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js +++ b/tools/node_modules/eslint/lib/rules/no-confusing-arrow.js @@ -27,6 +27,8 @@ function isConditional(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow arrow functions where they could be confused with comparisons", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-console.js b/tools/node_modules/eslint/lib/rules/no-console.js index 5fb3a159be82d7..d3a2e34475168f 100644 --- a/tools/node_modules/eslint/lib/rules/no-console.js +++ b/tools/node_modules/eslint/lib/rules/no-console.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `console`", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-const-assign.js b/tools/node_modules/eslint/lib/rules/no-const-assign.js index 3188bd34d3b28d..32f8154cc23eae 100644 --- a/tools/node_modules/eslint/lib/rules/no-const-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-const-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning `const` variables", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-constant-condition.js b/tools/node_modules/eslint/lib/rules/no-constant-condition.js index 48b1fbf689f966..88984c36e7f70f 100644 --- a/tools/node_modules/eslint/lib/rules/no-constant-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-constant-condition.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow constant expressions in conditions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-continue.js b/tools/node_modules/eslint/lib/rules/no-continue.js index 3075b77f9fdebd..96718d17a3db4b 100644 --- a/tools/node_modules/eslint/lib/rules/no-continue.js +++ b/tools/node_modules/eslint/lib/rules/no-continue.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `continue` statements", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-control-regex.js b/tools/node_modules/eslint/lib/rules/no-control-regex.js index 24bb6be6671edd..24e6b197be0b44 100644 --- a/tools/node_modules/eslint/lib/rules/no-control-regex.js +++ b/tools/node_modules/eslint/lib/rules/no-control-regex.js @@ -6,7 +6,7 @@ "use strict"; const RegExpValidator = require("regexpp").RegExpValidator; -const collector = new class { +const collector = new (class { constructor() { this.ecmaVersion = 2018; this._source = ""; @@ -41,7 +41,7 @@ const collector = new class { } return this._controlChars; } -}(); +})(); //------------------------------------------------------------------------------ // Rule Definition @@ -49,6 +49,8 @@ const collector = new class { module.exports = { meta: { + type: "problem", + docs: { description: "disallow control characters in regular expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-debugger.js b/tools/node_modules/eslint/lib/rules/no-debugger.js index 5d63bb7e141e0c..95a28a862151be 100644 --- a/tools/node_modules/eslint/lib/rules/no-debugger.js +++ b/tools/node_modules/eslint/lib/rules/no-debugger.js @@ -11,14 +11,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow the use of `debugger`", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/no-debugger" }, + fixable: null, schema: [], + messages: { unexpected: "Unexpected 'debugger' statement." } diff --git a/tools/node_modules/eslint/lib/rules/no-delete-var.js b/tools/node_modules/eslint/lib/rules/no-delete-var.js index f54a396ec2d552..aeab951d75ff82 100644 --- a/tools/node_modules/eslint/lib/rules/no-delete-var.js +++ b/tools/node_modules/eslint/lib/rules/no-delete-var.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow deleting variables", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-div-regex.js b/tools/node_modules/eslint/lib/rules/no-div-regex.js index c050249fd6ef6c..408e006528b584 100644 --- a/tools/node_modules/eslint/lib/rules/no-div-regex.js +++ b/tools/node_modules/eslint/lib/rules/no-div-regex.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow division operators explicitly at the beginning of regular expressions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-args.js b/tools/node_modules/eslint/lib/rules/no-dupe-args.js index e5a7f4154e72bf..4e42336ae3dc34 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-args.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-args.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate arguments in `function` definitions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js index d0fc35973608df..97f63a2896282b 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-class-members.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate class members", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-dupe-keys.js b/tools/node_modules/eslint/lib/rules/no-dupe-keys.js index 31493bd048d0a8..9b9c02f5efc9a1 100644 --- a/tools/node_modules/eslint/lib/rules/no-dupe-keys.js +++ b/tools/node_modules/eslint/lib/rules/no-dupe-keys.js @@ -84,6 +84,8 @@ class ObjectInfo { module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate keys in object literals", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js index 128b1fc1b1cf8e..93c8548f91ad75 100644 --- a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js +++ b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate case labels", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js b/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js index 32071da15fd2cf..1d5bdfdc1a2631 100644 --- a/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js +++ b/tools/node_modules/eslint/lib/rules/no-duplicate-imports.js @@ -101,6 +101,8 @@ function handleExports(context, importsInFile, exportsInFile) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow duplicate module imports", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-else-return.js b/tools/node_modules/eslint/lib/rules/no-else-return.js index 1000fa807ac1f2..eebdec76e0e7d4 100644 --- a/tools/node_modules/eslint/lib/rules/no-else-return.js +++ b/tools/node_modules/eslint/lib/rules/no-else-return.js @@ -18,6 +18,8 @@ const FixTracker = require("../util/fix-tracker"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `else` blocks after `return` statements in `if` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-empty-character-class.js b/tools/node_modules/eslint/lib/rules/no-empty-character-class.js index e3f06b069a8661..6d2fb3c50186b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty-character-class.js +++ b/tools/node_modules/eslint/lib/rules/no-empty-character-class.js @@ -29,6 +29,8 @@ const regex = /^\/([^\\[]|\\.|\[([^\\\]]|\\.)+])*\/[gimuys]*$/; module.exports = { meta: { + type: "problem", + docs: { description: "disallow empty character classes in regular expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-empty-function.js b/tools/node_modules/eslint/lib/rules/no-empty-function.js index c8039314ab0075..a443796e4e2861 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty-function.js +++ b/tools/node_modules/eslint/lib/rules/no-empty-function.js @@ -90,6 +90,8 @@ function getKind(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow empty functions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-empty-pattern.js b/tools/node_modules/eslint/lib/rules/no-empty-pattern.js index 939710560fab0a..9f34bfde92e2e9 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty-pattern.js +++ b/tools/node_modules/eslint/lib/rules/no-empty-pattern.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow empty destructuring patterns", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-empty.js b/tools/node_modules/eslint/lib/rules/no-empty.js index 2f4c258a26fd32..9d72969e67eb6f 100644 --- a/tools/node_modules/eslint/lib/rules/no-empty.js +++ b/tools/node_modules/eslint/lib/rules/no-empty.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow empty block statements", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-eq-null.js b/tools/node_modules/eslint/lib/rules/no-eq-null.js index eadd16de37f39c..b8dead96d2514c 100644 --- a/tools/node_modules/eslint/lib/rules/no-eq-null.js +++ b/tools/node_modules/eslint/lib/rules/no-eq-null.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `null` comparisons without type-checking operators", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-eval.js b/tools/node_modules/eslint/lib/rules/no-eval.js index c3ea87d466d7e6..39d91e776e9c79 100644 --- a/tools/node_modules/eslint/lib/rules/no-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-eval.js @@ -76,6 +76,8 @@ function isMember(node, name) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `eval()`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-ex-assign.js b/tools/node_modules/eslint/lib/rules/no-ex-assign.js index 1c7beccf89e08e..4cc179a6e8f00f 100644 --- a/tools/node_modules/eslint/lib/rules/no-ex-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-ex-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning exceptions in `catch` clauses", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-extend-native.js b/tools/node_modules/eslint/lib/rules/no-extend-native.js index a1bf49f1325eff..13895f0d06bb1b 100644 --- a/tools/node_modules/eslint/lib/rules/no-extend-native.js +++ b/tools/node_modules/eslint/lib/rules/no-extend-native.js @@ -24,6 +24,8 @@ const propertyDefinitionMethods = new Set(["defineProperty", "defineProperties"] module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow extending native types", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-extra-bind.js b/tools/node_modules/eslint/lib/rules/no-extra-bind.js index 6d6cad13e97deb..abbe1868e89837 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-bind.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-bind.js @@ -22,6 +22,8 @@ const SIDE_EFFECT_FREE_NODE_TYPES = new Set(["Literal", "Identifier", "ThisExpre module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary calls to `.bind()`", category: "Best Practices", @@ -30,7 +32,6 @@ module.exports = { }, schema: [], - fixable: "code", messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js index 5eac6b53fe4f19..615603177a5a76 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-boolean-cast.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary boolean casts", category: "Possible Errors", @@ -25,7 +27,6 @@ module.exports = { }, schema: [], - fixable: "code", messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-extra-label.js b/tools/node_modules/eslint/lib/rules/no-extra-label.js index 9310e90f71e7a9..f8acf7b2834fde 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-label.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-label.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary labels", category: "Best Practices", @@ -25,7 +27,6 @@ module.exports = { }, schema: [], - fixable: "code", messages: { diff --git a/tools/node_modules/eslint/lib/rules/no-extra-parens.js b/tools/node_modules/eslint/lib/rules/no-extra-parens.js index 47c58946cf18e1..3a21b69580b820 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-parens.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-parens.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils.js"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow unnecessary parentheses", category: "Possible Errors", @@ -382,8 +384,7 @@ module.exports = { * Allow extra parens around a new expression if * there are intervening parentheses. */ - callee.type === "MemberExpression" && - doesMemberExpressionContainCallExpression(callee) + (callee.type === "MemberExpression" && doesMemberExpressionContainCallExpression(callee)) ) ) { report(node.callee); @@ -574,15 +575,13 @@ module.exports = { * If `let` is the only thing on the left side of the loop, it's the loop variable: `for ((let) of foo);` * Removing it will cause a syntax error, because it will be parsed as the start of a VariableDeclarator. */ - firstLeftToken.range[1] === node.left.range[1] || - - /* + (firstLeftToken.range[1] === node.left.range[1] || /* * If `let` is followed by a `[` token, it's a property access on the `let` value: `for ((let[foo]) of bar);` * Removing it will cause the property access to be parsed as a destructuring declaration of `foo` instead. */ astUtils.isOpeningBracketToken( sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken) - ) + )) ) ) { tokensToIgnore.add(firstLeftToken); diff --git a/tools/node_modules/eslint/lib/rules/no-extra-semi.js b/tools/node_modules/eslint/lib/rules/no-extra-semi.js index 4d40b5e1538123..d87a181672f851 100644 --- a/tools/node_modules/eslint/lib/rules/no-extra-semi.js +++ b/tools/node_modules/eslint/lib/rules/no-extra-semi.js @@ -18,6 +18,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary semicolons", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-fallthrough.js b/tools/node_modules/eslint/lib/rules/no-fallthrough.js index ce4f91ad9643ce..b7fa221050dd94 100644 --- a/tools/node_modules/eslint/lib/rules/no-fallthrough.js +++ b/tools/node_modules/eslint/lib/rules/no-fallthrough.js @@ -55,6 +55,8 @@ function hasBlankLinesBetween(node, token) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow fallthrough of `case` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-floating-decimal.js b/tools/node_modules/eslint/lib/rules/no-floating-decimal.js index a62846cc10ff95..c835d6a545fa8e 100644 --- a/tools/node_modules/eslint/lib/rules/no-floating-decimal.js +++ b/tools/node_modules/eslint/lib/rules/no-floating-decimal.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow leading or trailing decimal points in numeric literals", category: "Best Practices", @@ -25,7 +27,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-func-assign.js b/tools/node_modules/eslint/lib/rules/no-func-assign.js index 029f6a9d7d15c3..ae96ab01f43057 100644 --- a/tools/node_modules/eslint/lib/rules/no-func-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-func-assign.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow reassigning `function` declarations", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-global-assign.js b/tools/node_modules/eslint/lib/rules/no-global-assign.js index 3397bdbe0009fc..73f36b25e4763e 100644 --- a/tools/node_modules/eslint/lib/rules/no-global-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-global-assign.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow assignments to native objects or read-only global variables", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js index 3bfe3f0d3a2c3f..826d9398cab56e 100644 --- a/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js +++ b/tools/node_modules/eslint/lib/rules/no-implicit-coercion.js @@ -152,6 +152,8 @@ function getNonEmptyOperand(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow shorthand type conversions", category: "Best Practices", @@ -160,6 +162,7 @@ module.exports = { }, fixable: "code", + schema: [{ type: "object", properties: { diff --git a/tools/node_modules/eslint/lib/rules/no-implicit-globals.js b/tools/node_modules/eslint/lib/rules/no-implicit-globals.js index c4717b6a374e86..2eea2b28463250 100644 --- a/tools/node_modules/eslint/lib/rules/no-implicit-globals.js +++ b/tools/node_modules/eslint/lib/rules/no-implicit-globals.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow variable and `function` declarations in the global scope", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-implied-eval.js b/tools/node_modules/eslint/lib/rules/no-implied-eval.js index de294bc8858f94..d31b5dfee8041f 100644 --- a/tools/node_modules/eslint/lib/rules/no-implied-eval.js +++ b/tools/node_modules/eslint/lib/rules/no-implied-eval.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `eval()`-like methods", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-inline-comments.js b/tools/node_modules/eslint/lib/rules/no-inline-comments.js index 2fb21909229c11..c282d16e75411a 100644 --- a/tools/node_modules/eslint/lib/rules/no-inline-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-inline-comments.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow inline comments after code", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js index 032c0a0f096788..60508d3e864eda 100644 --- a/tools/node_modules/eslint/lib/rules/no-inner-declarations.js +++ b/tools/node_modules/eslint/lib/rules/no-inner-declarations.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow variable or `function` declarations in nested blocks", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js index 7169e0ca77054c..74659001fdb9ce 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-regexp.js @@ -19,6 +19,8 @@ const undefined1 = void 0; module.exports = { meta: { + type: "problem", + docs: { description: "disallow invalid regular expression strings in `RegExp` constructors", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-invalid-this.js b/tools/node_modules/eslint/lib/rules/no-invalid-this.js index 480deebc14cded..e9be4445260bdb 100644 --- a/tools/node_modules/eslint/lib/rules/no-invalid-this.js +++ b/tools/node_modules/eslint/lib/rules/no-invalid-this.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `this` keywords outside of classes or class-like objects", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js index de6934c635ac33..7920ebdc564857 100644 --- a/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js +++ b/tools/node_modules/eslint/lib/rules/no-irregular-whitespace.js @@ -27,6 +27,8 @@ const LINE_BREAK = astUtils.createGlobalLinebreakMatcher(); module.exports = { meta: { + type: "problem", + docs: { description: "disallow irregular whitespace outside of strings and comments", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-iterator.js b/tools/node_modules/eslint/lib/rules/no-iterator.js index ca12fcda477639..82319a3fb1dfb6 100644 --- a/tools/node_modules/eslint/lib/rules/no-iterator.js +++ b/tools/node_modules/eslint/lib/rules/no-iterator.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of the `__iterator__` property", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-label-var.js b/tools/node_modules/eslint/lib/rules/no-label-var.js index 3f5aba4fc1e326..fdba2defc350c6 100644 --- a/tools/node_modules/eslint/lib/rules/no-label-var.js +++ b/tools/node_modules/eslint/lib/rules/no-label-var.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow labels that share a name with a variable", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-labels.js b/tools/node_modules/eslint/lib/rules/no-labels.js index bd6ec57a350e0f..34db20725b0af3 100644 --- a/tools/node_modules/eslint/lib/rules/no-labels.js +++ b/tools/node_modules/eslint/lib/rules/no-labels.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow labeled statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js index 5e22aacf00f8a6..6b51795863b379 100644 --- a/tools/node_modules/eslint/lib/rules/no-lone-blocks.js +++ b/tools/node_modules/eslint/lib/rules/no-lone-blocks.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary nested blocks", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-lonely-if.js b/tools/node_modules/eslint/lib/rules/no-lonely-if.js index 3ecc41e8cf6e22..4bbb5399ff9519 100644 --- a/tools/node_modules/eslint/lib/rules/no-lonely-if.js +++ b/tools/node_modules/eslint/lib/rules/no-lonely-if.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `if` statements as the only statement in `else` blocks", category: "Stylistic Issues", @@ -18,7 +20,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-loop-func.js b/tools/node_modules/eslint/lib/rules/no-loop-func.js index d103cb5335083f..e6063806a5dec2 100644 --- a/tools/node_modules/eslint/lib/rules/no-loop-func.js +++ b/tools/node_modules/eslint/lib/rules/no-loop-func.js @@ -154,6 +154,8 @@ function isSafe(loopNode, reference) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `function` declarations and expressions inside loop statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js index b70ca82675089d..84c08dfb08e717 100644 --- a/tools/node_modules/eslint/lib/rules/no-magic-numbers.js +++ b/tools/node_modules/eslint/lib/rules/no-magic-numbers.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow magic numbers", category: "Best Practices", @@ -40,6 +42,7 @@ module.exports = { }, additionalProperties: false }], + messages: { useConst: "Number constants declarations must use 'const'.", noMagic: "No magic number: {{raw}}." diff --git a/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js b/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js index e410efed9c943b..4fa650ed52725a 100644 --- a/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js +++ b/tools/node_modules/eslint/lib/rules/no-misleading-character-class.js @@ -101,13 +101,17 @@ const kinds = Object.keys(hasCharacterSequence); module.exports = { meta: { + type: "problem", + docs: { description: "disallow characters which are made with multiple code points in character class syntax", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/no-misleading-character-class" }, + schema: [], + messages: { surrogatePairWithoutUFlag: "Unexpected surrogate pair in character class. Use 'u' flag.", combiningClass: "Unexpected combined character in character class.", diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js index d4ead20062dda8..22ed65f5b1f0fd 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-operators.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-operators.js @@ -71,12 +71,15 @@ function includesBothInAGroup(groups, left, right) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow mixed binary operators", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/no-mixed-operators" }, + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js index 1058f3a511e120..438ac668a805af 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-requires.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-requires.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `require` calls to be mixed with regular variable declarations", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js index 7cb4b4ceeaea38..1fc0b6074b8fd7 100644 --- a/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-mixed-spaces-and-tabs.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "disallow mixed spaces and tabs for indentation", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-multi-assign.js b/tools/node_modules/eslint/lib/rules/no-multi-assign.js index ca3f778ac6fd87..8524a1a571ef9e 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-assign.js @@ -12,12 +12,15 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow use of chained assignment expressions", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/no-multi-assign" }, + schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js index 41bcd4fb61193f..f1792c31ed7e7e 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-spaces.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow multiple spaces", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-multi-str.js b/tools/node_modules/eslint/lib/rules/no-multi-str.js index ee0aaaa4c0c6e6..844842392df7d3 100644 --- a/tools/node_modules/eslint/lib/rules/no-multi-str.js +++ b/tools/node_modules/eslint/lib/rules/no-multi-str.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow multiline strings", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js index a111786a30829f..f945cfeffe2b07 100644 --- a/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js +++ b/tools/node_modules/eslint/lib/rules/no-multiple-empty-lines.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "disallow multiple empty lines", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-native-reassign.js b/tools/node_modules/eslint/lib/rules/no-native-reassign.js index b1064b0bb36661..9ecfb4da7cbee9 100644 --- a/tools/node_modules/eslint/lib/rules/no-native-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-native-reassign.js @@ -12,16 +12,19 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow assignments to native objects or read-only global variables", category: "Best Practices", recommended: false, - replacedBy: ["no-global-assign"], url: "https://eslint.org/docs/rules/no-native-reassign" }, deprecated: true, + replacedBy: ["no-global-assign"], + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/no-negated-condition.js b/tools/node_modules/eslint/lib/rules/no-negated-condition.js index 254dcb5c23c7e9..e55a8287487de3 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-condition.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow negated conditions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js b/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js index 7f08814c941ffd..0084ad1570bb00 100644 --- a/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js +++ b/tools/node_modules/eslint/lib/rules/no-negated-in-lhs.js @@ -12,15 +12,18 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow negating the left operand in `in` expressions", category: "Possible Errors", recommended: false, - replacedBy: ["no-unsafe-negation"], url: "https://eslint.org/docs/rules/no-negated-in-lhs" }, - deprecated: true, + replacedBy: ["no-unsafe-negation"], + + deprecated: true, schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js index 15e72f20d1cb7f..87a11e87962a8f 100644 --- a/tools/node_modules/eslint/lib/rules/no-nested-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-nested-ternary.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow nested ternary expressions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-new-func.js b/tools/node_modules/eslint/lib/rules/no-new-func.js index 8ee327baa1c445..23e92f7bf3030c 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-func.js +++ b/tools/node_modules/eslint/lib/rules/no-new-func.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators with the `Function` object", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-new-object.js b/tools/node_modules/eslint/lib/rules/no-new-object.js index 3f68cbc1b51b29..f5cc28664f4e1c 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-object.js +++ b/tools/node_modules/eslint/lib/rules/no-new-object.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `Object` constructors", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-new-require.js b/tools/node_modules/eslint/lib/rules/no-new-require.js index f74daa7569c984..1eae0659430fbd 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-require.js +++ b/tools/node_modules/eslint/lib/rules/no-new-require.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators with calls to `require`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-new-symbol.js b/tools/node_modules/eslint/lib/rules/no-new-symbol.js index a537268e38dc1d..ccf757ed6a0cee 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-symbol.js +++ b/tools/node_modules/eslint/lib/rules/no-new-symbol.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow `new` operators with the `Symbol` object", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js index e8d516212b67aa..ae2aeec0341243 100644 --- a/tools/node_modules/eslint/lib/rules/no-new-wrappers.js +++ b/tools/node_modules/eslint/lib/rules/no-new-wrappers.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators with the `String`, `Number`, and `Boolean` objects", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-new.js b/tools/node_modules/eslint/lib/rules/no-new.js index f9121bc18f656a..2e0702597eade3 100644 --- a/tools/node_modules/eslint/lib/rules/no-new.js +++ b/tools/node_modules/eslint/lib/rules/no-new.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `new` operators outside of assignments or comparisons", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-obj-calls.js b/tools/node_modules/eslint/lib/rules/no-obj-calls.js index 320343cb2c01e6..92492b7a26ed79 100644 --- a/tools/node_modules/eslint/lib/rules/no-obj-calls.js +++ b/tools/node_modules/eslint/lib/rules/no-obj-calls.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow calling global object properties as functions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-octal-escape.js b/tools/node_modules/eslint/lib/rules/no-octal-escape.js index e9509b87f821ec..fc073b14033410 100644 --- a/tools/node_modules/eslint/lib/rules/no-octal-escape.js +++ b/tools/node_modules/eslint/lib/rules/no-octal-escape.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow octal escape sequences in string literals", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-octal.js b/tools/node_modules/eslint/lib/rules/no-octal.js index d782c23a39b719..db1fa40aa5df0a 100644 --- a/tools/node_modules/eslint/lib/rules/no-octal.js +++ b/tools/node_modules/eslint/lib/rules/no-octal.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow octal literals", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-param-reassign.js b/tools/node_modules/eslint/lib/rules/no-param-reassign.js index be1a559178a973..243bb6412cff22 100644 --- a/tools/node_modules/eslint/lib/rules/no-param-reassign.js +++ b/tools/node_modules/eslint/lib/rules/no-param-reassign.js @@ -12,6 +12,8 @@ const stopNodePattern = /(?:Statement|Declaration|Function(?:Expression)?|Progra module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow reassigning `function` parameters", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-path-concat.js b/tools/node_modules/eslint/lib/rules/no-path-concat.js index 1dee7bda1117a6..dad56a4f56a9d0 100644 --- a/tools/node_modules/eslint/lib/rules/no-path-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-path-concat.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow string concatenation with `__dirname` and `__filename`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-plusplus.js b/tools/node_modules/eslint/lib/rules/no-plusplus.js index f754b3672194cd..4c854de1a06ff7 100644 --- a/tools/node_modules/eslint/lib/rules/no-plusplus.js +++ b/tools/node_modules/eslint/lib/rules/no-plusplus.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the unary operators `++` and `--`", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-process-env.js b/tools/node_modules/eslint/lib/rules/no-process-env.js index 71b27ffd72069b..a66d9709b09b4f 100644 --- a/tools/node_modules/eslint/lib/rules/no-process-env.js +++ b/tools/node_modules/eslint/lib/rules/no-process-env.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `process.env`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-process-exit.js b/tools/node_modules/eslint/lib/rules/no-process-exit.js index 2d22d7fd96a120..fcfc6b2af59d0e 100644 --- a/tools/node_modules/eslint/lib/rules/no-process-exit.js +++ b/tools/node_modules/eslint/lib/rules/no-process-exit.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `process.exit()`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-proto.js b/tools/node_modules/eslint/lib/rules/no-proto.js index e37c6c22e628b8..80b9650941696d 100644 --- a/tools/node_modules/eslint/lib/rules/no-proto.js +++ b/tools/node_modules/eslint/lib/rules/no-proto.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of the `__proto__` property", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js b/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js index f52847f44d4b0e..171395306725eb 100644 --- a/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js +++ b/tools/node_modules/eslint/lib/rules/no-prototype-builtins.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow calling some `Object.prototype` methods directly on objects", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-redeclare.js b/tools/node_modules/eslint/lib/rules/no-redeclare.js index 79ab21137ecf93..e88436d7c57b73 100644 --- a/tools/node_modules/eslint/lib/rules/no-redeclare.js +++ b/tools/node_modules/eslint/lib/rules/no-redeclare.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow variable redeclaration", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-regex-spaces.js b/tools/node_modules/eslint/lib/rules/no-regex-spaces.js index 089e06028655ed..d0f7293d20eef1 100644 --- a/tools/node_modules/eslint/lib/rules/no-regex-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-regex-spaces.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow multiple spaces in regular expressions", category: "Possible Errors", @@ -21,7 +23,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js index 72b02c032aa823..1a2629a8ec95e8 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-globals.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-globals.js @@ -17,6 +17,8 @@ const DEFAULT_MESSAGE_TEMPLATE = "Unexpected use of '{{name}}'.", module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified global variables", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js index fdebb8ca3ada0c..b8fcca1aaf8b6f 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-imports.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-imports.js @@ -53,6 +53,8 @@ const arrayOfStringsOrObjects = { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified modules when loaded by `import`", category: "ECMAScript 6", @@ -234,31 +236,47 @@ module.exports = { return restrictedPatterns.length > 0 && restrictedPatternsMatcher.ignores(importSource); } - return { - ImportDeclaration(node) { - const importSource = node.source.value.trim(); - const importNames = node.specifiers.reduce((set, specifier) => { - if (specifier.type === "ImportDefaultSpecifier") { - set.add("default"); - } else if (specifier.type === "ImportNamespaceSpecifier") { - set.add("*"); - } else { - set.add(specifier.imported.name); - } - return set; - }, new Set()); - - if (isRestrictedForEverythingImported(importSource, importNames)) { - reportPathForEverythingImported(importSource, node); + /** + * Checks a node to see if any problems should be reported. + * @param {ASTNode} node The node to check. + * @returns {void} + * @private + */ + function checkNode(node) { + const importSource = node.source.value.trim(); + const importNames = node.specifiers ? node.specifiers.reduce((set, specifier) => { + if (specifier.type === "ImportDefaultSpecifier") { + set.add("default"); + } else if (specifier.type === "ImportNamespaceSpecifier") { + set.add("*"); + } else if (specifier.imported) { + set.add(specifier.imported.name); + } else if (specifier.local) { + set.add(specifier.local.name); } + return set; + }, new Set()) : new Set(); - if (isRestrictedPath(importSource, importNames)) { - reportPath(node); - } - if (isRestrictedPattern(importSource)) { - reportPathForPatterns(node); - } + if (isRestrictedForEverythingImported(importSource, importNames)) { + reportPathForEverythingImported(importSource, node); + } + + if (isRestrictedPath(importSource, importNames)) { + reportPath(node); + } + if (isRestrictedPattern(importSource)) { + reportPathForPatterns(node); } + } + + return { + ImportDeclaration: checkNode, + ExportNamedDeclaration(node) { + if (node.source) { + checkNode(node); + } + }, + ExportAllDeclaration: checkNode }; } }; diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-modules.js b/tools/node_modules/eslint/lib/rules/no-restricted-modules.js index d63d2ce4f45881..ef8748a7d04baf 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-modules.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-modules.js @@ -47,6 +47,8 @@ const arrayOfStringsOrObjects = { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified modules when loaded by `require`", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-properties.js b/tools/node_modules/eslint/lib/rules/no-restricted-properties.js index c0f1cfb6d3834e..eede6ad1c161dd 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-properties.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-properties.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow certain properties on certain objects", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js index c472d9432e69d7..74eea1478911aa 100644 --- a/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js +++ b/tools/node_modules/eslint/lib/rules/no-restricted-syntax.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified syntax", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-return-assign.js b/tools/node_modules/eslint/lib/rules/no-return-assign.js index 519f9e0d039dac..b3c39ea2b8c4b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-return-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-return-assign.js @@ -22,6 +22,8 @@ const SENTINEL_TYPE = /^(?:[a-zA-Z]+?Statement|ArrowFunctionExpression|FunctionE module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow assignment operators in `return` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-return-await.js b/tools/node_modules/eslint/lib/rules/no-return-await.js index 5f531a18310c1b..24cb45ee5a7e52 100644 --- a/tools/node_modules/eslint/lib/rules/no-return-await.js +++ b/tools/node_modules/eslint/lib/rules/no-return-await.js @@ -14,6 +14,8 @@ const message = "Redundant use of `await` on a return value."; module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary `return await`", category: "Best Practices", @@ -22,7 +24,9 @@ module.exports = { url: "https://eslint.org/docs/rules/no-return-await" }, + fixable: null, + schema: [ ] }, diff --git a/tools/node_modules/eslint/lib/rules/no-script-url.js b/tools/node_modules/eslint/lib/rules/no-script-url.js index ba74dafb8e274d..40e9bfe8b27544 100644 --- a/tools/node_modules/eslint/lib/rules/no-script-url.js +++ b/tools/node_modules/eslint/lib/rules/no-script-url.js @@ -13,6 +13,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `javascript:` urls", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-self-assign.js b/tools/node_modules/eslint/lib/rules/no-self-assign.js index 87d1f2ff4f76de..d493855efe9c68 100644 --- a/tools/node_modules/eslint/lib/rules/no-self-assign.js +++ b/tools/node_modules/eslint/lib/rules/no-self-assign.js @@ -165,6 +165,8 @@ function eachSelfAssignment(left, right, props, report) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow assignments where both sides are exactly the same", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-self-compare.js b/tools/node_modules/eslint/lib/rules/no-self-compare.js index 6ebc3870feb6b7..8986240ec5c842 100644 --- a/tools/node_modules/eslint/lib/rules/no-self-compare.js +++ b/tools/node_modules/eslint/lib/rules/no-self-compare.js @@ -12,6 +12,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow comparisons where both sides are exactly the same", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-sequences.js b/tools/node_modules/eslint/lib/rules/no-sequences.js index e74943d81095d4..2570912f348e91 100644 --- a/tools/node_modules/eslint/lib/rules/no-sequences.js +++ b/tools/node_modules/eslint/lib/rules/no-sequences.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow comma operators", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js b/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js index 70052f56f2d2ed..9bdd50868042c3 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow-restricted-names.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow identifiers from shadowing restricted names", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-shadow.js b/tools/node_modules/eslint/lib/rules/no-shadow.js index 955fc05e582030..f910230d6a27f3 100644 --- a/tools/node_modules/eslint/lib/rules/no-shadow.js +++ b/tools/node_modules/eslint/lib/rules/no-shadow.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow variable declarations from shadowing variables declared in the outer scope", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-spaced-func.js b/tools/node_modules/eslint/lib/rules/no-spaced-func.js index 42d1e4b243a4d0..8535881f435e48 100644 --- a/tools/node_modules/eslint/lib/rules/no-spaced-func.js +++ b/tools/node_modules/eslint/lib/rules/no-spaced-func.js @@ -12,16 +12,19 @@ module.exports = { meta: { + type: "layout", + docs: { description: "disallow spacing between function identifiers and their applications (deprecated)", category: "Stylistic Issues", recommended: false, - replacedBy: ["func-call-spacing"], url: "https://eslint.org/docs/rules/no-spaced-func" }, deprecated: true, + replacedBy: ["func-call-spacing"], + fixable: "whitespace", schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js b/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js index 1cc6f7ccba9569..985109c36b267d 100644 --- a/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js +++ b/tools/node_modules/eslint/lib/rules/no-sparse-arrays.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow sparse arrays", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-sync.js b/tools/node_modules/eslint/lib/rules/no-sync.js index eb7b787d38c35a..a0096e3d04313f 100644 --- a/tools/node_modules/eslint/lib/rules/no-sync.js +++ b/tools/node_modules/eslint/lib/rules/no-sync.js @@ -13,6 +13,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow synchronous methods", category: "Node.js and CommonJS", diff --git a/tools/node_modules/eslint/lib/rules/no-tabs.js b/tools/node_modules/eslint/lib/rules/no-tabs.js index c22a94da38bee1..0002f5592900c1 100644 --- a/tools/node_modules/eslint/lib/rules/no-tabs.js +++ b/tools/node_modules/eslint/lib/rules/no-tabs.js @@ -18,6 +18,8 @@ const anyNonWhitespaceRegex = /\S/; module.exports = { meta: { + type: "layout", + docs: { description: "disallow all tabs", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js b/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js index ed74fcc6f7f16c..c286ec69000d60 100644 --- a/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js +++ b/tools/node_modules/eslint/lib/rules/no-template-curly-in-string.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "disallow template literal placeholder syntax in regular strings", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-ternary.js b/tools/node_modules/eslint/lib/rules/no-ternary.js index 4dcc8db069e991..890f2abfa0c59a 100644 --- a/tools/node_modules/eslint/lib/rules/no-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-ternary.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow ternary operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-this-before-super.js b/tools/node_modules/eslint/lib/rules/no-this-before-super.js index 8a489879eddf31..93fb094e9bc139 100644 --- a/tools/node_modules/eslint/lib/rules/no-this-before-super.js +++ b/tools/node_modules/eslint/lib/rules/no-this-before-super.js @@ -36,6 +36,8 @@ function isConstructorFunction(node) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow `this`/`super` before calling `super()` in constructors", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-throw-literal.js b/tools/node_modules/eslint/lib/rules/no-throw-literal.js index 301354b6b2c909..c4a6b86bfb4cc9 100644 --- a/tools/node_modules/eslint/lib/rules/no-throw-literal.js +++ b/tools/node_modules/eslint/lib/rules/no-throw-literal.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow throwing literals as exceptions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js b/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js index cca7af2aac322b..18f0340ef011c7 100644 --- a/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js +++ b/tools/node_modules/eslint/lib/rules/no-trailing-spaces.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow trailing whitespace at the end of lines", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-undef-init.js b/tools/node_modules/eslint/lib/rules/no-undef-init.js index f00b05d4ff0d2e..67f3944d47e7f4 100644 --- a/tools/node_modules/eslint/lib/rules/no-undef-init.js +++ b/tools/node_modules/eslint/lib/rules/no-undef-init.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow initializing variables to `undefined`", category: "Variables", @@ -21,7 +23,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-undef.js b/tools/node_modules/eslint/lib/rules/no-undef.js index c8347d50d1aa15..f923644eca114e 100644 --- a/tools/node_modules/eslint/lib/rules/no-undef.js +++ b/tools/node_modules/eslint/lib/rules/no-undef.js @@ -25,6 +25,8 @@ function hasTypeOfOperator(node) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow the use of undeclared variables unless mentioned in `/*global */` comments", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-undefined.js b/tools/node_modules/eslint/lib/rules/no-undefined.js index 8491ab5d54035e..b92f6700637c30 100644 --- a/tools/node_modules/eslint/lib/rules/no-undefined.js +++ b/tools/node_modules/eslint/lib/rules/no-undefined.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow the use of `undefined` as an identifier", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js b/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js index c76488a94313c4..926803b992d98a 100644 --- a/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js +++ b/tools/node_modules/eslint/lib/rules/no-underscore-dangle.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow dangling underscores in identifiers", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js b/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js index 181a00b2d0d4fa..3bed96fc77d069 100644 --- a/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js +++ b/tools/node_modules/eslint/lib/rules/no-unexpected-multiline.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow confusing multiline expressions", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js b/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js index fecd8ba5cca285..95898c5f19d814 100644 --- a/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js +++ b/tools/node_modules/eslint/lib/rules/no-unmodified-loop-condition.js @@ -165,6 +165,8 @@ function updateModifiedFlag(conditions, modifiers) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow unmodified loop conditions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js b/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js index 6b58b018da0ec2..3a7dd5fad7db19 100644 --- a/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js +++ b/tools/node_modules/eslint/lib/rules/no-unneeded-ternary.js @@ -24,6 +24,8 @@ const OPERATOR_INVERSES = { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow ternary operators when simpler alternatives exist", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-unreachable.js b/tools/node_modules/eslint/lib/rules/no-unreachable.js index 80d246307c31ea..8ea2583f7cb251 100644 --- a/tools/node_modules/eslint/lib/rules/no-unreachable.js +++ b/tools/node_modules/eslint/lib/rules/no-unreachable.js @@ -101,6 +101,8 @@ class ConsecutiveRange { module.exports = { meta: { + type: "problem", + docs: { description: "disallow unreachable code after `return`, `throw`, `continue`, and `break` statements", category: "Possible Errors", @@ -180,7 +182,6 @@ module.exports = { ContinueStatement: reportIfUnreachable, DebuggerStatement: reportIfUnreachable, DoWhileStatement: reportIfUnreachable, - EmptyStatement: reportIfUnreachable, ExpressionStatement: reportIfUnreachable, ForInStatement: reportIfUnreachable, ForOfStatement: reportIfUnreachable, diff --git a/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js b/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js index 1ebdd2e3775da3..ab612ae6526f66 100644 --- a/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js +++ b/tools/node_modules/eslint/lib/rules/no-unsafe-finally.js @@ -20,6 +20,8 @@ const SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaratio module.exports = { meta: { + type: "problem", + docs: { description: "disallow control flow statements in `finally` blocks", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js b/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js index b04f80106c64af..3a0402eb0d5d34 100644 --- a/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js +++ b/tools/node_modules/eslint/lib/rules/no-unsafe-negation.js @@ -41,12 +41,15 @@ function isNegation(node) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow negating the left operand of relational operators", category: "Possible Errors", recommended: true, url: "https://eslint.org/docs/rules/no-unsafe-negation" }, + schema: [], fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-unused-expressions.js b/tools/node_modules/eslint/lib/rules/no-unused-expressions.js index fedfac17d1fb15..854298b411978b 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-expressions.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-expressions.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unused expressions", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-unused-labels.js b/tools/node_modules/eslint/lib/rules/no-unused-labels.js index 3e1dcb6601fece..c9e097df458ba4 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-labels.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-labels.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unused labels", category: "Best Practices", @@ -19,7 +21,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/no-unused-vars.js b/tools/node_modules/eslint/lib/rules/no-unused-vars.js index 6f36813aca57a5..e76e3251038c00 100644 --- a/tools/node_modules/eslint/lib/rules/no-unused-vars.js +++ b/tools/node_modules/eslint/lib/rules/no-unused-vars.js @@ -18,6 +18,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow unused variables", category: "Variables", @@ -223,6 +225,32 @@ module.exports = { return false; } + /** + * Gets a list of function definitions for a specified variable. + * @param {Variable} variable - eslint-scope variable object. + * @returns {ASTNode[]} Function nodes. + * @private + */ + function getFunctionDefinitions(variable) { + const functionDefinitions = []; + + variable.defs.forEach(def => { + const { type, node } = def; + + // FunctionDeclarations + if (type === "FunctionName") { + functionDefinitions.push(node); + } + + // FunctionExpressions + if (type === "Variable" && node.init && + (node.init.type === "FunctionExpression" || node.init.type === "ArrowFunctionExpression")) { + functionDefinitions.push(node.init); + } + }); + return functionDefinitions; + } + /** * Checks the position of given nodes. * @@ -372,22 +400,18 @@ module.exports = { return ref.isRead() && ( // self update. e.g. `a += 1`, `a++` - ( - parent.type === "AssignmentExpression" && + (// in RHS of an assignment for itself. e.g. `a = a + 1` + (( + parent.type === "AssignmentExpression" && granpa.type === "ExpressionStatement" && parent.left === id - ) || + ) || ( parent.type === "UpdateExpression" && granpa.type === "ExpressionStatement" - ) || - - // in RHS of an assignment for itself. e.g. `a = a + 1` - ( - rhsNode && - isInside(id, rhsNode) && - !isInsideOfStorableFunction(id, rhsNode) - ) + ) || rhsNode && + isInside(id, rhsNode) && + !isInsideOfStorableFunction(id, rhsNode))) ); } @@ -435,7 +459,7 @@ module.exports = { * @private */ function isUsedVariable(variable) { - const functionNodes = variable.defs.filter(def => def.type === "FunctionName").map(def => def.node), + const functionNodes = getFunctionDefinitions(variable), isFunctionDefinition = functionNodes.length > 0; let rhsNode = null; diff --git a/tools/node_modules/eslint/lib/rules/no-use-before-define.js b/tools/node_modules/eslint/lib/rules/no-use-before-define.js index 64d82570279233..500cd3a4103672 100644 --- a/tools/node_modules/eslint/lib/rules/no-use-before-define.js +++ b/tools/node_modules/eslint/lib/rules/no-use-before-define.js @@ -136,6 +136,8 @@ function isInInitializer(variable, reference) { module.exports = { meta: { + type: "problem", + docs: { description: "disallow the use of variables before they are defined", category: "Variables", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-call.js b/tools/node_modules/eslint/lib/rules/no-useless-call.js index 0778b374f4f612..74e8bec08bcf3b 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-call.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-call.js @@ -49,6 +49,8 @@ function isValidThisArg(expectedThis, thisArg, sourceCode) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary calls to `.call()` and `.apply()`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js index 189f50853c8dd1..ef1f856f3efc5a 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-computed-key.js @@ -18,6 +18,8 @@ const MESSAGE_UNNECESSARY_COMPUTED = "Unnecessarily computed property [{{propert module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary computed property keys in object literals", category: "ECMAScript 6", @@ -26,7 +28,6 @@ module.exports = { }, schema: [], - fixable: "code" }, create(context) { diff --git a/tools/node_modules/eslint/lib/rules/no-useless-concat.js b/tools/node_modules/eslint/lib/rules/no-useless-concat.js index e8e36aa1c1a8b2..df310119032979 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-concat.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-concat.js @@ -66,6 +66,8 @@ function getRight(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary concatenation of literals or template literals", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js index 59e40bef8f4b66..c10376450eb5b5 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-constructor.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-constructor.js @@ -142,6 +142,8 @@ function isRedundantSuperCall(body, ctorParams) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary constructors", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-escape.js b/tools/node_modules/eslint/lib/rules/no-useless-escape.js index 7f4b87ed92cfab..c3c0421cc0c5b2 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-escape.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-escape.js @@ -79,6 +79,8 @@ function parseRegExp(regExpText) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow unnecessary escape characters", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-rename.js b/tools/node_modules/eslint/lib/rules/no-useless-rename.js index 83a03deb63022a..337f875b4564d8 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-rename.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-rename.js @@ -11,13 +11,17 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow renaming import, export, and destructured assignments to the same name", category: "ECMAScript 6", recommended: false, url: "https://eslint.org/docs/rules/no-useless-rename" }, + fixable: "code", + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/no-useless-return.js b/tools/node_modules/eslint/lib/rules/no-useless-return.js index b5b8ebc32a1e85..bb11b4b3619c8e 100644 --- a/tools/node_modules/eslint/lib/rules/no-useless-return.js +++ b/tools/node_modules/eslint/lib/rules/no-useless-return.js @@ -66,12 +66,15 @@ function isInFinally(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow redundant return statements", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/no-useless-return" }, + fixable: "code", schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/no-var.js b/tools/node_modules/eslint/lib/rules/no-var.js index 2c32a023dc9a81..edaed98f62e9d3 100644 --- a/tools/node_modules/eslint/lib/rules/no-var.js +++ b/tools/node_modules/eslint/lib/rules/no-var.js @@ -180,6 +180,8 @@ function hasReferenceInTDZ(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `let` or `const` instead of `var`", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/no-void.js b/tools/node_modules/eslint/lib/rules/no-void.js index 1d3d887da66873..d2b5d2f9631dff 100644 --- a/tools/node_modules/eslint/lib/rules/no-void.js +++ b/tools/node_modules/eslint/lib/rules/no-void.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `void` operators", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-warning-comments.js b/tools/node_modules/eslint/lib/rules/no-warning-comments.js index 5ff76e3a391138..9ea39b490f824d 100644 --- a/tools/node_modules/eslint/lib/rules/no-warning-comments.js +++ b/tools/node_modules/eslint/lib/rules/no-warning-comments.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow specified warning terms in comments", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js b/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js index 4b71a9ec17d99c..1ecc51db67c030 100644 --- a/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js +++ b/tools/node_modules/eslint/lib/rules/no-whitespace-before-property.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "disallow whitespace before properties", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/no-with.js b/tools/node_modules/eslint/lib/rules/no-with.js index d72dcdfb21e4d6..ecdf22c7d91d6a 100644 --- a/tools/node_modules/eslint/lib/rules/no-with.js +++ b/tools/node_modules/eslint/lib/rules/no-with.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `with` statements", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js b/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js index e447ef886b3c03..01763cea92f381 100644 --- a/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js +++ b/tools/node_modules/eslint/lib/rules/nonblock-statement-body-position.js @@ -12,13 +12,17 @@ const POSITION_SCHEMA = { enum: ["beside", "below", "any"] }; module.exports = { meta: { + type: "layout", + docs: { description: "enforce the location of single-line statements", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/nonblock-statement-body-position" }, + fixable: "whitespace", + schema: [ POSITION_SCHEMA, { diff --git a/tools/node_modules/eslint/lib/rules/object-curly-newline.js b/tools/node_modules/eslint/lib/rules/object-curly-newline.js index 494e78cff4aacb..c460ea56bc3128 100644 --- a/tools/node_modules/eslint/lib/rules/object-curly-newline.js +++ b/tools/node_modules/eslint/lib/rules/object-curly-newline.js @@ -134,13 +134,17 @@ function areLineBreaksRequired(node, options, first, last) { module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent line breaks inside braces", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/object-curly-newline" }, + fixable: "whitespace", + schema: [ { oneOf: [ diff --git a/tools/node_modules/eslint/lib/rules/object-curly-spacing.js b/tools/node_modules/eslint/lib/rules/object-curly-spacing.js index e7c847a6a9546e..bde4f14253eeec 100644 --- a/tools/node_modules/eslint/lib/rules/object-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/object-curly-spacing.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside braces", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/object-property-newline.js b/tools/node_modules/eslint/lib/rules/object-property-newline.js index 65baf0a95e37a7..3e2c0171577594 100644 --- a/tools/node_modules/eslint/lib/rules/object-property-newline.js +++ b/tools/node_modules/eslint/lib/rules/object-property-newline.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "enforce placing object properties on separate lines", category: "Stylistic Issues", @@ -38,8 +40,7 @@ module.exports = { create(context) { const allowSameLine = context.options[0] && ( - Boolean(context.options[0].allowAllPropertiesOnSameLine) || - Boolean(context.options[0].allowMultiplePropertiesPerLine) // Deprecated + (Boolean(context.options[0].allowAllPropertiesOnSameLine) || Boolean(context.options[0].allowMultiplePropertiesPerLine)) // Deprecated ); const errorMessage = allowSameLine ? "Object properties must go on a new line if they aren't all on the same line." diff --git a/tools/node_modules/eslint/lib/rules/object-shorthand.js b/tools/node_modules/eslint/lib/rules/object-shorthand.js index 21f039f8b6ed3a..ff6a51a4d1762a 100644 --- a/tools/node_modules/eslint/lib/rules/object-shorthand.js +++ b/tools/node_modules/eslint/lib/rules/object-shorthand.js @@ -24,6 +24,8 @@ const astUtils = require("../util/ast-utils"); //------------------------------------------------------------------------------ module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow method and property shorthand syntax for object literals", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js b/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js index e17529b6bed487..e7e40d66c0ced4 100644 --- a/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js +++ b/tools/node_modules/eslint/lib/rules/one-var-declaration-per-line.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow newlines around variable declarations", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/one-var.js b/tools/node_modules/eslint/lib/rules/one-var.js index 3efd0f27f7f301..44f05fb700a0d6 100644 --- a/tools/node_modules/eslint/lib/rules/one-var.js +++ b/tools/node_modules/eslint/lib/rules/one-var.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce variables to be declared either together or separately in functions", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/operator-assignment.js b/tools/node_modules/eslint/lib/rules/operator-assignment.js index 8e4b7025edab06..8bb01737dd62cd 100644 --- a/tools/node_modules/eslint/lib/rules/operator-assignment.js +++ b/tools/node_modules/eslint/lib/rules/operator-assignment.js @@ -89,6 +89,8 @@ function canBeFixed(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow assignment operator shorthand where possible", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/operator-linebreak.js b/tools/node_modules/eslint/lib/rules/operator-linebreak.js index be2709a1bdaae6..cd6e996b1b10bd 100644 --- a/tools/node_modules/eslint/lib/rules/operator-linebreak.js +++ b/tools/node_modules/eslint/lib/rules/operator-linebreak.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent linebreak style for operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/padded-blocks.js b/tools/node_modules/eslint/lib/rules/padded-blocks.js index 370d47bccff458..7c0b56ba7f8553 100644 --- a/tools/node_modules/eslint/lib/rules/padded-blocks.js +++ b/tools/node_modules/eslint/lib/rules/padded-blocks.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow padding within blocks", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js b/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js index 4af85fef015aad..3e55a2516d0156 100644 --- a/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js +++ b/tools/node_modules/eslint/lib/rules/padding-line-between-statements.js @@ -400,13 +400,17 @@ const StatementTypes = { module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow padding lines between statements", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/padding-line-between-statements" }, + fixable: "whitespace", + schema: { definitions: { paddingType: { diff --git a/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js b/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js index 1bc140b101bc06..b4bbf33f296ab8 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js +++ b/tools/node_modules/eslint/lib/rules/prefer-arrow-callback.js @@ -132,6 +132,8 @@ function hasDuplicateParams(paramsList) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require using arrow functions for callbacks", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/prefer-const.js b/tools/node_modules/eslint/lib/rules/prefer-const.js index 8b3bc5e0e436d3..a40ad353950df0 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-const.js +++ b/tools/node_modules/eslint/lib/rules/prefer-const.js @@ -330,6 +330,8 @@ function findUp(node, type, shouldStop) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require `const` declarations for variables that are never reassigned after declared", category: "ECMAScript 6", @@ -357,6 +359,8 @@ module.exports = { const shouldMatchAnyDestructuredVariable = options.destructuring !== "all"; const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true; const variables = []; + let reportCount = 0; + let name = ""; /** * Reports given identifier nodes if all of the nodes should be declared @@ -377,14 +381,41 @@ module.exports = { if (nodes.length && (shouldMatchAnyDestructuredVariable || nodesToReport.length === nodes.length)) { const varDeclParent = findUp(nodes[0], "VariableDeclaration", parentNode => parentNode.type.endsWith("Statement")); - const shouldFix = varDeclParent && + const isVarDecParentNull = varDeclParent === null; + + if (!isVarDecParentNull && varDeclParent.declarations.length > 0) { + const firstDeclaration = varDeclParent.declarations[0]; + + if (firstDeclaration.init) { + const firstDecParent = firstDeclaration.init.parent; + + /* + * First we check the declaration type and then depending on + * if the type is a "VariableDeclarator" or its an "ObjectPattern" + * we compare the name from the first identifier, if the names are different + * we assign the new name and reset the count of reportCount and nodeCount in + * order to check each block for the number of reported errors and base our fix + * based on comparing nodes.length and nodesToReport.length. + */ + + if (firstDecParent.type === "VariableDeclarator") { + + if (firstDecParent.id.name !== name) { + name = firstDecParent.id.name; + reportCount = 0; + } + + if (firstDecParent.id.type === "ObjectPattern") { + if (firstDecParent.init.name !== name) { + name = firstDecParent.init.name; + reportCount = 0; + } + } + } + } + } - /* - * If there are multiple variable declarations, like {let a = 1, b = 2}, then - * do not attempt to fix if one of the declarations should be `const`. It's - * too hard to know how the developer would want to automatically resolve the issue. - */ - varDeclParent.declarations.length === 1 && + let shouldFix = varDeclParent && // Don't do a fix unless the variable is initialized (or it's in a for-in or for-of loop) (varDeclParent.parent.type === "ForInStatement" || varDeclParent.parent.type === "ForOfStatement" || varDeclParent.declarations[0].init) && @@ -396,6 +427,21 @@ module.exports = { */ nodesToReport.length === nodes.length; + if (!isVarDecParentNull && varDeclParent.declarations && varDeclParent.declarations.length !== 1) { + + if (varDeclParent && varDeclParent.declarations && varDeclParent.declarations.length >= 1) { + + /* + * Add nodesToReport.length to a count, then comparing the count to the length + * of the declarations in the current block. + */ + + reportCount += nodesToReport.length; + + shouldFix = shouldFix && (reportCount === varDeclParent.declarations.length); + } + } + nodesToReport.forEach(node => { context.report({ node, diff --git a/tools/node_modules/eslint/lib/rules/prefer-destructuring.js b/tools/node_modules/eslint/lib/rules/prefer-destructuring.js index 112ea64613c6da..119fae560895e7 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-destructuring.js +++ b/tools/node_modules/eslint/lib/rules/prefer-destructuring.js @@ -10,12 +10,15 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require destructuring from arrays and/or objects", category: "ECMAScript 6", recommended: false, url: "https://eslint.org/docs/rules/prefer-destructuring" }, + schema: [ { diff --git a/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js b/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js index 051a91c81cb446..ca7358aa013bda 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js +++ b/tools/node_modules/eslint/lib/rules/prefer-numeric-literals.js @@ -38,6 +38,8 @@ function isParseInt(calleeNode) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow `parseInt()` and `Number.parseInt()` in favor of binary, octal, and hexadecimal literals", category: "ECMAScript 6", @@ -46,7 +48,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js index 8e54de2496a44f..a8dac696be0b70 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-object-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-object-spread.js @@ -212,6 +212,8 @@ function defineFixer(node, sourceCode) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow using Object.assign with an object literal as the first argument and prefer the use of object spread instead.", @@ -219,8 +221,10 @@ module.exports = { recommended: false, url: "https://eslint.org/docs/rules/prefer-object-spread" }, + schema: [], fixable: "code", + messages: { useSpreadMessage: "Use an object spread instead of `Object.assign` eg: `{ ...foo }`", useLiteralMessage: "Use an object literal instead of `Object.assign`. eg: `{ foo: bar }`" diff --git a/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js b/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js index e3d298a743caec..0db5ae874cfd9f 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js +++ b/tools/node_modules/eslint/lib/rules/prefer-promise-reject-errors.js @@ -12,13 +12,17 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require using Error objects as Promise rejection reasons", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/prefer-promise-reject-errors" }, + fixable: null, + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/prefer-reflect.js b/tools/node_modules/eslint/lib/rules/prefer-reflect.js index 765163e0eb3a14..796bbdf05fd446 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-reflect.js +++ b/tools/node_modules/eslint/lib/rules/prefer-reflect.js @@ -11,16 +11,19 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `Reflect` methods where applicable", category: "ECMAScript 6", recommended: false, - replacedBy: [], url: "https://eslint.org/docs/rules/prefer-reflect" }, deprecated: true, + replacedBy: [], + schema: [ { type: "object", diff --git a/tools/node_modules/eslint/lib/rules/prefer-rest-params.js b/tools/node_modules/eslint/lib/rules/prefer-rest-params.js index 133456e4d176cf..95a562c4a2f4de 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-rest-params.js +++ b/tools/node_modules/eslint/lib/rules/prefer-rest-params.js @@ -62,6 +62,8 @@ function isNotNormalMemberAccess(reference) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require rest parameters instead of `arguments`", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/prefer-spread.js b/tools/node_modules/eslint/lib/rules/prefer-spread.js index 9bf69c80f7b900..790fd3b82aab41 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-spread.js +++ b/tools/node_modules/eslint/lib/rules/prefer-spread.js @@ -49,6 +49,8 @@ function isValidThisArg(expectedThis, thisArg, context) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require spread operators instead of `.apply()`", category: "ECMAScript 6", @@ -57,7 +59,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/prefer-template.js b/tools/node_modules/eslint/lib/rules/prefer-template.js index 0471d61caef9f8..386674a92ef9c3 100644 --- a/tools/node_modules/eslint/lib/rules/prefer-template.js +++ b/tools/node_modules/eslint/lib/rules/prefer-template.js @@ -141,6 +141,8 @@ function endsWithTemplateCurly(node) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require template literals instead of string concatenation", category: "ECMAScript 6", @@ -149,7 +151,6 @@ module.exports = { }, schema: [], - fixable: "code" }, diff --git a/tools/node_modules/eslint/lib/rules/quote-props.js b/tools/node_modules/eslint/lib/rules/quote-props.js index 36739494da4058..7184bd34d35fd1 100644 --- a/tools/node_modules/eslint/lib/rules/quote-props.js +++ b/tools/node_modules/eslint/lib/rules/quote-props.js @@ -17,6 +17,8 @@ const espree = require("espree"), module.exports = { meta: { + type: "suggestion", + docs: { description: "require quotes around object literal property names", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/quotes.js b/tools/node_modules/eslint/lib/rules/quotes.js index 8dd61c3e3718b6..e0db17fcb7c45f 100644 --- a/tools/node_modules/eslint/lib/rules/quotes.js +++ b/tools/node_modules/eslint/lib/rules/quotes.js @@ -76,6 +76,8 @@ const AVOID_ESCAPE = "avoid-escape"; module.exports = { meta: { + type: "layout", + docs: { description: "enforce the consistent use of either backticks, double, or single quotes", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/radix.js b/tools/node_modules/eslint/lib/rules/radix.js index f71220beb4e5c6..5d3805d0a70679 100644 --- a/tools/node_modules/eslint/lib/rules/radix.js +++ b/tools/node_modules/eslint/lib/rules/radix.js @@ -78,6 +78,8 @@ function isDefaultRadix(radix) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the consistent use of the radix argument when using `parseInt()`", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/require-atomic-updates.js b/tools/node_modules/eslint/lib/rules/require-atomic-updates.js index c6cf0d74774002..e8dbe17b88dcd8 100644 --- a/tools/node_modules/eslint/lib/rules/require-atomic-updates.js +++ b/tools/node_modules/eslint/lib/rules/require-atomic-updates.js @@ -12,14 +12,18 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "problem", + docs: { description: "disallow assignments that can lead to race conditions due to usage of `await` or `yield`", category: "Possible Errors", recommended: false, url: "https://eslint.org/docs/rules/require-atomic-updates" }, + fixable: null, schema: [], + messages: { nonAtomicUpdate: "Possible race condition: `{{value}}` might be reassigned based on an outdated value of `{{value}}`." } diff --git a/tools/node_modules/eslint/lib/rules/require-await.js b/tools/node_modules/eslint/lib/rules/require-await.js index de39f372fd62ef..5e614c50251fed 100644 --- a/tools/node_modules/eslint/lib/rules/require-await.js +++ b/tools/node_modules/eslint/lib/rules/require-await.js @@ -31,12 +31,15 @@ function capitalizeFirstLetter(text) { module.exports = { meta: { + type: "suggestion", + docs: { description: "disallow async functions which have no `await` expression", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/require-await" }, + schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/require-jsdoc.js b/tools/node_modules/eslint/lib/rules/require-jsdoc.js index 91b90b7d10a381..949314993b64fb 100644 --- a/tools/node_modules/eslint/lib/rules/require-jsdoc.js +++ b/tools/node_modules/eslint/lib/rules/require-jsdoc.js @@ -6,6 +6,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require JSDoc comments", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js b/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js index 55ca4ff89a66b6..880405e9a25dbf 100644 --- a/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js +++ b/tools/node_modules/eslint/lib/rules/require-unicode-regexp.js @@ -22,15 +22,19 @@ const { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce the use of `u` flag on RegExp", category: "Best Practices", recommended: false, url: "https://eslint.org/docs/rules/require-unicode-regexp" }, + messages: { requireUFlag: "Use the 'u' flag." }, + schema: [] }, diff --git a/tools/node_modules/eslint/lib/rules/require-yield.js b/tools/node_modules/eslint/lib/rules/require-yield.js index 83a29876f0912a..7bb7cf9a872bd8 100644 --- a/tools/node_modules/eslint/lib/rules/require-yield.js +++ b/tools/node_modules/eslint/lib/rules/require-yield.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require generator functions to contain `yield`", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js b/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js index e87d881298bac2..04539395ef4ec1 100644 --- a/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js +++ b/tools/node_modules/eslint/lib/rules/rest-spread-spacing.js @@ -11,13 +11,17 @@ module.exports = { meta: { + type: "layout", + docs: { description: "enforce spacing between rest and spread operators and their expressions", category: "ECMAScript 6", recommended: false, url: "https://eslint.org/docs/rules/rest-spread-spacing" }, + fixable: "whitespace", + schema: [ { enum: ["always", "never"] diff --git a/tools/node_modules/eslint/lib/rules/semi-spacing.js b/tools/node_modules/eslint/lib/rules/semi-spacing.js index 75b53055a69bde..56ae687d8560a0 100644 --- a/tools/node_modules/eslint/lib/rules/semi-spacing.js +++ b/tools/node_modules/eslint/lib/rules/semi-spacing.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before and after semicolons", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/semi-style.js b/tools/node_modules/eslint/lib/rules/semi-style.js index 34899bb5444abc..dd76b68f82beac 100644 --- a/tools/node_modules/eslint/lib/rules/semi-style.js +++ b/tools/node_modules/eslint/lib/rules/semi-style.js @@ -65,12 +65,15 @@ function isLastChild(node) { module.exports = { meta: { + type: "layout", + docs: { description: "enforce location of semicolons", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/semi-style" }, + schema: [{ enum: ["last", "first"] }], fixable: "whitespace" }, diff --git a/tools/node_modules/eslint/lib/rules/semi.js b/tools/node_modules/eslint/lib/rules/semi.js index 129d106414defc..e8f4c959d4c7df 100644 --- a/tools/node_modules/eslint/lib/rules/semi.js +++ b/tools/node_modules/eslint/lib/rules/semi.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow semicolons instead of ASI", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/sort-imports.js b/tools/node_modules/eslint/lib/rules/sort-imports.js index 8735be5d307144..76997cc73d894b 100644 --- a/tools/node_modules/eslint/lib/rules/sort-imports.js +++ b/tools/node_modules/eslint/lib/rules/sort-imports.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce sorted import declarations within modules", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/sort-keys.js b/tools/node_modules/eslint/lib/rules/sort-keys.js index 6e538f73291179..0668e617d3c785 100644 --- a/tools/node_modules/eslint/lib/rules/sort-keys.js +++ b/tools/node_modules/eslint/lib/rules/sort-keys.js @@ -73,12 +73,15 @@ const isValidOrders = { module.exports = { meta: { + type: "suggestion", + docs: { description: "require object keys to be sorted", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/sort-keys" }, + schema: [ { enum: ["asc", "desc"] diff --git a/tools/node_modules/eslint/lib/rules/sort-vars.js b/tools/node_modules/eslint/lib/rules/sort-vars.js index 334deb0657f3ef..b6a2c86779c095 100644 --- a/tools/node_modules/eslint/lib/rules/sort-vars.js +++ b/tools/node_modules/eslint/lib/rules/sort-vars.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require variables within the same declaration block to be sorted", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-before-blocks.js b/tools/node_modules/eslint/lib/rules/space-before-blocks.js index 4f22ae6b65382d..872338effc29b3 100644 --- a/tools/node_modules/eslint/lib/rules/space-before-blocks.js +++ b/tools/node_modules/eslint/lib/rules/space-before-blocks.js @@ -13,6 +13,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before blocks", category: "Stylistic Issues", @@ -32,13 +34,13 @@ module.exports = { type: "object", properties: { keywords: { - enum: ["always", "never"] + enum: ["always", "never", "off"] }, functions: { - enum: ["always", "never"] + enum: ["always", "never", "off"] }, classes: { - enum: ["always", "never"] + enum: ["always", "never", "off"] } }, additionalProperties: false @@ -51,18 +53,27 @@ module.exports = { create(context) { const config = context.options[0], sourceCode = context.getSourceCode(); - let checkFunctions = true, - checkKeywords = true, - checkClasses = true; + let alwaysFunctions = true, + alwaysKeywords = true, + alwaysClasses = true, + neverFunctions = false, + neverKeywords = false, + neverClasses = false; if (typeof config === "object") { - checkFunctions = config.functions !== "never"; - checkKeywords = config.keywords !== "never"; - checkClasses = config.classes !== "never"; + alwaysFunctions = config.functions === "always"; + alwaysKeywords = config.keywords === "always"; + alwaysClasses = config.classes === "always"; + neverFunctions = config.functions === "never"; + neverKeywords = config.keywords === "never"; + neverClasses = config.classes === "never"; } else if (config === "never") { - checkFunctions = false; - checkKeywords = false; - checkClasses = false; + alwaysFunctions = false; + alwaysKeywords = false; + alwaysClasses = false; + neverFunctions = true; + neverKeywords = true; + neverClasses = true; } /** @@ -88,35 +99,35 @@ module.exports = { const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node); const parent = context.getAncestors().pop(); let requireSpace; + let requireNoSpace; if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") { - requireSpace = checkFunctions; + requireSpace = alwaysFunctions; + requireNoSpace = neverFunctions; } else if (node.type === "ClassBody") { - requireSpace = checkClasses; + requireSpace = alwaysClasses; + requireNoSpace = neverClasses; } else { - requireSpace = checkKeywords; + requireSpace = alwaysKeywords; + requireNoSpace = neverKeywords; } - if (requireSpace) { - if (!hasSpace) { - context.report({ - node, - message: "Missing space before opening brace.", - fix(fixer) { - return fixer.insertTextBefore(node, " "); - } - }); - } - } else { - if (hasSpace) { - context.report({ - node, - message: "Unexpected space before opening brace.", - fix(fixer) { - return fixer.removeRange([precedingToken.range[1], node.range[0]]); - } - }); - } + if (requireSpace && !hasSpace) { + context.report({ + node, + message: "Missing space before opening brace.", + fix(fixer) { + return fixer.insertTextBefore(node, " "); + } + }); + } else if (requireNoSpace && hasSpace) { + context.report({ + node, + message: "Unexpected space before opening brace.", + fix(fixer) { + return fixer.removeRange([precedingToken.range[1], node.range[0]]); + } + }); } } } diff --git a/tools/node_modules/eslint/lib/rules/space-before-function-paren.js b/tools/node_modules/eslint/lib/rules/space-before-function-paren.js index 81697d64f1f1f8..64ba72bf9ead29 100644 --- a/tools/node_modules/eslint/lib/rules/space-before-function-paren.js +++ b/tools/node_modules/eslint/lib/rules/space-before-function-paren.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before `function` definition opening parenthesis", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-in-parens.js b/tools/node_modules/eslint/lib/rules/space-in-parens.js index aa1374380342a5..88f4f0b50e150d 100644 --- a/tools/node_modules/eslint/lib/rules/space-in-parens.js +++ b/tools/node_modules/eslint/lib/rules/space-in-parens.js @@ -12,6 +12,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing inside parentheses", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-infix-ops.js b/tools/node_modules/eslint/lib/rules/space-infix-ops.js index 17b49cc1184ca1..45b76795eae14e 100644 --- a/tools/node_modules/eslint/lib/rules/space-infix-ops.js +++ b/tools/node_modules/eslint/lib/rules/space-infix-ops.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require spacing around infix operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/space-unary-ops.js b/tools/node_modules/eslint/lib/rules/space-unary-ops.js index 5032b46c3b05c8..b56fa4f2fac396 100644 --- a/tools/node_modules/eslint/lib/rules/space-unary-ops.js +++ b/tools/node_modules/eslint/lib/rules/space-unary-ops.js @@ -16,6 +16,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce consistent spacing before or after unary operators", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/spaced-comment.js b/tools/node_modules/eslint/lib/rules/spaced-comment.js index 6fbe2aac790ff4..d4c86d27cf8fc7 100644 --- a/tools/node_modules/eslint/lib/rules/spaced-comment.js +++ b/tools/node_modules/eslint/lib/rules/spaced-comment.js @@ -151,6 +151,8 @@ function createNeverStylePattern(markers) { module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce consistent spacing after the `//` or `/*` in a comment", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/strict.js b/tools/node_modules/eslint/lib/rules/strict.js index 8b5757738de09c..bec1baf4653961 100644 --- a/tools/node_modules/eslint/lib/rules/strict.js +++ b/tools/node_modules/eslint/lib/rules/strict.js @@ -80,6 +80,8 @@ function isSimpleParameterList(params) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow strict mode directives", category: "Strict Mode", diff --git a/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js b/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js index 23dfff6133d3a6..e94b3292106ddf 100644 --- a/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js +++ b/tools/node_modules/eslint/lib/rules/switch-colon-spacing.js @@ -17,12 +17,15 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "enforce spacing around colons of switch statements", category: "Stylistic Issues", recommended: false, url: "https://eslint.org/docs/rules/switch-colon-spacing" }, + schema: [ { type: "object", @@ -33,6 +36,7 @@ module.exports = { additionalProperties: false } ], + fixable: "whitespace" }, diff --git a/tools/node_modules/eslint/lib/rules/symbol-description.js b/tools/node_modules/eslint/lib/rules/symbol-description.js index 271012b5429d48..7bb4e2dec699d4 100644 --- a/tools/node_modules/eslint/lib/rules/symbol-description.js +++ b/tools/node_modules/eslint/lib/rules/symbol-description.js @@ -18,6 +18,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "suggestion", + docs: { description: "require symbol descriptions", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js index 6702d730cd37e8..ea801cbe5d2ea9 100644 --- a/tools/node_modules/eslint/lib/rules/template-curly-spacing.js +++ b/tools/node_modules/eslint/lib/rules/template-curly-spacing.js @@ -24,6 +24,8 @@ const CLOSE_PAREN = /^\}/; module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing around embedded expressions of template strings", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/template-tag-spacing.js b/tools/node_modules/eslint/lib/rules/template-tag-spacing.js index aee7ac108be16c..f258cde3d88e09 100644 --- a/tools/node_modules/eslint/lib/rules/template-tag-spacing.js +++ b/tools/node_modules/eslint/lib/rules/template-tag-spacing.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing between template tags and their literals", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/unicode-bom.js b/tools/node_modules/eslint/lib/rules/unicode-bom.js index 03b2d5ae68e463..20f48e22b3c6b2 100644 --- a/tools/node_modules/eslint/lib/rules/unicode-bom.js +++ b/tools/node_modules/eslint/lib/rules/unicode-bom.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow Unicode byte order mark (BOM)", category: "Stylistic Issues", diff --git a/tools/node_modules/eslint/lib/rules/use-isnan.js b/tools/node_modules/eslint/lib/rules/use-isnan.js index 5bad5b3c6ddb5b..343ca0454441e4 100644 --- a/tools/node_modules/eslint/lib/rules/use-isnan.js +++ b/tools/node_modules/eslint/lib/rules/use-isnan.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "require calls to `isNaN()` when checking for `NaN`", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/valid-jsdoc.js b/tools/node_modules/eslint/lib/rules/valid-jsdoc.js index 42d66a8a79b518..b434491bfad873 100644 --- a/tools/node_modules/eslint/lib/rules/valid-jsdoc.js +++ b/tools/node_modules/eslint/lib/rules/valid-jsdoc.js @@ -16,6 +16,8 @@ const doctrine = require("doctrine"); module.exports = { meta: { + type: "suggestion", + docs: { description: "enforce valid JSDoc comments", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/valid-typeof.js b/tools/node_modules/eslint/lib/rules/valid-typeof.js index ac4e74f20ba6c5..e3245e8f306ca9 100644 --- a/tools/node_modules/eslint/lib/rules/valid-typeof.js +++ b/tools/node_modules/eslint/lib/rules/valid-typeof.js @@ -10,6 +10,8 @@ module.exports = { meta: { + type: "problem", + docs: { description: "enforce comparing `typeof` expressions against valid strings", category: "Possible Errors", diff --git a/tools/node_modules/eslint/lib/rules/vars-on-top.js b/tools/node_modules/eslint/lib/rules/vars-on-top.js index 0489aa61fcc232..d69c223388f05f 100644 --- a/tools/node_modules/eslint/lib/rules/vars-on-top.js +++ b/tools/node_modules/eslint/lib/rules/vars-on-top.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "suggestion", + docs: { description: "require `var` declarations be placed at the top of their containing scope", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/wrap-iife.js b/tools/node_modules/eslint/lib/rules/wrap-iife.js index d006d30a0042fb..ce272235b4f035 100644 --- a/tools/node_modules/eslint/lib/rules/wrap-iife.js +++ b/tools/node_modules/eslint/lib/rules/wrap-iife.js @@ -17,6 +17,8 @@ const astUtils = require("../util/ast-utils"); module.exports = { meta: { + type: "layout", + docs: { description: "require parentheses around immediate `function` invocations", category: "Best Practices", diff --git a/tools/node_modules/eslint/lib/rules/wrap-regex.js b/tools/node_modules/eslint/lib/rules/wrap-regex.js index 1816e0e9e64e19..4ecbcecbbeb0b3 100644 --- a/tools/node_modules/eslint/lib/rules/wrap-regex.js +++ b/tools/node_modules/eslint/lib/rules/wrap-regex.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require parenthesis around regex literals", category: "Stylistic Issues", @@ -19,8 +21,8 @@ module.exports = { }, schema: [], - fixable: "code", + messages: { requireParens: "Wrap the regexp literal in parens to disambiguate the slash." } diff --git a/tools/node_modules/eslint/lib/rules/yield-star-spacing.js b/tools/node_modules/eslint/lib/rules/yield-star-spacing.js index 33a37f0d991577..e7712a51dbf7e7 100644 --- a/tools/node_modules/eslint/lib/rules/yield-star-spacing.js +++ b/tools/node_modules/eslint/lib/rules/yield-star-spacing.js @@ -11,6 +11,8 @@ module.exports = { meta: { + type: "layout", + docs: { description: "require or disallow spacing around the `*` in `yield*` expressions", category: "ECMAScript 6", diff --git a/tools/node_modules/eslint/lib/rules/yoda.js b/tools/node_modules/eslint/lib/rules/yoda.js index 35368dd4df9780..8789c001ef933e 100644 --- a/tools/node_modules/eslint/lib/rules/yoda.js +++ b/tools/node_modules/eslint/lib/rules/yoda.js @@ -152,6 +152,8 @@ function same(a, b) { module.exports = { meta: { + type: "suggestion", + docs: { description: "require or disallow \"Yoda\" conditions", category: "Best Practices", diff --git a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js index 922ff0c9fc9c1b..9f2447cff5cb7e 100644 --- a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js +++ b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js @@ -445,6 +445,8 @@ var SCOPE_ASYNC = 4; var SCOPE_GENERATOR = 8; var SCOPE_ARROW = 16; var SCOPE_SIMPLE_CATCH = 32; +var SCOPE_SUPER = 64; +var SCOPE_DIRECT_SUPER = 128; function functionFlags(async, generator) { return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0) @@ -540,7 +542,7 @@ var Parser = function Parser(options, input, startPos) { this.regexpState = null; }; -var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true } }; +var prototypeAccessors = { inFunction: { configurable: true },inGenerator: { configurable: true },inAsync: { configurable: true },allowSuper: { configurable: true },allowDirectSuper: { configurable: true } }; Parser.prototype.parse = function parse () { var node = this.options.program || this.startNode(); @@ -551,6 +553,11 @@ Parser.prototype.parse = function parse () { prototypeAccessors.inFunction.get = function () { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }; prototypeAccessors.inGenerator.get = function () { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }; prototypeAccessors.inAsync.get = function () { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }; +prototypeAccessors.allowSuper.get = function () { return (this.currentThisScope().flags & SCOPE_SUPER) > 0 }; +prototypeAccessors.allowDirectSuper.get = function () { return (this.currentThisScope().flags & SCOPE_DIRECT_SUPER) > 0 }; + +// Switch to a getter for 7.0.0. +Parser.prototype.inNonArrowFunction = function inNonArrowFunction () { return (this.currentThisScope().flags & SCOPE_FUNCTION) > 0 }; Parser.extend = function extend () { var plugins = [], len = arguments.length; @@ -1266,7 +1273,7 @@ pp$1.parseClass = function(node, isStatement) { classBody.body = []; this.expect(types.braceL); while (!this.eat(types.braceR)) { - var element = this$1.parseClassElement(); + var element = this$1.parseClassElement(node.superClass !== null); if (element) { classBody.body.push(element); if (element.type === "MethodDefinition" && element.kind === "constructor") { @@ -1279,7 +1286,7 @@ pp$1.parseClass = function(node, isStatement) { return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression") }; -pp$1.parseClassElement = function() { +pp$1.parseClassElement = function(constructorAllowsSuper) { var this$1 = this; if (this.eat(types.semi)) { return null } @@ -1315,16 +1322,18 @@ pp$1.parseClassElement = function() { } if (!method.key) { this.parsePropertyName(method); } var key = method.key; + var allowsDirectSuper = false; if (!method.computed && !method.static && (key.type === "Identifier" && key.name === "constructor" || key.type === "Literal" && key.value === "constructor")) { if (method.kind !== "method") { this.raise(key.start, "Constructor can't have get/set modifier"); } if (isGenerator) { this.raise(key.start, "Constructor can't be a generator"); } if (isAsync) { this.raise(key.start, "Constructor can't be an async method"); } method.kind = "constructor"; + allowsDirectSuper = constructorAllowsSuper; } else if (method.static && key.type === "Identifier" && key.name === "prototype") { this.raise(key.start, "Classes may not have a static property named prototype"); } - this.parseClassMethod(method, isGenerator, isAsync); + this.parseClassMethod(method, isGenerator, isAsync, allowsDirectSuper); if (method.kind === "get" && method.value.params.length !== 0) { this.raiseRecoverable(method.value.start, "getter should have no params"); } if (method.kind === "set" && method.value.params.length !== 1) @@ -1334,8 +1343,8 @@ pp$1.parseClassElement = function() { return method }; -pp$1.parseClassMethod = function(method, isGenerator, isAsync) { - method.value = this.parseMethod(isGenerator, isAsync); +pp$1.parseClassMethod = function(method, isGenerator, isAsync, allowsDirectSuper) { + method.value = this.parseMethod(isGenerator, isAsync, allowsDirectSuper); return this.finishNode(method, "MethodDefinition") }; @@ -2122,13 +2131,19 @@ pp$3.parseSubscripts = function(base, startPos, startLoc, noCalls) { // or `{}`. pp$3.parseExprAtom = function(refDestructuringErrors) { + // If a division operator appears in an expression position, the + // tokenizer got confused, and we force it to read a regexp instead. + if (this.type === types.slash) { this.readRegexp(); } + var node, canBeArrow = this.potentialArrowAt === this.start; switch (this.type) { case types._super: - if (!this.inFunction) - { this.raise(this.start, "'super' outside of function or class"); } + if (!this.allowSuper) + { this.raise(this.start, "'super' keyword outside a method"); } node = this.startNode(); this.next(); + if (this.type === types.parenL && !this.allowDirectSuper) + { this.raise(node.start, "super() call outside constructor of a subclass"); } // The `super` keyword can appear at below: // SuperProperty: // super [ Expression ] @@ -2524,7 +2539,7 @@ pp$3.initFunction = function(node) { // Parse object or class method. -pp$3.parseMethod = function(isGenerator, isAsync) { +pp$3.parseMethod = function(isGenerator, isAsync, allowDirectSuper) { var node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos; this.initFunction(node); @@ -2535,7 +2550,7 @@ pp$3.parseMethod = function(isGenerator, isAsync) { this.yieldPos = 0; this.awaitPos = 0; - this.enterScope(functionFlags(isAsync, node.generator)); + this.enterScope(functionFlags(isAsync, node.generator) | SCOPE_SUPER | (allowDirectSuper ? SCOPE_DIRECT_SUPER : 0)); this.expect(types.parenL); node.params = this.parseBindingList(types.parenR, false, this.options.ecmaVersion >= 8); @@ -2823,12 +2838,14 @@ pp$5.currentVarScope = function() { } }; -pp$5.inNonArrowFunction = function() { +// Could be useful for `this`, `new.target`, `super()`, `super.property`, and `super[property]`. +pp$5.currentThisScope = function() { var this$1 = this; - for (var i = this.scopeStack.length - 1; i >= 0; i--) - { if (this$1.scopeStack[i].flags & SCOPE_FUNCTION && !(this$1.scopeStack[i].flags & SCOPE_ARROW)) { return true } } - return false + for (var i = this.scopeStack.length - 1;; i--) { + var scope = this$1.scopeStack[i]; + if (scope.flags & SCOPE_VAR && !(scope.flags & SCOPE_ARROW)) { return scope } + } }; var Node = function Node(parser, pos, loc) { @@ -2924,7 +2941,7 @@ pp$7.braceIsBlock = function(prevType) { { return true } if (prevType === types.braceL) { return parent === types$1.b_stat } - if (prevType === types._var || prevType === types.name) + if (prevType === types._var || prevType === types._const || prevType === types.name) { return false } return !this.exprAllowed }; @@ -2986,6 +3003,7 @@ types.incDec.updateContext = function() { types._function.updateContext = types._class.updateContext = function(prevType) { if (prevType.beforeExpr && prevType !== types.semi && prevType !== types._else && + !(prevType === types._return && lineBreak.test(this.input.slice(this.lastTokEnd, this.start))) && !((prevType === types.colon || prevType === types.braceL) && this.curContext() === types$1.b_stat)) { this.context.push(types$1.f_expr); } else @@ -5257,7 +5275,7 @@ pp$8.readWord = function() { // // [walk]: util/walk.js -var version = "6.0.2"; +var version = "6.0.4"; // The main exported interface (under `self.acorn` when in the // browser) is a `parse` function that takes a code string and diff --git a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map index 57c8681c2eac8e..9cd41ec074e110 100644 --- a/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map +++ b/tools/node_modules/eslint/node_modules/acorn/dist/acorn.js.map @@ -1 +1 @@ -{"version":3,"file":"acorn.js","sources":["../src/identifier.js","../src/tokentype.js","../src/whitespace.js","../src/util.js","../src/locutil.js","../src/options.js","../src/scopeflags.js","../src/state.js","../src/parseutil.js","../src/statement.js","../src/lval.js","../src/expression.js","../src/location.js","../src/scope.js","../src/node.js","../src/tokencontext.js","../src/unicode-property-data.js","../src/regexp.js","../src/tokenize.js","../src/index.js"],"sourcesContent":["// Reserved word lists for various dialects of the language\n\nexport const reservedWords = {\n 3: \"abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile\",\n 5: \"class enum extends super const export import\",\n 6: \"enum\",\n strict: \"implements interface let package private protected public static yield\",\n strictBind: \"eval arguments\"\n}\n\n// And the keywords\n\nconst ecma5AndLessKeywords = \"break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this\"\n\nexport const keywords = {\n 5: ecma5AndLessKeywords,\n 6: ecma5AndLessKeywords + \" const class extends export import super\"\n}\n\nexport const keywordRelationalOperator = /^in(stanceof)?$/\n\n// ## Character categories\n\n// Big ugly regular expressions that match characters in the\n// whitespace, identifier, and identifier-start categories. These\n// are only applied when a character is found to actually have a\n// code point above 128.\n// Generated by `bin/generate-identifier-regex.js`.\n\nlet nonASCIIidentifierStartChars = \"\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u037f\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u052f\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05d0-\\u05ea\\u05ef-\\u05f2\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086a\\u08a0-\\u08b4\\u08b6-\\u08bd\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u09fc\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0af9\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c39\\u0c3d\\u0c58-\\u0c5a\\u0c60\\u0c61\\u0c80\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d54-\\u0d56\\u0d5f-\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0e01-\\u0e30\\u0e32\\u0e33\\u0e40-\\u0e46\\u0e81\\u0e82\\u0e84\\u0e87\\u0e88\\u0e8a\\u0e8d\\u0e94-\\u0e97\\u0e99-\\u0e9f\\u0ea1-\\u0ea3\\u0ea5\\u0ea7\\u0eaa\\u0eab\\u0ead-\\u0eb0\\u0eb2\\u0eb3\\u0ebd\\u0ec0-\\u0ec4\\u0ec6\\u0edc-\\u0edf\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u1000-\\u102a\\u103f\\u1050-\\u1055\\u105a-\\u105d\\u1061\\u1065\\u1066\\u106e-\\u1070\\u1075-\\u1081\\u108e\\u10a0-\\u10c5\\u10c7\\u10cd\\u10d0-\\u10fa\\u10fc-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f5\\u13f8-\\u13fd\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f8\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1780-\\u17b3\\u17d7\\u17dc\\u1820-\\u1878\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191e\\u1950-\\u196d\\u1970-\\u1974\\u1980-\\u19ab\\u19b0-\\u19c9\\u1a00-\\u1a16\\u1a20-\\u1a54\\u1aa7\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bba-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1c80-\\u1c88\\u1c90-\\u1cba\\u1cbd-\\u1cbf\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1cf5\\u1cf6\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2118-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2cf2\\u2cf3\\u2d00-\\u2d25\\u2d27\\u2d2d\\u2d30-\\u2d67\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303c\\u3041-\\u3096\\u309b-\\u309f\\u30a1-\\u30fa\\u30fc-\\u30ff\\u3105-\\u312f\\u3131-\\u318e\\u31a0-\\u31ba\\u31f0-\\u31ff\\u3400-\\u4db5\\u4e00-\\u9fef\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua69d\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua7b9\\ua7f7-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua8fd\\ua8fe\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\ua9e0-\\ua9e4\\ua9e6-\\ua9ef\\ua9fa-\\ua9fe\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uaa60-\\uaa76\\uaa7a\\uaa7e-\\uaaaf\\uaab1\\uaab5\\uaab6\\uaab9-\\uaabd\\uaac0\\uaac2\\uaadb-\\uaadd\\uaae0-\\uaaea\\uaaf2-\\uaaf4\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uab30-\\uab5a\\uab5c-\\uab65\\uab70-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\uf900-\\ufa6d\\ufa70-\\ufad9\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uff66-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc\"\nlet nonASCIIidentifierChars = \"\\u200c\\u200d\\xb7\\u0300-\\u036f\\u0387\\u0483-\\u0487\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u0669\\u0670\\u06d6-\\u06dc\\u06df-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u06f0-\\u06f9\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07c0-\\u07c9\\u07eb-\\u07f3\\u07fd\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0859-\\u085b\\u08d3-\\u08e1\\u08e3-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962\\u0963\\u0966-\\u096f\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09cb-\\u09cd\\u09d7\\u09e2\\u09e3\\u09e6-\\u09ef\\u09fe\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a66-\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2\\u0ae3\\u0ae6-\\u0aef\\u0afa-\\u0aff\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b66-\\u0b6f\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0be6-\\u0bef\\u0c00-\\u0c04\\u0c3e-\\u0c44\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0c66-\\u0c6f\\u0c81-\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0ce6-\\u0cef\\u0d00-\\u0d03\\u0d3b\\u0d3c\\u0d3e-\\u0d44\\u0d46-\\u0d48\\u0d4a-\\u0d4d\\u0d57\\u0d62\\u0d63\\u0d66-\\u0d6f\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0de6-\\u0def\\u0df2\\u0df3\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0e50-\\u0e59\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0ed0-\\u0ed9\\u0f18\\u0f19\\u0f20-\\u0f29\\u0f35\\u0f37\\u0f39\\u0f3e\\u0f3f\\u0f71-\\u0f84\\u0f86\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102b-\\u103e\\u1040-\\u1049\\u1056-\\u1059\\u105e-\\u1060\\u1062-\\u1064\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f-\\u109d\\u135d-\\u135f\\u1369-\\u1371\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b4-\\u17d3\\u17dd\\u17e0-\\u17e9\\u180b-\\u180d\\u1810-\\u1819\\u18a9\\u1920-\\u192b\\u1930-\\u193b\\u1946-\\u194f\\u19d0-\\u19da\\u1a17-\\u1a1b\\u1a55-\\u1a5e\\u1a60-\\u1a7c\\u1a7f-\\u1a89\\u1a90-\\u1a99\\u1ab0-\\u1abd\\u1b00-\\u1b04\\u1b34-\\u1b44\\u1b50-\\u1b59\\u1b6b-\\u1b73\\u1b80-\\u1b82\\u1ba1-\\u1bad\\u1bb0-\\u1bb9\\u1be6-\\u1bf3\\u1c24-\\u1c37\\u1c40-\\u1c49\\u1c50-\\u1c59\\u1cd0-\\u1cd2\\u1cd4-\\u1ce8\\u1ced\\u1cf2-\\u1cf4\\u1cf7-\\u1cf9\\u1dc0-\\u1df9\\u1dfb-\\u1dff\\u203f\\u2040\\u2054\\u20d0-\\u20dc\\u20e1\\u20e5-\\u20f0\\u2cef-\\u2cf1\\u2d7f\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua620-\\ua629\\ua66f\\ua674-\\ua67d\\ua69e\\ua69f\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua823-\\ua827\\ua880\\ua881\\ua8b4-\\ua8c5\\ua8d0-\\ua8d9\\ua8e0-\\ua8f1\\ua8ff-\\ua909\\ua926-\\ua92d\\ua947-\\ua953\\ua980-\\ua983\\ua9b3-\\ua9c0\\ua9d0-\\ua9d9\\ua9e5\\ua9f0-\\ua9f9\\uaa29-\\uaa36\\uaa43\\uaa4c\\uaa4d\\uaa50-\\uaa59\\uaa7b-\\uaa7d\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uaaeb-\\uaaef\\uaaf5\\uaaf6\\uabe3-\\uabea\\uabec\\uabed\\uabf0-\\uabf9\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe2f\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff10-\\uff19\\uff3f\"\n\nconst nonASCIIidentifierStart = new RegExp(\"[\" + nonASCIIidentifierStartChars + \"]\")\nconst nonASCIIidentifier = new RegExp(\"[\" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + \"]\")\n\nnonASCIIidentifierStartChars = nonASCIIidentifierChars = null\n\n// These are a run-length and offset encoded representation of the\n// >0xffff code points that are a valid part of identifiers. The\n// offset starts at 0x10000, and each pair of numbers represents an\n// offset to the next range, and then a size of the range. They were\n// generated by bin/generate-identifier-regex.js\n\n// eslint-disable-next-line comma-spacing\nconst astralIdentifierStartCodes = [0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,157,310,10,21,11,7,153,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,477,28,11,0,9,21,190,52,76,44,33,24,27,35,30,0,12,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,85,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,159,52,19,3,54,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,86,26,230,43,117,63,32,0,257,0,11,39,8,0,22,0,12,39,3,3,20,0,35,56,264,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,270,921,103,110,18,195,2749,1070,4050,582,8634,568,8,30,114,29,19,47,17,3,32,20,6,18,689,63,129,68,12,0,67,12,65,1,31,6129,15,754,9486,286,82,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,4149,196,60,67,1213,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42710,42,4148,12,221,3,5761,15,7472,3104,541]\n\n// eslint-disable-next-line comma-spacing\nconst astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,525,10,176,2,54,14,32,9,16,3,46,10,54,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,4,9,83,11,7,0,161,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,193,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,84,14,5,9,243,14,166,9,280,9,41,6,2,3,9,0,10,10,47,15,406,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,19306,9,135,4,60,6,26,9,1016,45,17,3,19723,1,5319,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,2214,6,110,6,6,9,792487,239]\n\n// This has a complexity linear to the value of the code. The\n// assumption is that looking up astral identifier characters is\n// rare.\nfunction isInAstralSet(code, set) {\n let pos = 0x10000\n for (let i = 0; i < set.length; i += 2) {\n pos += set[i]\n if (pos > code) return false\n pos += set[i + 1]\n if (pos >= code) return true\n }\n}\n\n// Test whether a given character code starts an identifier.\n\nexport function isIdentifierStart(code, astral) {\n if (code < 65) return code === 36\n if (code < 91) return true\n if (code < 97) return code === 95\n if (code < 123) return true\n if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code))\n if (astral === false) return false\n return isInAstralSet(code, astralIdentifierStartCodes)\n}\n\n// Test whether a given character is part of an identifier.\n\nexport function isIdentifierChar(code, astral) {\n if (code < 48) return code === 36\n if (code < 58) return true\n if (code < 65) return false\n if (code < 91) return true\n if (code < 97) return code === 95\n if (code < 123) return true\n if (code <= 0xffff) return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code))\n if (astral === false) return false\n return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes)\n}\n","// ## Token types\n\n// The assignment of fine-grained, information-carrying type objects\n// allows the tokenizer to store the information it has about a\n// token in a way that is very cheap for the parser to look up.\n\n// All token type variables start with an underscore, to make them\n// easy to recognize.\n\n// The `beforeExpr` property is used to disambiguate between regular\n// expressions and divisions. It is set on all token types that can\n// be followed by an expression (thus, a slash after them would be a\n// regular expression).\n//\n// The `startsExpr` property is used to check if the token ends a\n// `yield` expression. It is set on all token types that either can\n// directly start an expression (like a quotation mark) or can\n// continue an expression (like the body of a string).\n//\n// `isLoop` marks a keyword as starting a loop, which is important\n// to know when parsing a label, in order to allow or disallow\n// continue jumps to that label.\n\nexport class TokenType {\n constructor(label, conf = {}) {\n this.label = label\n this.keyword = conf.keyword\n this.beforeExpr = !!conf.beforeExpr\n this.startsExpr = !!conf.startsExpr\n this.isLoop = !!conf.isLoop\n this.isAssign = !!conf.isAssign\n this.prefix = !!conf.prefix\n this.postfix = !!conf.postfix\n this.binop = conf.binop || null\n this.updateContext = null\n }\n}\n\nfunction binop(name, prec) {\n return new TokenType(name, {beforeExpr: true, binop: prec})\n}\nconst beforeExpr = {beforeExpr: true}, startsExpr = {startsExpr: true}\n\n// Map keyword names to token types.\n\nexport const keywords = {}\n\n// Succinct definitions of keyword token types\nfunction kw(name, options = {}) {\n options.keyword = name\n return keywords[name] = new TokenType(name, options)\n}\n\nexport const types = {\n num: new TokenType(\"num\", startsExpr),\n regexp: new TokenType(\"regexp\", startsExpr),\n string: new TokenType(\"string\", startsExpr),\n name: new TokenType(\"name\", startsExpr),\n eof: new TokenType(\"eof\"),\n\n // Punctuation token types.\n bracketL: new TokenType(\"[\", {beforeExpr: true, startsExpr: true}),\n bracketR: new TokenType(\"]\"),\n braceL: new TokenType(\"{\", {beforeExpr: true, startsExpr: true}),\n braceR: new TokenType(\"}\"),\n parenL: new TokenType(\"(\", {beforeExpr: true, startsExpr: true}),\n parenR: new TokenType(\")\"),\n comma: new TokenType(\",\", beforeExpr),\n semi: new TokenType(\";\", beforeExpr),\n colon: new TokenType(\":\", beforeExpr),\n dot: new TokenType(\".\"),\n question: new TokenType(\"?\", beforeExpr),\n arrow: new TokenType(\"=>\", beforeExpr),\n template: new TokenType(\"template\"),\n invalidTemplate: new TokenType(\"invalidTemplate\"),\n ellipsis: new TokenType(\"...\", beforeExpr),\n backQuote: new TokenType(\"`\", startsExpr),\n dollarBraceL: new TokenType(\"${\", {beforeExpr: true, startsExpr: true}),\n\n // Operators. These carry several kinds of properties to help the\n // parser use them properly (the presence of these properties is\n // what categorizes them as operators).\n //\n // `binop`, when present, specifies that this operator is a binary\n // operator, and will refer to its precedence.\n //\n // `prefix` and `postfix` mark the operator as a prefix or postfix\n // unary operator.\n //\n // `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as\n // binary operators with a very low precedence, that should result\n // in AssignmentExpression nodes.\n\n eq: new TokenType(\"=\", {beforeExpr: true, isAssign: true}),\n assign: new TokenType(\"_=\", {beforeExpr: true, isAssign: true}),\n incDec: new TokenType(\"++/--\", {prefix: true, postfix: true, startsExpr: true}),\n prefix: new TokenType(\"!/~\", {beforeExpr: true, prefix: true, startsExpr: true}),\n logicalOR: binop(\"||\", 1),\n logicalAND: binop(\"&&\", 2),\n bitwiseOR: binop(\"|\", 3),\n bitwiseXOR: binop(\"^\", 4),\n bitwiseAND: binop(\"&\", 5),\n equality: binop(\"==/!=/===/!==\", 6),\n relational: binop(\"/<=/>=\", 7),\n bitShift: binop(\"<>/>>>\", 8),\n plusMin: new TokenType(\"+/-\", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}),\n modulo: binop(\"%\", 10),\n star: binop(\"*\", 10),\n slash: binop(\"/\", 10),\n starstar: new TokenType(\"**\", {beforeExpr: true}),\n\n // Keyword token types.\n _break: kw(\"break\"),\n _case: kw(\"case\", beforeExpr),\n _catch: kw(\"catch\"),\n _continue: kw(\"continue\"),\n _debugger: kw(\"debugger\"),\n _default: kw(\"default\", beforeExpr),\n _do: kw(\"do\", {isLoop: true, beforeExpr: true}),\n _else: kw(\"else\", beforeExpr),\n _finally: kw(\"finally\"),\n _for: kw(\"for\", {isLoop: true}),\n _function: kw(\"function\", startsExpr),\n _if: kw(\"if\"),\n _return: kw(\"return\", beforeExpr),\n _switch: kw(\"switch\"),\n _throw: kw(\"throw\", beforeExpr),\n _try: kw(\"try\"),\n _var: kw(\"var\"),\n _const: kw(\"const\"),\n _while: kw(\"while\", {isLoop: true}),\n _with: kw(\"with\"),\n _new: kw(\"new\", {beforeExpr: true, startsExpr: true}),\n _this: kw(\"this\", startsExpr),\n _super: kw(\"super\", startsExpr),\n _class: kw(\"class\", startsExpr),\n _extends: kw(\"extends\", beforeExpr),\n _export: kw(\"export\"),\n _import: kw(\"import\"),\n _null: kw(\"null\", startsExpr),\n _true: kw(\"true\", startsExpr),\n _false: kw(\"false\", startsExpr),\n _in: kw(\"in\", {beforeExpr: true, binop: 7}),\n _instanceof: kw(\"instanceof\", {beforeExpr: true, binop: 7}),\n _typeof: kw(\"typeof\", {beforeExpr: true, prefix: true, startsExpr: true}),\n _void: kw(\"void\", {beforeExpr: true, prefix: true, startsExpr: true}),\n _delete: kw(\"delete\", {beforeExpr: true, prefix: true, startsExpr: true})\n}\n","// Matches a whole line break (where CRLF is considered a single\n// line break). Used to count lines.\n\nexport const lineBreak = /\\r\\n?|\\n|\\u2028|\\u2029/\nexport const lineBreakG = new RegExp(lineBreak.source, \"g\")\n\nexport function isNewLine(code, ecma2019String) {\n return code === 10 || code === 13 || (!ecma2019String && (code === 0x2028 || code === 0x2029))\n}\n\nexport const nonASCIIwhitespace = /[\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]/\n\nexport const skipWhiteSpace = /(?:\\s|\\/\\/.*|\\/\\*[^]*?\\*\\/)*/g\n","const {hasOwnProperty, toString} = Object.prototype\n\n// Checks if an object has a property.\n\nexport function has(obj, propName) {\n return hasOwnProperty.call(obj, propName)\n}\n\nexport const isArray = Array.isArray || ((obj) => (\n toString.call(obj) === \"[object Array]\"\n))\n","import {lineBreakG} from \"./whitespace\"\n\n// These are used when `options.locations` is on, for the\n// `startLoc` and `endLoc` properties.\n\nexport class Position {\n constructor(line, col) {\n this.line = line\n this.column = col\n }\n\n offset(n) {\n return new Position(this.line, this.column + n)\n }\n}\n\nexport class SourceLocation {\n constructor(p, start, end) {\n this.start = start\n this.end = end\n if (p.sourceFile !== null) this.source = p.sourceFile\n }\n}\n\n// The `getLineInfo` function is mostly useful when the\n// `locations` option is off (for performance reasons) and you\n// want to find the line/column position for a given character\n// offset. `input` should be the code string that the offset refers\n// into.\n\nexport function getLineInfo(input, offset) {\n for (let line = 1, cur = 0;;) {\n lineBreakG.lastIndex = cur\n let match = lineBreakG.exec(input)\n if (match && match.index < offset) {\n ++line\n cur = match.index + match[0].length\n } else {\n return new Position(line, offset - cur)\n }\n }\n}\n","import {has, isArray} from \"./util\"\nimport {SourceLocation} from \"./locutil\"\n\n// A second optional argument can be given to further configure\n// the parser process. These options are recognized:\n\nexport const defaultOptions = {\n // `ecmaVersion` indicates the ECMAScript version to parse. Must be\n // either 3, 5, 6 (2015), 7 (2016), 8 (2017), 9 (2018), or 10\n // (2019). This influences support for strict mode, the set of\n // reserved words, and support for new syntax features. The default\n // is 9.\n ecmaVersion: 9,\n // `sourceType` indicates the mode the code should be parsed in.\n // Can be either `\"script\"` or `\"module\"`. This influences global\n // strict mode and parsing of `import` and `export` declarations.\n sourceType: \"script\",\n // `onInsertedSemicolon` can be a callback that will be called\n // when a semicolon is automatically inserted. It will be passed\n // th position of the comma as an offset, and if `locations` is\n // enabled, it is given the location as a `{line, column}` object\n // as second argument.\n onInsertedSemicolon: null,\n // `onTrailingComma` is similar to `onInsertedSemicolon`, but for\n // trailing commas.\n onTrailingComma: null,\n // By default, reserved words are only enforced if ecmaVersion >= 5.\n // Set `allowReserved` to a boolean value to explicitly turn this on\n // an off. When this option has the value \"never\", reserved words\n // and keywords can also not be used as property names.\n allowReserved: null,\n // When enabled, a return at the top level is not considered an\n // error.\n allowReturnOutsideFunction: false,\n // When enabled, import/export statements are not constrained to\n // appearing at the top of the program.\n allowImportExportEverywhere: false,\n // When enabled, await identifiers are allowed to appear at the top-level scope,\n // but they are still not allowed in non-async functions.\n allowAwaitOutsideFunction: false,\n // When enabled, hashbang directive in the beginning of file\n // is allowed and treated as a line comment.\n allowHashBang: false,\n // When `locations` is on, `loc` properties holding objects with\n // `start` and `end` properties in `{line, column}` form (with\n // line being 1-based and column 0-based) will be attached to the\n // nodes.\n locations: false,\n // A function can be passed as `onToken` option, which will\n // cause Acorn to call that function with object in the same\n // format as tokens returned from `tokenizer().getToken()`. Note\n // that you are not allowed to call the parser from the\n // callback—that will corrupt its internal state.\n onToken: null,\n // A function can be passed as `onComment` option, which will\n // cause Acorn to call that function with `(block, text, start,\n // end)` parameters whenever a comment is skipped. `block` is a\n // boolean indicating whether this is a block (`/* */`) comment,\n // `text` is the content of the comment, and `start` and `end` are\n // character offsets that denote the start and end of the comment.\n // When the `locations` option is on, two more parameters are\n // passed, the full `{line, column}` locations of the start and\n // end of the comments. Note that you are not allowed to call the\n // parser from the callback—that will corrupt its internal state.\n onComment: null,\n // Nodes have their start and end characters offsets recorded in\n // `start` and `end` properties (directly on the node, rather than\n // the `loc` object, which holds line/column data. To also add a\n // [semi-standardized][range] `range` property holding a `[start,\n // end]` array with the same numbers, set the `ranges` option to\n // `true`.\n //\n // [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678\n ranges: false,\n // It is possible to parse multiple files into a single AST by\n // passing the tree produced by parsing the first file as\n // `program` option in subsequent parses. This will add the\n // toplevel forms of the parsed file to the `Program` (top) node\n // of an existing parse tree.\n program: null,\n // When `locations` is on, you can pass this to record the source\n // file in every node's `loc` object.\n sourceFile: null,\n // This value, if given, is stored in every node, whether\n // `locations` is on or off.\n directSourceFile: null,\n // When enabled, parenthesized expressions are represented by\n // (non-standard) ParenthesizedExpression nodes\n preserveParens: false\n}\n\n// Interpret and default an options object\n\nexport function getOptions(opts) {\n let options = {}\n\n for (let opt in defaultOptions)\n options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt]\n\n if (options.ecmaVersion >= 2015)\n options.ecmaVersion -= 2009\n\n if (options.allowReserved == null)\n options.allowReserved = options.ecmaVersion < 5\n\n if (isArray(options.onToken)) {\n let tokens = options.onToken\n options.onToken = (token) => tokens.push(token)\n }\n if (isArray(options.onComment))\n options.onComment = pushComment(options, options.onComment)\n\n return options\n}\n\nfunction pushComment(options, array) {\n return function(block, text, start, end, startLoc, endLoc) {\n let comment = {\n type: block ? \"Block\" : \"Line\",\n value: text,\n start: start,\n end: end\n }\n if (options.locations)\n comment.loc = new SourceLocation(this, startLoc, endLoc)\n if (options.ranges)\n comment.range = [start, end]\n array.push(comment)\n }\n}\n","// Each scope gets a bitset that may contain these flags\nexport const\n SCOPE_TOP = 1,\n SCOPE_FUNCTION = 2,\n SCOPE_VAR = SCOPE_TOP | SCOPE_FUNCTION,\n SCOPE_ASYNC = 4,\n SCOPE_GENERATOR = 8,\n SCOPE_ARROW = 16,\n SCOPE_SIMPLE_CATCH = 32\n\nexport function functionFlags(async, generator) {\n return SCOPE_FUNCTION | (async ? SCOPE_ASYNC : 0) | (generator ? SCOPE_GENERATOR : 0)\n}\n\n// Used in checkLVal and declareName to determine the type of a binding\nexport const\n BIND_NONE = 0, // Not a binding\n BIND_VAR = 1, // Var-style binding\n BIND_LEXICAL = 2, // Let- or const-style binding\n BIND_FUNCTION = 3, // Function declaration\n BIND_SIMPLE_CATCH = 4, // Simple (identifier pattern) catch binding\n BIND_OUTSIDE = 5 // Special case for function names as bound inside the function\n","import {reservedWords, keywords} from \"./identifier\"\nimport {types as tt} from \"./tokentype\"\nimport {lineBreak} from \"./whitespace\"\nimport {getOptions} from \"./options\"\nimport {SCOPE_TOP, SCOPE_FUNCTION, SCOPE_ASYNC, SCOPE_GENERATOR} from \"./scopeflags\"\n\nfunction keywordRegexp(words) {\n return new RegExp(\"^(?:\" + words.replace(/ /g, \"|\") + \")$\")\n}\n\nexport class Parser {\n constructor(options, input, startPos) {\n this.options = options = getOptions(options)\n this.sourceFile = options.sourceFile\n this.keywords = keywordRegexp(keywords[options.ecmaVersion >= 6 ? 6 : 5])\n let reserved = \"\"\n if (!options.allowReserved) {\n for (let v = options.ecmaVersion;; v--)\n if (reserved = reservedWords[v]) break\n if (options.sourceType === \"module\") reserved += \" await\"\n }\n this.reservedWords = keywordRegexp(reserved)\n let reservedStrict = (reserved ? reserved + \" \" : \"\") + reservedWords.strict\n this.reservedWordsStrict = keywordRegexp(reservedStrict)\n this.reservedWordsStrictBind = keywordRegexp(reservedStrict + \" \" + reservedWords.strictBind)\n this.input = String(input)\n\n // Used to signal to callers of `readWord1` whether the word\n // contained any escape sequences. This is needed because words with\n // escape sequences must not be interpreted as keywords.\n this.containsEsc = false\n\n // Set up token state\n\n // The current position of the tokenizer in the input.\n if (startPos) {\n this.pos = startPos\n this.lineStart = this.input.lastIndexOf(\"\\n\", startPos - 1) + 1\n this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length\n } else {\n this.pos = this.lineStart = 0\n this.curLine = 1\n }\n\n // Properties of the current token:\n // Its type\n this.type = tt.eof\n // For tokens that include more information than their type, the value\n this.value = null\n // Its start and end offset\n this.start = this.end = this.pos\n // And, if locations are used, the {line, column} object\n // corresponding to those offsets\n this.startLoc = this.endLoc = this.curPosition()\n\n // Position information for the previous token\n this.lastTokEndLoc = this.lastTokStartLoc = null\n this.lastTokStart = this.lastTokEnd = this.pos\n\n // The context stack is used to superficially track syntactic\n // context to predict whether a regular expression is allowed in a\n // given position.\n this.context = this.initialContext()\n this.exprAllowed = true\n\n // Figure out if it's a module code.\n this.inModule = options.sourceType === \"module\"\n this.strict = this.inModule || this.strictDirective(this.pos)\n\n // Used to signify the start of a potential arrow function\n this.potentialArrowAt = -1\n\n // Positions to delayed-check that yield/await does not exist in default parameters.\n this.yieldPos = this.awaitPos = 0\n // Labels in scope.\n this.labels = []\n\n // If enabled, skip leading hashbang line.\n if (this.pos === 0 && options.allowHashBang && this.input.slice(0, 2) === \"#!\")\n this.skipLineComment(2)\n\n // Scope tracking for duplicate variable names (see scope.js)\n this.scopeStack = []\n this.enterScope(SCOPE_TOP)\n\n // For RegExp validation\n this.regexpState = null\n }\n\n parse() {\n let node = this.options.program || this.startNode()\n this.nextToken()\n return this.parseTopLevel(node)\n }\n\n get inFunction() { return (this.currentVarScope().flags & SCOPE_FUNCTION) > 0 }\n get inGenerator() { return (this.currentVarScope().flags & SCOPE_GENERATOR) > 0 }\n get inAsync() { return (this.currentVarScope().flags & SCOPE_ASYNC) > 0 }\n\n static extend(...plugins) {\n let cls = this\n for (let i = 0; i < plugins.length; i++) cls = plugins[i](cls)\n return cls\n }\n\n static parse(input, options) {\n return new this(options, input).parse()\n }\n\n static parseExpressionAt(input, pos, options) {\n let parser = new this(options, input, pos)\n parser.nextToken()\n return parser.parseExpression()\n }\n\n static tokenizer(input, options) {\n return new this(options, input)\n }\n}\n","import {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {lineBreak, skipWhiteSpace} from \"./whitespace\"\n\nconst pp = Parser.prototype\n\n// ## Parser utilities\n\nconst literal = /^(?:'((?:\\\\.|[^'])*?)'|\"((?:\\\\.|[^\"])*?)\"|;)/\npp.strictDirective = function(start) {\n for (;;) {\n skipWhiteSpace.lastIndex = start\n start += skipWhiteSpace.exec(this.input)[0].length\n let match = literal.exec(this.input.slice(start))\n if (!match) return false\n if ((match[1] || match[2]) === \"use strict\") return true\n start += match[0].length\n }\n}\n\n// Predicate that tests whether the next token is of the given\n// type, and if yes, consumes it as a side effect.\n\npp.eat = function(type) {\n if (this.type === type) {\n this.next()\n return true\n } else {\n return false\n }\n}\n\n// Tests whether parsed token is a contextual keyword.\n\npp.isContextual = function(name) {\n return this.type === tt.name && this.value === name && !this.containsEsc\n}\n\n// Consumes contextual keyword if possible.\n\npp.eatContextual = function(name) {\n if (!this.isContextual(name)) return false\n this.next()\n return true\n}\n\n// Asserts that following token is given contextual keyword.\n\npp.expectContextual = function(name) {\n if (!this.eatContextual(name)) this.unexpected()\n}\n\n// Test whether a semicolon can be inserted at the current position.\n\npp.canInsertSemicolon = function() {\n return this.type === tt.eof ||\n this.type === tt.braceR ||\n lineBreak.test(this.input.slice(this.lastTokEnd, this.start))\n}\n\npp.insertSemicolon = function() {\n if (this.canInsertSemicolon()) {\n if (this.options.onInsertedSemicolon)\n this.options.onInsertedSemicolon(this.lastTokEnd, this.lastTokEndLoc)\n return true\n }\n}\n\n// Consume a semicolon, or, failing that, see if we are allowed to\n// pretend that there is a semicolon at this position.\n\npp.semicolon = function() {\n if (!this.eat(tt.semi) && !this.insertSemicolon()) this.unexpected()\n}\n\npp.afterTrailingComma = function(tokType, notNext) {\n if (this.type === tokType) {\n if (this.options.onTrailingComma)\n this.options.onTrailingComma(this.lastTokStart, this.lastTokStartLoc)\n if (!notNext)\n this.next()\n return true\n }\n}\n\n// Expect a token of a given type. If found, consume it, otherwise,\n// raise an unexpected token error.\n\npp.expect = function(type) {\n this.eat(type) || this.unexpected()\n}\n\n// Raise an unexpected token error.\n\npp.unexpected = function(pos) {\n this.raise(pos != null ? pos : this.start, \"Unexpected token\")\n}\n\nexport function DestructuringErrors() {\n this.shorthandAssign =\n this.trailingComma =\n this.parenthesizedAssign =\n this.parenthesizedBind =\n this.doubleProto =\n -1\n}\n\npp.checkPatternErrors = function(refDestructuringErrors, isAssign) {\n if (!refDestructuringErrors) return\n if (refDestructuringErrors.trailingComma > -1)\n this.raiseRecoverable(refDestructuringErrors.trailingComma, \"Comma is not permitted after the rest element\")\n let parens = isAssign ? refDestructuringErrors.parenthesizedAssign : refDestructuringErrors.parenthesizedBind\n if (parens > -1) this.raiseRecoverable(parens, \"Parenthesized pattern\")\n}\n\npp.checkExpressionErrors = function(refDestructuringErrors, andThrow) {\n if (!refDestructuringErrors) return false\n let {shorthandAssign, doubleProto} = refDestructuringErrors\n if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0\n if (shorthandAssign >= 0)\n this.raise(shorthandAssign, \"Shorthand property assignments are valid only in destructuring patterns\")\n if (doubleProto >= 0)\n this.raiseRecoverable(doubleProto, \"Redefinition of __proto__ property\")\n}\n\npp.checkYieldAwaitInDefaultParams = function() {\n if (this.yieldPos && (!this.awaitPos || this.yieldPos < this.awaitPos))\n this.raise(this.yieldPos, \"Yield expression cannot be a default value\")\n if (this.awaitPos)\n this.raise(this.awaitPos, \"Await expression cannot be a default value\")\n}\n\npp.isSimpleAssignTarget = function(expr) {\n if (expr.type === \"ParenthesizedExpression\")\n return this.isSimpleAssignTarget(expr.expression)\n return expr.type === \"Identifier\" || expr.type === \"MemberExpression\"\n}\n","import {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {lineBreak, skipWhiteSpace} from \"./whitespace\"\nimport {isIdentifierStart, isIdentifierChar, keywordRelationalOperator} from \"./identifier\"\nimport {has} from \"./util\"\nimport {DestructuringErrors} from \"./parseutil\"\nimport {functionFlags, SCOPE_SIMPLE_CATCH, BIND_SIMPLE_CATCH, BIND_LEXICAL, BIND_VAR, BIND_FUNCTION} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\n// ### Statement parsing\n\n// Parse a program. Initializes the parser, reads any number of\n// statements, and wraps them in a Program node. Optionally takes a\n// `program` argument. If present, the statements will be appended\n// to its body instead of creating a new node.\n\npp.parseTopLevel = function(node) {\n let exports = {}\n if (!node.body) node.body = []\n while (this.type !== tt.eof) {\n let stmt = this.parseStatement(null, true, exports)\n node.body.push(stmt)\n }\n this.adaptDirectivePrologue(node.body)\n this.next()\n if (this.options.ecmaVersion >= 6) {\n node.sourceType = this.options.sourceType\n }\n return this.finishNode(node, \"Program\")\n}\n\nconst loopLabel = {kind: \"loop\"}, switchLabel = {kind: \"switch\"}\n\npp.isLet = function() {\n if (this.options.ecmaVersion < 6 || !this.isContextual(\"let\")) return false\n skipWhiteSpace.lastIndex = this.pos\n let skip = skipWhiteSpace.exec(this.input)\n let next = this.pos + skip[0].length, nextCh = this.input.charCodeAt(next)\n if (nextCh === 91 || nextCh === 123) return true // '{' and '['\n if (isIdentifierStart(nextCh, true)) {\n let pos = next + 1\n while (isIdentifierChar(this.input.charCodeAt(pos), true)) ++pos\n let ident = this.input.slice(next, pos)\n if (!keywordRelationalOperator.test(ident)) return true\n }\n return false\n}\n\n// check 'async [no LineTerminator here] function'\n// - 'async /*foo*/ function' is OK.\n// - 'async /*\\n*/ function' is invalid.\npp.isAsyncFunction = function() {\n if (this.options.ecmaVersion < 8 || !this.isContextual(\"async\"))\n return false\n\n skipWhiteSpace.lastIndex = this.pos\n let skip = skipWhiteSpace.exec(this.input)\n let next = this.pos + skip[0].length\n return !lineBreak.test(this.input.slice(this.pos, next)) &&\n this.input.slice(next, next + 8) === \"function\" &&\n (next + 8 === this.input.length || !isIdentifierChar(this.input.charAt(next + 8)))\n}\n\n// Parse a single statement.\n//\n// If expecting a statement and finding a slash operator, parse a\n// regular expression literal. This is to handle cases like\n// `if (foo) /blah/.exec(foo)`, where looking at the previous token\n// does not help.\n\npp.parseStatement = function(context, topLevel, exports) {\n let starttype = this.type, node = this.startNode(), kind\n\n if (this.isLet()) {\n starttype = tt._var\n kind = \"let\"\n }\n\n // Most types of statements are recognized by the keyword they\n // start with. Many are trivial to parse, some require a bit of\n // complexity.\n\n switch (starttype) {\n case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword)\n case tt._debugger: return this.parseDebuggerStatement(node)\n case tt._do: return this.parseDoStatement(node)\n case tt._for: return this.parseForStatement(node)\n case tt._function:\n if ((context && (this.strict || context !== \"if\")) && this.options.ecmaVersion >= 6) this.unexpected()\n return this.parseFunctionStatement(node, false, !context)\n case tt._class:\n if (context) this.unexpected()\n return this.parseClass(node, true)\n case tt._if: return this.parseIfStatement(node)\n case tt._return: return this.parseReturnStatement(node)\n case tt._switch: return this.parseSwitchStatement(node)\n case tt._throw: return this.parseThrowStatement(node)\n case tt._try: return this.parseTryStatement(node)\n case tt._const: case tt._var:\n kind = kind || this.value\n if (context && kind !== \"var\") this.unexpected()\n return this.parseVarStatement(node, kind)\n case tt._while: return this.parseWhileStatement(node)\n case tt._with: return this.parseWithStatement(node)\n case tt.braceL: return this.parseBlock(true, node)\n case tt.semi: return this.parseEmptyStatement(node)\n case tt._export:\n case tt._import:\n if (!this.options.allowImportExportEverywhere) {\n if (!topLevel)\n this.raise(this.start, \"'import' and 'export' may only appear at the top level\")\n if (!this.inModule)\n this.raise(this.start, \"'import' and 'export' may appear only with 'sourceType: module'\")\n }\n return starttype === tt._import ? this.parseImport(node) : this.parseExport(node, exports)\n\n // If the statement does not start with a statement keyword or a\n // brace, it's an ExpressionStatement or LabeledStatement. We\n // simply start parsing an expression, and afterwards, if the\n // next token is a colon and the expression was a simple\n // Identifier node, we switch to interpreting it as a label.\n default:\n if (this.isAsyncFunction()) {\n if (context) this.unexpected()\n this.next()\n return this.parseFunctionStatement(node, true, !context)\n }\n\n let maybeName = this.value, expr = this.parseExpression()\n if (starttype === tt.name && expr.type === \"Identifier\" && this.eat(tt.colon))\n return this.parseLabeledStatement(node, maybeName, expr, context)\n else return this.parseExpressionStatement(node, expr)\n }\n}\n\npp.parseBreakContinueStatement = function(node, keyword) {\n let isBreak = keyword === \"break\"\n this.next()\n if (this.eat(tt.semi) || this.insertSemicolon()) node.label = null\n else if (this.type !== tt.name) this.unexpected()\n else {\n node.label = this.parseIdent()\n this.semicolon()\n }\n\n // Verify that there is an actual destination to break or\n // continue to.\n let i = 0\n for (; i < this.labels.length; ++i) {\n let lab = this.labels[i]\n if (node.label == null || lab.name === node.label.name) {\n if (lab.kind != null && (isBreak || lab.kind === \"loop\")) break\n if (node.label && isBreak) break\n }\n }\n if (i === this.labels.length) this.raise(node.start, \"Unsyntactic \" + keyword)\n return this.finishNode(node, isBreak ? \"BreakStatement\" : \"ContinueStatement\")\n}\n\npp.parseDebuggerStatement = function(node) {\n this.next()\n this.semicolon()\n return this.finishNode(node, \"DebuggerStatement\")\n}\n\npp.parseDoStatement = function(node) {\n this.next()\n this.labels.push(loopLabel)\n node.body = this.parseStatement(\"do\")\n this.labels.pop()\n this.expect(tt._while)\n node.test = this.parseParenExpression()\n if (this.options.ecmaVersion >= 6)\n this.eat(tt.semi)\n else\n this.semicolon()\n return this.finishNode(node, \"DoWhileStatement\")\n}\n\n// Disambiguating between a `for` and a `for`/`in` or `for`/`of`\n// loop is non-trivial. Basically, we have to parse the init `var`\n// statement or expression, disallowing the `in` operator (see\n// the second parameter to `parseExpression`), and then check\n// whether the next token is `in` or `of`. When there is no init\n// part (semicolon immediately after the opening parenthesis), it\n// is a regular `for` loop.\n\npp.parseForStatement = function(node) {\n this.next()\n let awaitAt = (this.options.ecmaVersion >= 9 && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction)) && this.eatContextual(\"await\")) ? this.lastTokStart : -1\n this.labels.push(loopLabel)\n this.enterScope(0)\n this.expect(tt.parenL)\n if (this.type === tt.semi) {\n if (awaitAt > -1) this.unexpected(awaitAt)\n return this.parseFor(node, null)\n }\n let isLet = this.isLet()\n if (this.type === tt._var || this.type === tt._const || isLet) {\n let init = this.startNode(), kind = isLet ? \"let\" : this.value\n this.next()\n this.parseVar(init, true, kind)\n this.finishNode(init, \"VariableDeclaration\")\n if ((this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual(\"of\"))) && init.declarations.length === 1 &&\n !(kind !== \"var\" && init.declarations[0].init)) {\n if (this.options.ecmaVersion >= 9) {\n if (this.type === tt._in) {\n if (awaitAt > -1) this.unexpected(awaitAt)\n } else node.await = awaitAt > -1\n }\n return this.parseForIn(node, init)\n }\n if (awaitAt > -1) this.unexpected(awaitAt)\n return this.parseFor(node, init)\n }\n let refDestructuringErrors = new DestructuringErrors\n let init = this.parseExpression(true, refDestructuringErrors)\n if (this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual(\"of\"))) {\n if (this.options.ecmaVersion >= 9) {\n if (this.type === tt._in) {\n if (awaitAt > -1) this.unexpected(awaitAt)\n } else node.await = awaitAt > -1\n }\n this.toAssignable(init, false, refDestructuringErrors)\n this.checkLVal(init)\n return this.parseForIn(node, init)\n } else {\n this.checkExpressionErrors(refDestructuringErrors, true)\n }\n if (awaitAt > -1) this.unexpected(awaitAt)\n return this.parseFor(node, init)\n}\n\npp.parseFunctionStatement = function(node, isAsync, declarationPosition) {\n this.next()\n return this.parseFunction(node, FUNC_STATEMENT | (declarationPosition ? 0 : FUNC_HANGING_STATEMENT), false, isAsync)\n}\n\npp.parseIfStatement = function(node) {\n this.next()\n node.test = this.parseParenExpression()\n // allow function declarations in branches, but only in non-strict mode\n node.consequent = this.parseStatement(\"if\")\n node.alternate = this.eat(tt._else) ? this.parseStatement(\"if\") : null\n return this.finishNode(node, \"IfStatement\")\n}\n\npp.parseReturnStatement = function(node) {\n if (!this.inFunction && !this.options.allowReturnOutsideFunction)\n this.raise(this.start, \"'return' outside of function\")\n this.next()\n\n // In `return` (and `break`/`continue`), the keywords with\n // optional arguments, we eagerly look for a semicolon or the\n // possibility to insert one.\n\n if (this.eat(tt.semi) || this.insertSemicolon()) node.argument = null\n else { node.argument = this.parseExpression(); this.semicolon() }\n return this.finishNode(node, \"ReturnStatement\")\n}\n\npp.parseSwitchStatement = function(node) {\n this.next()\n node.discriminant = this.parseParenExpression()\n node.cases = []\n this.expect(tt.braceL)\n this.labels.push(switchLabel)\n this.enterScope(0)\n\n // Statements under must be grouped (by label) in SwitchCase\n // nodes. `cur` is used to keep the node that we are currently\n // adding statements to.\n\n let cur\n for (let sawDefault = false; this.type !== tt.braceR;) {\n if (this.type === tt._case || this.type === tt._default) {\n let isCase = this.type === tt._case\n if (cur) this.finishNode(cur, \"SwitchCase\")\n node.cases.push(cur = this.startNode())\n cur.consequent = []\n this.next()\n if (isCase) {\n cur.test = this.parseExpression()\n } else {\n if (sawDefault) this.raiseRecoverable(this.lastTokStart, \"Multiple default clauses\")\n sawDefault = true\n cur.test = null\n }\n this.expect(tt.colon)\n } else {\n if (!cur) this.unexpected()\n cur.consequent.push(this.parseStatement(null))\n }\n }\n this.exitScope()\n if (cur) this.finishNode(cur, \"SwitchCase\")\n this.next() // Closing brace\n this.labels.pop()\n return this.finishNode(node, \"SwitchStatement\")\n}\n\npp.parseThrowStatement = function(node) {\n this.next()\n if (lineBreak.test(this.input.slice(this.lastTokEnd, this.start)))\n this.raise(this.lastTokEnd, \"Illegal newline after throw\")\n node.argument = this.parseExpression()\n this.semicolon()\n return this.finishNode(node, \"ThrowStatement\")\n}\n\n// Reused empty array added for node fields that are always empty.\n\nconst empty = []\n\npp.parseTryStatement = function(node) {\n this.next()\n node.block = this.parseBlock()\n node.handler = null\n if (this.type === tt._catch) {\n let clause = this.startNode()\n this.next()\n if (this.eat(tt.parenL)) {\n clause.param = this.parseBindingAtom()\n let simple = clause.param.type === \"Identifier\"\n this.enterScope(simple ? SCOPE_SIMPLE_CATCH : 0)\n this.checkLVal(clause.param, simple ? BIND_SIMPLE_CATCH : BIND_LEXICAL)\n this.expect(tt.parenR)\n } else {\n if (this.options.ecmaVersion < 10) this.unexpected()\n clause.param = null\n this.enterScope(0)\n }\n clause.body = this.parseBlock(false)\n this.exitScope()\n node.handler = this.finishNode(clause, \"CatchClause\")\n }\n node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null\n if (!node.handler && !node.finalizer)\n this.raise(node.start, \"Missing catch or finally clause\")\n return this.finishNode(node, \"TryStatement\")\n}\n\npp.parseVarStatement = function(node, kind) {\n this.next()\n this.parseVar(node, false, kind)\n this.semicolon()\n return this.finishNode(node, \"VariableDeclaration\")\n}\n\npp.parseWhileStatement = function(node) {\n this.next()\n node.test = this.parseParenExpression()\n this.labels.push(loopLabel)\n node.body = this.parseStatement(\"while\")\n this.labels.pop()\n return this.finishNode(node, \"WhileStatement\")\n}\n\npp.parseWithStatement = function(node) {\n if (this.strict) this.raise(this.start, \"'with' in strict mode\")\n this.next()\n node.object = this.parseParenExpression()\n node.body = this.parseStatement(\"with\")\n return this.finishNode(node, \"WithStatement\")\n}\n\npp.parseEmptyStatement = function(node) {\n this.next()\n return this.finishNode(node, \"EmptyStatement\")\n}\n\npp.parseLabeledStatement = function(node, maybeName, expr, context) {\n for (let label of this.labels)\n if (label.name === maybeName)\n this.raise(expr.start, \"Label '\" + maybeName + \"' is already declared\")\n let kind = this.type.isLoop ? \"loop\" : this.type === tt._switch ? \"switch\" : null\n for (let i = this.labels.length - 1; i >= 0; i--) {\n let label = this.labels[i]\n if (label.statementStart === node.start) {\n // Update information about previous labels on this node\n label.statementStart = this.start\n label.kind = kind\n } else break\n }\n this.labels.push({name: maybeName, kind, statementStart: this.start})\n node.body = this.parseStatement(context)\n if (node.body.type === \"ClassDeclaration\" ||\n node.body.type === \"VariableDeclaration\" && node.body.kind !== \"var\" ||\n node.body.type === \"FunctionDeclaration\" && (this.strict || node.body.generator || node.body.async))\n this.raiseRecoverable(node.body.start, \"Invalid labeled declaration\")\n this.labels.pop()\n node.label = expr\n return this.finishNode(node, \"LabeledStatement\")\n}\n\npp.parseExpressionStatement = function(node, expr) {\n node.expression = expr\n this.semicolon()\n return this.finishNode(node, \"ExpressionStatement\")\n}\n\n// Parse a semicolon-enclosed block of statements, handling `\"use\n// strict\"` declarations when `allowStrict` is true (used for\n// function bodies).\n\npp.parseBlock = function(createNewLexicalScope = true, node = this.startNode()) {\n node.body = []\n this.expect(tt.braceL)\n if (createNewLexicalScope) this.enterScope(0)\n while (!this.eat(tt.braceR)) {\n let stmt = this.parseStatement(null)\n node.body.push(stmt)\n }\n if (createNewLexicalScope) this.exitScope()\n return this.finishNode(node, \"BlockStatement\")\n}\n\n// Parse a regular `for` loop. The disambiguation code in\n// `parseStatement` will already have parsed the init statement or\n// expression.\n\npp.parseFor = function(node, init) {\n node.init = init\n this.expect(tt.semi)\n node.test = this.type === tt.semi ? null : this.parseExpression()\n this.expect(tt.semi)\n node.update = this.type === tt.parenR ? null : this.parseExpression()\n this.expect(tt.parenR)\n this.exitScope()\n node.body = this.parseStatement(\"for\")\n this.labels.pop()\n return this.finishNode(node, \"ForStatement\")\n}\n\n// Parse a `for`/`in` and `for`/`of` loop, which are almost\n// same from parser's perspective.\n\npp.parseForIn = function(node, init) {\n let type = this.type === tt._in ? \"ForInStatement\" : \"ForOfStatement\"\n this.next()\n if (type === \"ForInStatement\") {\n if (init.type === \"AssignmentPattern\" ||\n (init.type === \"VariableDeclaration\" && init.declarations[0].init != null &&\n (this.strict || init.declarations[0].id.type !== \"Identifier\")))\n this.raise(init.start, \"Invalid assignment in for-in loop head\")\n }\n node.left = init\n node.right = type === \"ForInStatement\" ? this.parseExpression() : this.parseMaybeAssign()\n this.expect(tt.parenR)\n this.exitScope()\n node.body = this.parseStatement(\"for\")\n this.labels.pop()\n return this.finishNode(node, type)\n}\n\n// Parse a list of variable declarations.\n\npp.parseVar = function(node, isFor, kind) {\n node.declarations = []\n node.kind = kind\n for (;;) {\n let decl = this.startNode()\n this.parseVarId(decl, kind)\n if (this.eat(tt.eq)) {\n decl.init = this.parseMaybeAssign(isFor)\n } else if (kind === \"const\" && !(this.type === tt._in || (this.options.ecmaVersion >= 6 && this.isContextual(\"of\")))) {\n this.unexpected()\n } else if (decl.id.type !== \"Identifier\" && !(isFor && (this.type === tt._in || this.isContextual(\"of\")))) {\n this.raise(this.lastTokEnd, \"Complex binding patterns require an initialization value\")\n } else {\n decl.init = null\n }\n node.declarations.push(this.finishNode(decl, \"VariableDeclarator\"))\n if (!this.eat(tt.comma)) break\n }\n return node\n}\n\npp.parseVarId = function(decl, kind) {\n decl.id = this.parseBindingAtom(kind)\n this.checkLVal(decl.id, kind === \"var\" ? BIND_VAR : BIND_LEXICAL, false)\n}\n\nconst FUNC_STATEMENT = 1, FUNC_HANGING_STATEMENT = 2, FUNC_NULLABLE_ID = 4\n\n// Parse a function declaration or literal (depending on the\n// `isStatement` parameter).\n\npp.parseFunction = function(node, statement, allowExpressionBody, isAsync) {\n this.initFunction(node)\n if (this.options.ecmaVersion >= 9 || this.options.ecmaVersion >= 6 && !isAsync)\n node.generator = this.eat(tt.star)\n if (this.options.ecmaVersion >= 8)\n node.async = !!isAsync\n\n if (statement & FUNC_STATEMENT) {\n node.id = (statement & FUNC_NULLABLE_ID) && this.type !== tt.name ? null : this.parseIdent()\n if (node.id && !(statement & FUNC_HANGING_STATEMENT))\n this.checkLVal(node.id, this.inModule && !this.inFunction ? BIND_LEXICAL : BIND_FUNCTION)\n }\n\n let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos\n this.yieldPos = 0\n this.awaitPos = 0\n this.enterScope(functionFlags(node.async, node.generator))\n\n if (!(statement & FUNC_STATEMENT))\n node.id = this.type === tt.name ? this.parseIdent() : null\n\n this.parseFunctionParams(node)\n this.parseFunctionBody(node, allowExpressionBody)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.finishNode(node, (statement & FUNC_STATEMENT) ? \"FunctionDeclaration\" : \"FunctionExpression\")\n}\n\npp.parseFunctionParams = function(node) {\n this.expect(tt.parenL)\n node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8)\n this.checkYieldAwaitInDefaultParams()\n}\n\n// Parse a class declaration or literal (depending on the\n// `isStatement` parameter).\n\npp.parseClass = function(node, isStatement) {\n this.next()\n\n this.parseClassId(node, isStatement)\n this.parseClassSuper(node)\n let classBody = this.startNode()\n let hadConstructor = false\n classBody.body = []\n this.expect(tt.braceL)\n while (!this.eat(tt.braceR)) {\n const element = this.parseClassElement()\n if (element) {\n classBody.body.push(element)\n if (element.type === \"MethodDefinition\" && element.kind === \"constructor\") {\n if (hadConstructor) this.raise(element.start, \"Duplicate constructor in the same class\")\n hadConstructor = true\n }\n }\n }\n node.body = this.finishNode(classBody, \"ClassBody\")\n return this.finishNode(node, isStatement ? \"ClassDeclaration\" : \"ClassExpression\")\n}\n\npp.parseClassElement = function() {\n if (this.eat(tt.semi)) return null\n\n let method = this.startNode()\n const tryContextual = (k, noLineBreak = false) => {\n const start = this.start, startLoc = this.startLoc\n if (!this.eatContextual(k)) return false\n if (this.type !== tt.parenL && (!noLineBreak || !this.canInsertSemicolon())) return true\n if (method.key) this.unexpected()\n method.computed = false\n method.key = this.startNodeAt(start, startLoc)\n method.key.name = k\n this.finishNode(method.key, \"Identifier\")\n return false\n }\n\n method.kind = \"method\"\n method.static = tryContextual(\"static\")\n let isGenerator = this.eat(tt.star)\n let isAsync = false\n if (!isGenerator) {\n if (this.options.ecmaVersion >= 8 && tryContextual(\"async\", true)) {\n isAsync = true\n isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star)\n } else if (tryContextual(\"get\")) {\n method.kind = \"get\"\n } else if (tryContextual(\"set\")) {\n method.kind = \"set\"\n }\n }\n if (!method.key) this.parsePropertyName(method)\n let {key} = method\n if (!method.computed && !method.static && (key.type === \"Identifier\" && key.name === \"constructor\" ||\n key.type === \"Literal\" && key.value === \"constructor\")) {\n if (method.kind !== \"method\") this.raise(key.start, \"Constructor can't have get/set modifier\")\n if (isGenerator) this.raise(key.start, \"Constructor can't be a generator\")\n if (isAsync) this.raise(key.start, \"Constructor can't be an async method\")\n method.kind = \"constructor\"\n } else if (method.static && key.type === \"Identifier\" && key.name === \"prototype\") {\n this.raise(key.start, \"Classes may not have a static property named prototype\")\n }\n this.parseClassMethod(method, isGenerator, isAsync)\n if (method.kind === \"get\" && method.value.params.length !== 0)\n this.raiseRecoverable(method.value.start, \"getter should have no params\")\n if (method.kind === \"set\" && method.value.params.length !== 1)\n this.raiseRecoverable(method.value.start, \"setter should have exactly one param\")\n if (method.kind === \"set\" && method.value.params[0].type === \"RestElement\")\n this.raiseRecoverable(method.value.params[0].start, \"Setter cannot use rest params\")\n return method\n}\n\npp.parseClassMethod = function(method, isGenerator, isAsync) {\n method.value = this.parseMethod(isGenerator, isAsync)\n return this.finishNode(method, \"MethodDefinition\")\n}\n\npp.parseClassId = function(node, isStatement) {\n node.id = this.type === tt.name ? this.parseIdent() : isStatement === true ? this.unexpected() : null\n}\n\npp.parseClassSuper = function(node) {\n node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null\n}\n\n// Parses module export declaration.\n\npp.parseExport = function(node, exports) {\n this.next()\n // export * from '...'\n if (this.eat(tt.star)) {\n this.expectContextual(\"from\")\n if (this.type !== tt.string) this.unexpected()\n node.source = this.parseExprAtom()\n this.semicolon()\n return this.finishNode(node, \"ExportAllDeclaration\")\n }\n if (this.eat(tt._default)) { // export default ...\n this.checkExport(exports, \"default\", this.lastTokStart)\n let isAsync\n if (this.type === tt._function || (isAsync = this.isAsyncFunction())) {\n let fNode = this.startNode()\n this.next()\n if (isAsync) this.next()\n node.declaration = this.parseFunction(fNode, FUNC_STATEMENT | FUNC_NULLABLE_ID, false, isAsync, true)\n } else if (this.type === tt._class) {\n let cNode = this.startNode()\n node.declaration = this.parseClass(cNode, \"nullableID\")\n } else {\n node.declaration = this.parseMaybeAssign()\n this.semicolon()\n }\n return this.finishNode(node, \"ExportDefaultDeclaration\")\n }\n // export var|const|let|function|class ...\n if (this.shouldParseExportStatement()) {\n node.declaration = this.parseStatement(null)\n if (node.declaration.type === \"VariableDeclaration\")\n this.checkVariableExport(exports, node.declaration.declarations)\n else\n this.checkExport(exports, node.declaration.id.name, node.declaration.id.start)\n node.specifiers = []\n node.source = null\n } else { // export { x, y as z } [from '...']\n node.declaration = null\n node.specifiers = this.parseExportSpecifiers(exports)\n if (this.eatContextual(\"from\")) {\n if (this.type !== tt.string) this.unexpected()\n node.source = this.parseExprAtom()\n } else {\n // check for keywords used as local names\n for (let spec of node.specifiers) {\n this.checkUnreserved(spec.local)\n }\n\n node.source = null\n }\n this.semicolon()\n }\n return this.finishNode(node, \"ExportNamedDeclaration\")\n}\n\npp.checkExport = function(exports, name, pos) {\n if (!exports) return\n if (has(exports, name))\n this.raiseRecoverable(pos, \"Duplicate export '\" + name + \"'\")\n exports[name] = true\n}\n\npp.checkPatternExport = function(exports, pat) {\n let type = pat.type\n if (type === \"Identifier\")\n this.checkExport(exports, pat.name, pat.start)\n else if (type === \"ObjectPattern\")\n for (let prop of pat.properties)\n this.checkPatternExport(exports, prop)\n else if (type === \"ArrayPattern\")\n for (let elt of pat.elements) {\n if (elt) this.checkPatternExport(exports, elt)\n }\n else if (type === \"Property\")\n this.checkPatternExport(exports, pat.value)\n else if (type === \"AssignmentPattern\")\n this.checkPatternExport(exports, pat.left)\n else if (type === \"RestElement\")\n this.checkPatternExport(exports, pat.argument)\n else if (type === \"ParenthesizedExpression\")\n this.checkPatternExport(exports, pat.expression)\n}\n\npp.checkVariableExport = function(exports, decls) {\n if (!exports) return\n for (let decl of decls)\n this.checkPatternExport(exports, decl.id)\n}\n\npp.shouldParseExportStatement = function() {\n return this.type.keyword === \"var\" ||\n this.type.keyword === \"const\" ||\n this.type.keyword === \"class\" ||\n this.type.keyword === \"function\" ||\n this.isLet() ||\n this.isAsyncFunction()\n}\n\n// Parses a comma-separated list of module exports.\n\npp.parseExportSpecifiers = function(exports) {\n let nodes = [], first = true\n // export { x, y as z } [from '...']\n this.expect(tt.braceL)\n while (!this.eat(tt.braceR)) {\n if (!first) {\n this.expect(tt.comma)\n if (this.afterTrailingComma(tt.braceR)) break\n } else first = false\n\n let node = this.startNode()\n node.local = this.parseIdent(true)\n node.exported = this.eatContextual(\"as\") ? this.parseIdent(true) : node.local\n this.checkExport(exports, node.exported.name, node.exported.start)\n nodes.push(this.finishNode(node, \"ExportSpecifier\"))\n }\n return nodes\n}\n\n// Parses import declaration.\n\npp.parseImport = function(node) {\n this.next()\n // import '...'\n if (this.type === tt.string) {\n node.specifiers = empty\n node.source = this.parseExprAtom()\n } else {\n node.specifiers = this.parseImportSpecifiers()\n this.expectContextual(\"from\")\n node.source = this.type === tt.string ? this.parseExprAtom() : this.unexpected()\n }\n this.semicolon()\n return this.finishNode(node, \"ImportDeclaration\")\n}\n\n// Parses a comma-separated list of module imports.\n\npp.parseImportSpecifiers = function() {\n let nodes = [], first = true\n if (this.type === tt.name) {\n // import defaultObj, { x, y as z } from '...'\n let node = this.startNode()\n node.local = this.parseIdent()\n this.checkLVal(node.local, BIND_LEXICAL)\n nodes.push(this.finishNode(node, \"ImportDefaultSpecifier\"))\n if (!this.eat(tt.comma)) return nodes\n }\n if (this.type === tt.star) {\n let node = this.startNode()\n this.next()\n this.expectContextual(\"as\")\n node.local = this.parseIdent()\n this.checkLVal(node.local, BIND_LEXICAL)\n nodes.push(this.finishNode(node, \"ImportNamespaceSpecifier\"))\n return nodes\n }\n this.expect(tt.braceL)\n while (!this.eat(tt.braceR)) {\n if (!first) {\n this.expect(tt.comma)\n if (this.afterTrailingComma(tt.braceR)) break\n } else first = false\n\n let node = this.startNode()\n node.imported = this.parseIdent(true)\n if (this.eatContextual(\"as\")) {\n node.local = this.parseIdent()\n } else {\n this.checkUnreserved(node.imported)\n node.local = node.imported\n }\n this.checkLVal(node.local, BIND_LEXICAL)\n nodes.push(this.finishNode(node, \"ImportSpecifier\"))\n }\n return nodes\n}\n\n// Set `ExpressionStatement#directive` property for directive prologues.\npp.adaptDirectivePrologue = function(statements) {\n for (let i = 0; i < statements.length && this.isDirectiveCandidate(statements[i]); ++i) {\n statements[i].directive = statements[i].expression.raw.slice(1, -1)\n }\n}\npp.isDirectiveCandidate = function(statement) {\n return (\n statement.type === \"ExpressionStatement\" &&\n statement.expression.type === \"Literal\" &&\n typeof statement.expression.value === \"string\" &&\n // Reject parenthesized strings.\n (this.input[statement.start] === \"\\\"\" || this.input[statement.start] === \"'\")\n )\n}\n","import {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {has} from \"./util\"\nimport {BIND_NONE, BIND_OUTSIDE} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\n// Convert existing expression atom to assignable pattern\n// if possible.\n\npp.toAssignable = function(node, isBinding, refDestructuringErrors) {\n if (this.options.ecmaVersion >= 6 && node) {\n switch (node.type) {\n case \"Identifier\":\n if (this.inAsync && node.name === \"await\")\n this.raise(node.start, \"Can not use 'await' as identifier inside an async function\")\n break\n\n case \"ObjectPattern\":\n case \"ArrayPattern\":\n case \"RestElement\":\n break\n\n case \"ObjectExpression\":\n node.type = \"ObjectPattern\"\n if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true)\n for (let prop of node.properties) {\n this.toAssignable(prop, isBinding)\n // Early error:\n // AssignmentRestProperty[Yield, Await] :\n // `...` DestructuringAssignmentTarget[Yield, Await]\n //\n // It is a Syntax Error if |DestructuringAssignmentTarget| is an |ArrayLiteral| or an |ObjectLiteral|.\n if (\n prop.type === \"RestElement\" &&\n (prop.argument.type === \"ArrayPattern\" || prop.argument.type === \"ObjectPattern\")\n ) {\n this.raise(prop.argument.start, \"Unexpected token\")\n }\n }\n break\n\n case \"Property\":\n // AssignmentProperty has type === \"Property\"\n if (node.kind !== \"init\") this.raise(node.key.start, \"Object pattern can't contain getter or setter\")\n this.toAssignable(node.value, isBinding)\n break\n\n case \"ArrayExpression\":\n node.type = \"ArrayPattern\"\n if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true)\n this.toAssignableList(node.elements, isBinding)\n break\n\n case \"SpreadElement\":\n node.type = \"RestElement\"\n this.toAssignable(node.argument, isBinding)\n if (node.argument.type === \"AssignmentPattern\")\n this.raise(node.argument.start, \"Rest elements cannot have a default value\")\n break\n\n case \"AssignmentExpression\":\n if (node.operator !== \"=\") this.raise(node.left.end, \"Only '=' operator can be used for specifying default value.\")\n node.type = \"AssignmentPattern\"\n delete node.operator\n this.toAssignable(node.left, isBinding)\n // falls through to AssignmentPattern\n\n case \"AssignmentPattern\":\n break\n\n case \"ParenthesizedExpression\":\n this.toAssignable(node.expression, isBinding)\n break\n\n case \"MemberExpression\":\n if (!isBinding) break\n\n default:\n this.raise(node.start, \"Assigning to rvalue\")\n }\n } else if (refDestructuringErrors) this.checkPatternErrors(refDestructuringErrors, true)\n return node\n}\n\n// Convert list of expression atoms to binding list.\n\npp.toAssignableList = function(exprList, isBinding) {\n let end = exprList.length\n for (let i = 0; i < end; i++) {\n let elt = exprList[i]\n if (elt) this.toAssignable(elt, isBinding)\n }\n if (end) {\n let last = exprList[end - 1]\n if (this.options.ecmaVersion === 6 && isBinding && last && last.type === \"RestElement\" && last.argument.type !== \"Identifier\")\n this.unexpected(last.argument.start)\n }\n return exprList\n}\n\n// Parses spread element.\n\npp.parseSpread = function(refDestructuringErrors) {\n let node = this.startNode()\n this.next()\n node.argument = this.parseMaybeAssign(false, refDestructuringErrors)\n return this.finishNode(node, \"SpreadElement\")\n}\n\npp.parseRestBinding = function() {\n let node = this.startNode()\n this.next()\n\n // RestElement inside of a function parameter must be an identifier\n if (this.options.ecmaVersion === 6 && this.type !== tt.name)\n this.unexpected()\n\n node.argument = this.parseBindingAtom()\n\n return this.finishNode(node, \"RestElement\")\n}\n\n// Parses lvalue (assignable) atom.\n\npp.parseBindingAtom = function() {\n if (this.options.ecmaVersion >= 6) {\n switch (this.type) {\n case tt.bracketL:\n let node = this.startNode()\n this.next()\n node.elements = this.parseBindingList(tt.bracketR, true, true)\n return this.finishNode(node, \"ArrayPattern\")\n\n case tt.braceL:\n return this.parseObj(true)\n }\n }\n return this.parseIdent()\n}\n\npp.parseBindingList = function(close, allowEmpty, allowTrailingComma) {\n let elts = [], first = true\n while (!this.eat(close)) {\n if (first) first = false\n else this.expect(tt.comma)\n if (allowEmpty && this.type === tt.comma) {\n elts.push(null)\n } else if (allowTrailingComma && this.afterTrailingComma(close)) {\n break\n } else if (this.type === tt.ellipsis) {\n let rest = this.parseRestBinding()\n this.parseBindingListItem(rest)\n elts.push(rest)\n if (this.type === tt.comma) this.raise(this.start, \"Comma is not permitted after the rest element\")\n this.expect(close)\n break\n } else {\n let elem = this.parseMaybeDefault(this.start, this.startLoc)\n this.parseBindingListItem(elem)\n elts.push(elem)\n }\n }\n return elts\n}\n\npp.parseBindingListItem = function(param) {\n return param\n}\n\n// Parses assignment pattern around given atom if possible.\n\npp.parseMaybeDefault = function(startPos, startLoc, left) {\n left = left || this.parseBindingAtom()\n if (this.options.ecmaVersion < 6 || !this.eat(tt.eq)) return left\n let node = this.startNodeAt(startPos, startLoc)\n node.left = left\n node.right = this.parseMaybeAssign()\n return this.finishNode(node, \"AssignmentPattern\")\n}\n\n// Verify that a node is an lval — something that can be assigned\n// to.\n// bindingType can be either:\n// 'var' indicating that the lval creates a 'var' binding\n// 'let' indicating that the lval creates a lexical ('let' or 'const') binding\n// 'none' indicating that the binding should be checked for illegal identifiers, but not for duplicate references\n\npp.checkLVal = function(expr, bindingType = BIND_NONE, checkClashes) {\n switch (expr.type) {\n case \"Identifier\":\n if (this.strict && this.reservedWordsStrictBind.test(expr.name))\n this.raiseRecoverable(expr.start, (bindingType ? \"Binding \" : \"Assigning to \") + expr.name + \" in strict mode\")\n if (checkClashes) {\n if (has(checkClashes, expr.name))\n this.raiseRecoverable(expr.start, \"Argument name clash\")\n checkClashes[expr.name] = true\n }\n if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) this.declareName(expr.name, bindingType, expr.start)\n break\n\n case \"MemberExpression\":\n if (bindingType) this.raiseRecoverable(expr.start, \"Binding member expression\")\n break\n\n case \"ObjectPattern\":\n for (let prop of expr.properties)\n this.checkLVal(prop, bindingType, checkClashes)\n break\n\n case \"Property\":\n // AssignmentProperty has type === \"Property\"\n this.checkLVal(expr.value, bindingType, checkClashes)\n break\n\n case \"ArrayPattern\":\n for (let elem of expr.elements) {\n if (elem) this.checkLVal(elem, bindingType, checkClashes)\n }\n break\n\n case \"AssignmentPattern\":\n this.checkLVal(expr.left, bindingType, checkClashes)\n break\n\n case \"RestElement\":\n this.checkLVal(expr.argument, bindingType, checkClashes)\n break\n\n case \"ParenthesizedExpression\":\n this.checkLVal(expr.expression, bindingType, checkClashes)\n break\n\n default:\n this.raise(expr.start, (bindingType ? \"Binding\" : \"Assigning to\") + \" rvalue\")\n }\n}\n","// A recursive descent parser operates by defining functions for all\n// syntactic elements, and recursively calling those, each function\n// advancing the input stream and returning an AST node. Precedence\n// of constructs (for example, the fact that `!x[1]` means `!(x[1])`\n// instead of `(!x)[1]` is handled by the fact that the parser\n// function that parses unary prefix operators is called first, and\n// in turn calls the function that parses `[]` subscripts — that\n// way, it'll receive the node for `x[1]` already parsed, and wraps\n// *that* in the unary operator node.\n//\n// Acorn uses an [operator precedence parser][opp] to handle binary\n// operator precedence, because it is much more compact than using\n// the technique outlined above, which uses different, nesting\n// functions to specify precedence, for all of the ten binary\n// precedence levels that JavaScript defines.\n//\n// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser\n\nimport {types as tt} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {DestructuringErrors} from \"./parseutil\"\nimport {lineBreak} from \"./whitespace\"\nimport {functionFlags, SCOPE_ARROW, BIND_OUTSIDE, BIND_VAR} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\n// Check if property name clashes with already added.\n// Object/class getters and setters are not allowed to clash —\n// either with each other or with an init property — and in\n// strict mode, init properties are also not allowed to be repeated.\n\npp.checkPropClash = function(prop, propHash, refDestructuringErrors) {\n if (this.options.ecmaVersion >= 9 && prop.type === \"SpreadElement\")\n return\n if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand))\n return\n let {key} = prop, name\n switch (key.type) {\n case \"Identifier\": name = key.name; break\n case \"Literal\": name = String(key.value); break\n default: return\n }\n let {kind} = prop\n if (this.options.ecmaVersion >= 6) {\n if (name === \"__proto__\" && kind === \"init\") {\n if (propHash.proto) {\n if (refDestructuringErrors && refDestructuringErrors.doubleProto < 0) refDestructuringErrors.doubleProto = key.start\n // Backwards-compat kludge. Can be removed in version 6.0\n else this.raiseRecoverable(key.start, \"Redefinition of __proto__ property\")\n }\n propHash.proto = true\n }\n return\n }\n name = \"$\" + name\n let other = propHash[name]\n if (other) {\n let redefinition\n if (kind === \"init\") {\n redefinition = this.strict && other.init || other.get || other.set\n } else {\n redefinition = other.init || other[kind]\n }\n if (redefinition)\n this.raiseRecoverable(key.start, \"Redefinition of property\")\n } else {\n other = propHash[name] = {\n init: false,\n get: false,\n set: false\n }\n }\n other[kind] = true\n}\n\n// ### Expression parsing\n\n// These nest, from the most general expression type at the top to\n// 'atomic', nondivisible expression types at the bottom. Most of\n// the functions will simply let the function(s) below them parse,\n// and, *if* the syntactic construct they handle is present, wrap\n// the AST node that the inner parser gave them in another node.\n\n// Parse a full expression. The optional arguments are used to\n// forbid the `in` operator (in for loops initalization expressions)\n// and provide reference for storing '=' operator inside shorthand\n// property assignment in contexts where both object expression\n// and object pattern might appear (so it's possible to raise\n// delayed syntax error at correct position).\n\npp.parseExpression = function(noIn, refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseMaybeAssign(noIn, refDestructuringErrors)\n if (this.type === tt.comma) {\n let node = this.startNodeAt(startPos, startLoc)\n node.expressions = [expr]\n while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn, refDestructuringErrors))\n return this.finishNode(node, \"SequenceExpression\")\n }\n return expr\n}\n\n// Parse an assignment expression. This includes applications of\n// operators like `+=`.\n\npp.parseMaybeAssign = function(noIn, refDestructuringErrors, afterLeftParse) {\n if (this.isContextual(\"yield\")) {\n if (this.inGenerator) return this.parseYield()\n // The tokenizer will assume an expression is allowed after\n // `yield`, but this isn't that kind of yield\n else this.exprAllowed = false\n }\n\n let ownDestructuringErrors = false, oldParenAssign = -1, oldTrailingComma = -1, oldShorthandAssign = -1\n if (refDestructuringErrors) {\n oldParenAssign = refDestructuringErrors.parenthesizedAssign\n oldTrailingComma = refDestructuringErrors.trailingComma\n oldShorthandAssign = refDestructuringErrors.shorthandAssign;\n refDestructuringErrors.parenthesizedAssign = refDestructuringErrors.trailingComma = refDestructuringErrors.shorthandAssign = -1\n } else {\n refDestructuringErrors = new DestructuringErrors\n ownDestructuringErrors = true\n }\n\n let startPos = this.start, startLoc = this.startLoc\n if (this.type === tt.parenL || this.type === tt.name)\n this.potentialArrowAt = this.start\n let left = this.parseMaybeConditional(noIn, refDestructuringErrors)\n if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc)\n if (this.type.isAssign) {\n let node = this.startNodeAt(startPos, startLoc)\n node.operator = this.value\n node.left = this.type === tt.eq ? this.toAssignable(left, false, refDestructuringErrors) : left\n if (!ownDestructuringErrors) DestructuringErrors.call(refDestructuringErrors)\n refDestructuringErrors.shorthandAssign = -1 // reset because shorthand default was used correctly\n this.checkLVal(left)\n this.next()\n node.right = this.parseMaybeAssign(noIn)\n return this.finishNode(node, \"AssignmentExpression\")\n } else {\n if (ownDestructuringErrors) this.checkExpressionErrors(refDestructuringErrors, true)\n }\n if (oldParenAssign > -1) refDestructuringErrors.parenthesizedAssign = oldParenAssign\n if (oldTrailingComma > -1) refDestructuringErrors.trailingComma = oldTrailingComma\n if (oldShorthandAssign > -1) refDestructuringErrors.shorthandAssign = oldShorthandAssign\n return left\n}\n\n// Parse a ternary conditional (`?:`) operator.\n\npp.parseMaybeConditional = function(noIn, refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseExprOps(noIn, refDestructuringErrors)\n if (this.checkExpressionErrors(refDestructuringErrors)) return expr\n if (this.eat(tt.question)) {\n let node = this.startNodeAt(startPos, startLoc)\n node.test = expr\n node.consequent = this.parseMaybeAssign()\n this.expect(tt.colon)\n node.alternate = this.parseMaybeAssign(noIn)\n return this.finishNode(node, \"ConditionalExpression\")\n }\n return expr\n}\n\n// Start the precedence parser.\n\npp.parseExprOps = function(noIn, refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseMaybeUnary(refDestructuringErrors, false)\n if (this.checkExpressionErrors(refDestructuringErrors)) return expr\n return expr.start === startPos && expr.type === \"ArrowFunctionExpression\" ? expr : this.parseExprOp(expr, startPos, startLoc, -1, noIn)\n}\n\n// Parse binary operators with the operator precedence parsing\n// algorithm. `left` is the left-hand side of the operator.\n// `minPrec` provides context that allows the function to stop and\n// defer further parser to one of its callers when it encounters an\n// operator that has a lower precedence than the set it is parsing.\n\npp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {\n let prec = this.type.binop\n if (prec != null && (!noIn || this.type !== tt._in)) {\n if (prec > minPrec) {\n let logical = this.type === tt.logicalOR || this.type === tt.logicalAND\n let op = this.value\n this.next()\n let startPos = this.start, startLoc = this.startLoc\n let right = this.parseExprOp(this.parseMaybeUnary(null, false), startPos, startLoc, prec, noIn)\n let node = this.buildBinary(leftStartPos, leftStartLoc, left, right, op, logical)\n return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn)\n }\n }\n return left\n}\n\npp.buildBinary = function(startPos, startLoc, left, right, op, logical) {\n let node = this.startNodeAt(startPos, startLoc)\n node.left = left\n node.operator = op\n node.right = right\n return this.finishNode(node, logical ? \"LogicalExpression\" : \"BinaryExpression\")\n}\n\n// Parse unary operators, both prefix and postfix.\n\npp.parseMaybeUnary = function(refDestructuringErrors, sawUnary) {\n let startPos = this.start, startLoc = this.startLoc, expr\n if (this.isContextual(\"await\") && (this.inAsync || (!this.inFunction && this.options.allowAwaitOutsideFunction))) {\n expr = this.parseAwait()\n sawUnary = true\n } else if (this.type.prefix) {\n let node = this.startNode(), update = this.type === tt.incDec\n node.operator = this.value\n node.prefix = true\n this.next()\n node.argument = this.parseMaybeUnary(null, true)\n this.checkExpressionErrors(refDestructuringErrors, true)\n if (update) this.checkLVal(node.argument)\n else if (this.strict && node.operator === \"delete\" &&\n node.argument.type === \"Identifier\")\n this.raiseRecoverable(node.start, \"Deleting local variable in strict mode\")\n else sawUnary = true\n expr = this.finishNode(node, update ? \"UpdateExpression\" : \"UnaryExpression\")\n } else {\n expr = this.parseExprSubscripts(refDestructuringErrors)\n if (this.checkExpressionErrors(refDestructuringErrors)) return expr\n while (this.type.postfix && !this.canInsertSemicolon()) {\n let node = this.startNodeAt(startPos, startLoc)\n node.operator = this.value\n node.prefix = false\n node.argument = expr\n this.checkLVal(expr)\n this.next()\n expr = this.finishNode(node, \"UpdateExpression\")\n }\n }\n\n if (!sawUnary && this.eat(tt.starstar))\n return this.buildBinary(startPos, startLoc, expr, this.parseMaybeUnary(null, false), \"**\", false)\n else\n return expr\n}\n\n// Parse call, dot, and `[]`-subscript expressions.\n\npp.parseExprSubscripts = function(refDestructuringErrors) {\n let startPos = this.start, startLoc = this.startLoc\n let expr = this.parseExprAtom(refDestructuringErrors)\n let skipArrowSubscripts = expr.type === \"ArrowFunctionExpression\" && this.input.slice(this.lastTokStart, this.lastTokEnd) !== \")\"\n if (this.checkExpressionErrors(refDestructuringErrors) || skipArrowSubscripts) return expr\n let result = this.parseSubscripts(expr, startPos, startLoc)\n if (refDestructuringErrors && result.type === \"MemberExpression\") {\n if (refDestructuringErrors.parenthesizedAssign >= result.start) refDestructuringErrors.parenthesizedAssign = -1\n if (refDestructuringErrors.parenthesizedBind >= result.start) refDestructuringErrors.parenthesizedBind = -1\n }\n return result\n}\n\npp.parseSubscripts = function(base, startPos, startLoc, noCalls) {\n let maybeAsyncArrow = this.options.ecmaVersion >= 8 && base.type === \"Identifier\" && base.name === \"async\" &&\n this.lastTokEnd === base.end && !this.canInsertSemicolon() && this.input.slice(base.start, base.end) === \"async\"\n for (let computed;;) {\n if ((computed = this.eat(tt.bracketL)) || this.eat(tt.dot)) {\n let node = this.startNodeAt(startPos, startLoc)\n node.object = base\n node.property = computed ? this.parseExpression() : this.parseIdent(true)\n node.computed = !!computed\n if (computed) this.expect(tt.bracketR)\n base = this.finishNode(node, \"MemberExpression\")\n } else if (!noCalls && this.eat(tt.parenL)) {\n let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos\n this.yieldPos = 0\n this.awaitPos = 0\n let exprList = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false, refDestructuringErrors)\n if (maybeAsyncArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {\n this.checkPatternErrors(refDestructuringErrors, false)\n this.checkYieldAwaitInDefaultParams()\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList, true)\n }\n this.checkExpressionErrors(refDestructuringErrors, true)\n this.yieldPos = oldYieldPos || this.yieldPos\n this.awaitPos = oldAwaitPos || this.awaitPos\n let node = this.startNodeAt(startPos, startLoc)\n node.callee = base\n node.arguments = exprList\n base = this.finishNode(node, \"CallExpression\")\n } else if (this.type === tt.backQuote) {\n let node = this.startNodeAt(startPos, startLoc)\n node.tag = base\n node.quasi = this.parseTemplate({isTagged: true})\n base = this.finishNode(node, \"TaggedTemplateExpression\")\n } else {\n return base\n }\n }\n}\n\n// Parse an atomic expression — either a single token that is an\n// expression, an expression started by a keyword like `function` or\n// `new`, or an expression wrapped in punctuation like `()`, `[]`,\n// or `{}`.\n\npp.parseExprAtom = function(refDestructuringErrors) {\n let node, canBeArrow = this.potentialArrowAt === this.start\n switch (this.type) {\n case tt._super:\n if (!this.inFunction)\n this.raise(this.start, \"'super' outside of function or class\")\n node = this.startNode()\n this.next()\n // The `super` keyword can appear at below:\n // SuperProperty:\n // super [ Expression ]\n // super . IdentifierName\n // SuperCall:\n // super Arguments\n if (this.type !== tt.dot && this.type !== tt.bracketL && this.type !== tt.parenL)\n this.unexpected()\n return this.finishNode(node, \"Super\")\n\n case tt._this:\n node = this.startNode()\n this.next()\n return this.finishNode(node, \"ThisExpression\")\n\n case tt.name:\n let startPos = this.start, startLoc = this.startLoc, containsEsc = this.containsEsc\n let id = this.parseIdent(this.type !== tt.name)\n if (this.options.ecmaVersion >= 8 && !containsEsc && id.name === \"async\" && !this.canInsertSemicolon() && this.eat(tt._function))\n return this.parseFunction(this.startNodeAt(startPos, startLoc), 0, false, true)\n if (canBeArrow && !this.canInsertSemicolon()) {\n if (this.eat(tt.arrow))\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], false)\n if (this.options.ecmaVersion >= 8 && id.name === \"async\" && this.type === tt.name && !containsEsc) {\n id = this.parseIdent()\n if (this.canInsertSemicolon() || !this.eat(tt.arrow))\n this.unexpected()\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), [id], true)\n }\n }\n return id\n\n case tt.regexp:\n let value = this.value\n node = this.parseLiteral(value.value)\n node.regex = {pattern: value.pattern, flags: value.flags}\n return node\n\n case tt.num: case tt.string:\n return this.parseLiteral(this.value)\n\n case tt._null: case tt._true: case tt._false:\n node = this.startNode()\n node.value = this.type === tt._null ? null : this.type === tt._true\n node.raw = this.type.keyword\n this.next()\n return this.finishNode(node, \"Literal\")\n\n case tt.parenL:\n let start = this.start, expr = this.parseParenAndDistinguishExpression(canBeArrow)\n if (refDestructuringErrors) {\n if (refDestructuringErrors.parenthesizedAssign < 0 && !this.isSimpleAssignTarget(expr))\n refDestructuringErrors.parenthesizedAssign = start\n if (refDestructuringErrors.parenthesizedBind < 0)\n refDestructuringErrors.parenthesizedBind = start\n }\n return expr\n\n case tt.bracketL:\n node = this.startNode()\n this.next()\n node.elements = this.parseExprList(tt.bracketR, true, true, refDestructuringErrors)\n return this.finishNode(node, \"ArrayExpression\")\n\n case tt.braceL:\n return this.parseObj(false, refDestructuringErrors)\n\n case tt._function:\n node = this.startNode()\n this.next()\n return this.parseFunction(node, 0)\n\n case tt._class:\n return this.parseClass(this.startNode(), false)\n\n case tt._new:\n return this.parseNew()\n\n case tt.backQuote:\n return this.parseTemplate()\n\n default:\n this.unexpected()\n }\n}\n\npp.parseLiteral = function(value) {\n let node = this.startNode()\n node.value = value\n node.raw = this.input.slice(this.start, this.end)\n this.next()\n return this.finishNode(node, \"Literal\")\n}\n\npp.parseParenExpression = function() {\n this.expect(tt.parenL)\n let val = this.parseExpression()\n this.expect(tt.parenR)\n return val\n}\n\npp.parseParenAndDistinguishExpression = function(canBeArrow) {\n let startPos = this.start, startLoc = this.startLoc, val, allowTrailingComma = this.options.ecmaVersion >= 8\n if (this.options.ecmaVersion >= 6) {\n this.next()\n\n let innerStartPos = this.start, innerStartLoc = this.startLoc\n let exprList = [], first = true, lastIsComma = false\n let refDestructuringErrors = new DestructuringErrors, oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos, spreadStart\n this.yieldPos = 0\n this.awaitPos = 0\n while (this.type !== tt.parenR) {\n first ? first = false : this.expect(tt.comma)\n if (allowTrailingComma && this.afterTrailingComma(tt.parenR, true)) {\n lastIsComma = true\n break\n } else if (this.type === tt.ellipsis) {\n spreadStart = this.start\n exprList.push(this.parseParenItem(this.parseRestBinding()))\n if (this.type === tt.comma) this.raise(this.start, \"Comma is not permitted after the rest element\")\n break\n } else {\n exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem))\n }\n }\n let innerEndPos = this.start, innerEndLoc = this.startLoc\n this.expect(tt.parenR)\n\n if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {\n this.checkPatternErrors(refDestructuringErrors, false)\n this.checkYieldAwaitInDefaultParams()\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.parseParenArrowList(startPos, startLoc, exprList)\n }\n\n if (!exprList.length || lastIsComma) this.unexpected(this.lastTokStart)\n if (spreadStart) this.unexpected(spreadStart)\n this.checkExpressionErrors(refDestructuringErrors, true)\n this.yieldPos = oldYieldPos || this.yieldPos\n this.awaitPos = oldAwaitPos || this.awaitPos\n\n if (exprList.length > 1) {\n val = this.startNodeAt(innerStartPos, innerStartLoc)\n val.expressions = exprList\n this.finishNodeAt(val, \"SequenceExpression\", innerEndPos, innerEndLoc)\n } else {\n val = exprList[0]\n }\n } else {\n val = this.parseParenExpression()\n }\n\n if (this.options.preserveParens) {\n let par = this.startNodeAt(startPos, startLoc)\n par.expression = val\n return this.finishNode(par, \"ParenthesizedExpression\")\n } else {\n return val\n }\n}\n\npp.parseParenItem = function(item) {\n return item\n}\n\npp.parseParenArrowList = function(startPos, startLoc, exprList) {\n return this.parseArrowExpression(this.startNodeAt(startPos, startLoc), exprList)\n}\n\n// New's precedence is slightly tricky. It must allow its argument to\n// be a `[]` or dot subscript expression, but not a call — at least,\n// not without wrapping it in parentheses. Thus, it uses the noCalls\n// argument to parseSubscripts to prevent it from consuming the\n// argument list.\n\nconst empty = []\n\npp.parseNew = function() {\n let node = this.startNode()\n let meta = this.parseIdent(true)\n if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) {\n node.meta = meta\n let containsEsc = this.containsEsc\n node.property = this.parseIdent(true)\n if (node.property.name !== \"target\" || containsEsc)\n this.raiseRecoverable(node.property.start, \"The only valid meta property for new is new.target\")\n if (!this.inNonArrowFunction())\n this.raiseRecoverable(node.start, \"new.target can only be used in functions\")\n return this.finishNode(node, \"MetaProperty\")\n }\n let startPos = this.start, startLoc = this.startLoc\n node.callee = this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true)\n if (this.eat(tt.parenL)) node.arguments = this.parseExprList(tt.parenR, this.options.ecmaVersion >= 8, false)\n else node.arguments = empty\n return this.finishNode(node, \"NewExpression\")\n}\n\n// Parse template expression.\n\npp.parseTemplateElement = function({isTagged}) {\n let elem = this.startNode()\n if (this.type === tt.invalidTemplate) {\n if (!isTagged) {\n this.raiseRecoverable(this.start, \"Bad escape sequence in untagged template literal\")\n }\n elem.value = {\n raw: this.value,\n cooked: null\n }\n } else {\n elem.value = {\n raw: this.input.slice(this.start, this.end).replace(/\\r\\n?/g, \"\\n\"),\n cooked: this.value\n }\n }\n this.next()\n elem.tail = this.type === tt.backQuote\n return this.finishNode(elem, \"TemplateElement\")\n}\n\npp.parseTemplate = function({isTagged = false} = {}) {\n let node = this.startNode()\n this.next()\n node.expressions = []\n let curElt = this.parseTemplateElement({isTagged})\n node.quasis = [curElt]\n while (!curElt.tail) {\n if (this.type === tt.eof) this.raise(this.pos, \"Unterminated template literal\")\n this.expect(tt.dollarBraceL)\n node.expressions.push(this.parseExpression())\n this.expect(tt.braceR)\n node.quasis.push(curElt = this.parseTemplateElement({isTagged}))\n }\n this.next()\n return this.finishNode(node, \"TemplateLiteral\")\n}\n\npp.isAsyncProp = function(prop) {\n return !prop.computed && prop.key.type === \"Identifier\" && prop.key.name === \"async\" &&\n (this.type === tt.name || this.type === tt.num || this.type === tt.string || this.type === tt.bracketL || this.type.keyword || (this.options.ecmaVersion >= 9 && this.type === tt.star)) &&\n !lineBreak.test(this.input.slice(this.lastTokEnd, this.start))\n}\n\n// Parse an object literal or binding pattern.\n\npp.parseObj = function(isPattern, refDestructuringErrors) {\n let node = this.startNode(), first = true, propHash = {}\n node.properties = []\n this.next()\n while (!this.eat(tt.braceR)) {\n if (!first) {\n this.expect(tt.comma)\n if (this.afterTrailingComma(tt.braceR)) break\n } else first = false\n\n const prop = this.parseProperty(isPattern, refDestructuringErrors)\n if (!isPattern) this.checkPropClash(prop, propHash, refDestructuringErrors)\n node.properties.push(prop)\n }\n return this.finishNode(node, isPattern ? \"ObjectPattern\" : \"ObjectExpression\")\n}\n\npp.parseProperty = function(isPattern, refDestructuringErrors) {\n let prop = this.startNode(), isGenerator, isAsync, startPos, startLoc\n if (this.options.ecmaVersion >= 9 && this.eat(tt.ellipsis)) {\n if (isPattern) {\n prop.argument = this.parseIdent(false)\n if (this.type === tt.comma) {\n this.raise(this.start, \"Comma is not permitted after the rest element\")\n }\n return this.finishNode(prop, \"RestElement\")\n }\n // To disallow parenthesized identifier via `this.toAssignable()`.\n if (this.type === tt.parenL && refDestructuringErrors) {\n if (refDestructuringErrors.parenthesizedAssign < 0) {\n refDestructuringErrors.parenthesizedAssign = this.start\n }\n if (refDestructuringErrors.parenthesizedBind < 0) {\n refDestructuringErrors.parenthesizedBind = this.start\n }\n }\n // Parse argument.\n prop.argument = this.parseMaybeAssign(false, refDestructuringErrors)\n // To disallow trailing comma via `this.toAssignable()`.\n if (this.type === tt.comma && refDestructuringErrors && refDestructuringErrors.trailingComma < 0) {\n refDestructuringErrors.trailingComma = this.start\n }\n // Finish\n return this.finishNode(prop, \"SpreadElement\")\n }\n if (this.options.ecmaVersion >= 6) {\n prop.method = false\n prop.shorthand = false\n if (isPattern || refDestructuringErrors) {\n startPos = this.start\n startLoc = this.startLoc\n }\n if (!isPattern)\n isGenerator = this.eat(tt.star)\n }\n let containsEsc = this.containsEsc\n this.parsePropertyName(prop)\n if (!isPattern && !containsEsc && this.options.ecmaVersion >= 8 && !isGenerator && this.isAsyncProp(prop)) {\n isAsync = true\n isGenerator = this.options.ecmaVersion >= 9 && this.eat(tt.star)\n this.parsePropertyName(prop, refDestructuringErrors)\n } else {\n isAsync = false\n }\n this.parsePropertyValue(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc)\n return this.finishNode(prop, \"Property\")\n}\n\npp.parsePropertyValue = function(prop, isPattern, isGenerator, isAsync, startPos, startLoc, refDestructuringErrors, containsEsc) {\n if ((isGenerator || isAsync) && this.type === tt.colon)\n this.unexpected()\n\n if (this.eat(tt.colon)) {\n prop.value = isPattern ? this.parseMaybeDefault(this.start, this.startLoc) : this.parseMaybeAssign(false, refDestructuringErrors)\n prop.kind = \"init\"\n } else if (this.options.ecmaVersion >= 6 && this.type === tt.parenL) {\n if (isPattern) this.unexpected()\n prop.kind = \"init\"\n prop.method = true\n prop.value = this.parseMethod(isGenerator, isAsync)\n } else if (!isPattern && !containsEsc &&\n this.options.ecmaVersion >= 5 && !prop.computed && prop.key.type === \"Identifier\" &&\n (prop.key.name === \"get\" || prop.key.name === \"set\") &&\n (this.type !== tt.comma && this.type !== tt.braceR)) {\n if (isGenerator || isAsync) this.unexpected()\n prop.kind = prop.key.name\n this.parsePropertyName(prop)\n prop.value = this.parseMethod(false)\n let paramCount = prop.kind === \"get\" ? 0 : 1\n if (prop.value.params.length !== paramCount) {\n let start = prop.value.start\n if (prop.kind === \"get\")\n this.raiseRecoverable(start, \"getter should have no params\")\n else\n this.raiseRecoverable(start, \"setter should have exactly one param\")\n } else {\n if (prop.kind === \"set\" && prop.value.params[0].type === \"RestElement\")\n this.raiseRecoverable(prop.value.params[0].start, \"Setter cannot use rest params\")\n }\n } else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === \"Identifier\") {\n this.checkUnreserved(prop.key)\n prop.kind = \"init\"\n if (isPattern) {\n prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)\n } else if (this.type === tt.eq && refDestructuringErrors) {\n if (refDestructuringErrors.shorthandAssign < 0)\n refDestructuringErrors.shorthandAssign = this.start\n prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key)\n } else {\n prop.value = prop.key\n }\n prop.shorthand = true\n } else this.unexpected()\n}\n\npp.parsePropertyName = function(prop) {\n if (this.options.ecmaVersion >= 6) {\n if (this.eat(tt.bracketL)) {\n prop.computed = true\n prop.key = this.parseMaybeAssign()\n this.expect(tt.bracketR)\n return prop.key\n } else {\n prop.computed = false\n }\n }\n return prop.key = this.type === tt.num || this.type === tt.string ? this.parseExprAtom() : this.parseIdent(true)\n}\n\n// Initialize empty function node.\n\npp.initFunction = function(node) {\n node.id = null\n if (this.options.ecmaVersion >= 6) node.generator = node.expression = false\n if (this.options.ecmaVersion >= 8) node.async = false\n}\n\n// Parse object or class method.\n\npp.parseMethod = function(isGenerator, isAsync) {\n let node = this.startNode(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos\n\n this.initFunction(node)\n if (this.options.ecmaVersion >= 6)\n node.generator = isGenerator\n if (this.options.ecmaVersion >= 8)\n node.async = !!isAsync\n\n this.yieldPos = 0\n this.awaitPos = 0\n this.enterScope(functionFlags(isAsync, node.generator))\n\n this.expect(tt.parenL)\n node.params = this.parseBindingList(tt.parenR, false, this.options.ecmaVersion >= 8)\n this.checkYieldAwaitInDefaultParams()\n this.parseFunctionBody(node, false)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.finishNode(node, \"FunctionExpression\")\n}\n\n// Parse arrow function expression with given parameters.\n\npp.parseArrowExpression = function(node, params, isAsync) {\n let oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos\n\n this.enterScope(functionFlags(isAsync, false) | SCOPE_ARROW)\n this.initFunction(node)\n if (this.options.ecmaVersion >= 8) node.async = !!isAsync\n\n this.yieldPos = 0\n this.awaitPos = 0\n\n node.params = this.toAssignableList(params, true)\n this.parseFunctionBody(node, true)\n\n this.yieldPos = oldYieldPos\n this.awaitPos = oldAwaitPos\n return this.finishNode(node, \"ArrowFunctionExpression\")\n}\n\n// Parse function body and check parameters.\n\npp.parseFunctionBody = function(node, isArrowFunction) {\n let isExpression = isArrowFunction && this.type !== tt.braceL\n let oldStrict = this.strict, useStrict = false\n\n if (isExpression) {\n node.body = this.parseMaybeAssign()\n node.expression = true\n this.checkParams(node, false)\n } else {\n let nonSimple = this.options.ecmaVersion >= 7 && !this.isSimpleParamList(node.params)\n if (!oldStrict || nonSimple) {\n useStrict = this.strictDirective(this.end)\n // If this is a strict mode function, verify that argument names\n // are not repeated, and it does not try to bind the words `eval`\n // or `arguments`.\n if (useStrict && nonSimple)\n this.raiseRecoverable(node.start, \"Illegal 'use strict' directive in function with non-simple parameter list\")\n }\n // Start a new scope with regard to labels and the `inFunction`\n // flag (restore them to their old value afterwards).\n let oldLabels = this.labels\n this.labels = []\n if (useStrict) this.strict = true\n\n // Add the params to varDeclaredNames to ensure that an error is thrown\n // if a let/const declaration in the function clashes with one of the params.\n this.checkParams(node, !oldStrict && !useStrict && !isArrowFunction && this.isSimpleParamList(node.params))\n node.body = this.parseBlock(false)\n node.expression = false\n this.adaptDirectivePrologue(node.body.body)\n this.labels = oldLabels\n }\n this.exitScope()\n\n // Ensure the function name isn't a forbidden identifier in strict mode, e.g. 'eval'\n if (this.strict && node.id) this.checkLVal(node.id, BIND_OUTSIDE)\n this.strict = oldStrict\n}\n\npp.isSimpleParamList = function(params) {\n for (let param of params)\n if (param.type !== \"Identifier\") return false\n return true\n}\n\n// Checks function params for various disallowed patterns such as using \"eval\"\n// or \"arguments\" and duplicate parameters.\n\npp.checkParams = function(node, allowDuplicates) {\n let nameHash = {}\n for (let param of node.params)\n this.checkLVal(param, BIND_VAR, allowDuplicates ? null : nameHash)\n}\n\n// Parses a comma-separated list of expressions, and returns them as\n// an array. `close` is the token type that ends the list, and\n// `allowEmpty` can be turned on to allow subsequent commas with\n// nothing in between them to be parsed as `null` (which is needed\n// for array literals).\n\npp.parseExprList = function(close, allowTrailingComma, allowEmpty, refDestructuringErrors) {\n let elts = [], first = true\n while (!this.eat(close)) {\n if (!first) {\n this.expect(tt.comma)\n if (allowTrailingComma && this.afterTrailingComma(close)) break\n } else first = false\n\n let elt\n if (allowEmpty && this.type === tt.comma)\n elt = null\n else if (this.type === tt.ellipsis) {\n elt = this.parseSpread(refDestructuringErrors)\n if (refDestructuringErrors && this.type === tt.comma && refDestructuringErrors.trailingComma < 0)\n refDestructuringErrors.trailingComma = this.start\n } else {\n elt = this.parseMaybeAssign(false, refDestructuringErrors)\n }\n elts.push(elt)\n }\n return elts\n}\n\npp.checkUnreserved = function({start, end, name}) {\n if (this.inGenerator && name === \"yield\")\n this.raiseRecoverable(start, \"Can not use 'yield' as identifier inside a generator\")\n if (this.inAsync && name === \"await\")\n this.raiseRecoverable(start, \"Can not use 'await' as identifier inside an async function\")\n if (this.keywords.test(name))\n this.raise(start, `Unexpected keyword '${name}'`)\n if (this.options.ecmaVersion < 6 &&\n this.input.slice(start, end).indexOf(\"\\\\\") !== -1) return\n const re = this.strict ? this.reservedWordsStrict : this.reservedWords\n if (re.test(name)) {\n if (!this.inAsync && name === \"await\")\n this.raiseRecoverable(start, \"Can not use keyword 'await' outside an async function\")\n this.raiseRecoverable(start, `The keyword '${name}' is reserved`)\n }\n}\n\n// Parse the next token as an identifier. If `liberal` is true (used\n// when parsing properties), it will also convert keywords into\n// identifiers.\n\npp.parseIdent = function(liberal, isBinding) {\n let node = this.startNode()\n if (liberal && this.options.allowReserved === \"never\") liberal = false\n if (this.type === tt.name) {\n node.name = this.value\n } else if (this.type.keyword) {\n node.name = this.type.keyword\n\n // To fix https://github.com/acornjs/acorn/issues/575\n // `class` and `function` keywords push new context into this.context.\n // But there is no chance to pop the context if the keyword is consumed as an identifier such as a property name.\n // If the previous token is a dot, this does not apply because the context-managing code already ignored the keyword\n if ((node.name === \"class\" || node.name === \"function\") &&\n (this.lastTokEnd !== this.lastTokStart + 1 || this.input.charCodeAt(this.lastTokStart) !== 46)) {\n this.context.pop()\n }\n } else {\n this.unexpected()\n }\n this.next()\n this.finishNode(node, \"Identifier\")\n if (!liberal) this.checkUnreserved(node)\n return node\n}\n\n// Parses yield expression inside generator.\n\npp.parseYield = function() {\n if (!this.yieldPos) this.yieldPos = this.start\n\n let node = this.startNode()\n this.next()\n if (this.type === tt.semi || this.canInsertSemicolon() || (this.type !== tt.star && !this.type.startsExpr)) {\n node.delegate = false\n node.argument = null\n } else {\n node.delegate = this.eat(tt.star)\n node.argument = this.parseMaybeAssign()\n }\n return this.finishNode(node, \"YieldExpression\")\n}\n\npp.parseAwait = function() {\n if (!this.awaitPos) this.awaitPos = this.start\n\n let node = this.startNode()\n this.next()\n node.argument = this.parseMaybeUnary(null, true)\n return this.finishNode(node, \"AwaitExpression\")\n}\n","import {Parser} from \"./state\"\nimport {Position, getLineInfo} from \"./locutil\"\n\nconst pp = Parser.prototype\n\n// This function is used to raise exceptions on parse errors. It\n// takes an offset integer (into the current `input`) to indicate\n// the location of the error, attaches the position to the end\n// of the error message, and then raises a `SyntaxError` with that\n// message.\n\npp.raise = function(pos, message) {\n let loc = getLineInfo(this.input, pos)\n message += \" (\" + loc.line + \":\" + loc.column + \")\"\n let err = new SyntaxError(message)\n err.pos = pos; err.loc = loc; err.raisedAt = this.pos\n throw err\n}\n\npp.raiseRecoverable = pp.raise\n\npp.curPosition = function() {\n if (this.options.locations) {\n return new Position(this.curLine, this.pos - this.lineStart)\n }\n}\n","import {Parser} from \"./state\"\nimport {SCOPE_VAR, SCOPE_FUNCTION, SCOPE_ARROW, SCOPE_SIMPLE_CATCH, BIND_LEXICAL, BIND_SIMPLE_CATCH, BIND_FUNCTION} from \"./scopeflags\"\n\nconst pp = Parser.prototype\n\nclass Scope {\n constructor(flags) {\n this.flags = flags\n // A list of var-declared names in the current lexical scope\n this.var = []\n // A list of lexically-declared names in the current lexical scope\n this.lexical = []\n }\n}\n\n// The functions in this module keep track of declared variables in the current scope in order to detect duplicate variable names.\n\npp.enterScope = function(flags) {\n this.scopeStack.push(new Scope(flags))\n}\n\npp.exitScope = function() {\n this.scopeStack.pop()\n}\n\npp.declareName = function(name, bindingType, pos) {\n let redeclared = false\n if (bindingType === BIND_LEXICAL) {\n const scope = this.currentScope()\n redeclared = scope.lexical.indexOf(name) > -1 || scope.var.indexOf(name) > -1\n scope.lexical.push(name)\n } else if (bindingType === BIND_SIMPLE_CATCH) {\n const scope = this.currentScope()\n scope.lexical.push(name)\n } else if (bindingType === BIND_FUNCTION) {\n const scope = this.currentScope()\n redeclared = scope.lexical.indexOf(name) > -1\n scope.var.push(name)\n } else {\n for (let i = this.scopeStack.length - 1; i >= 0; --i) {\n const scope = this.scopeStack[i]\n if (scope.lexical.indexOf(name) > -1 && !(scope.flags & SCOPE_SIMPLE_CATCH) && scope.lexical[0] === name) redeclared = true\n scope.var.push(name)\n if (scope.flags & SCOPE_VAR) break\n }\n }\n if (redeclared) this.raiseRecoverable(pos, `Identifier '${name}' has already been declared`)\n}\n\npp.currentScope = function() {\n return this.scopeStack[this.scopeStack.length - 1]\n}\n\npp.currentVarScope = function() {\n for (let i = this.scopeStack.length - 1;; i--) {\n let scope = this.scopeStack[i]\n if (scope.flags & SCOPE_VAR) return scope\n }\n}\n\npp.inNonArrowFunction = function() {\n for (let i = this.scopeStack.length - 1; i >= 0; i--)\n if (this.scopeStack[i].flags & SCOPE_FUNCTION && !(this.scopeStack[i].flags & SCOPE_ARROW)) return true\n return false\n}\n","import {Parser} from \"./state\"\nimport {SourceLocation} from \"./locutil\"\n\nexport class Node {\n constructor(parser, pos, loc) {\n this.type = \"\"\n this.start = pos\n this.end = 0\n if (parser.options.locations)\n this.loc = new SourceLocation(parser, loc)\n if (parser.options.directSourceFile)\n this.sourceFile = parser.options.directSourceFile\n if (parser.options.ranges)\n this.range = [pos, 0]\n }\n}\n\n// Start an AST node, attaching a start offset.\n\nconst pp = Parser.prototype\n\npp.startNode = function() {\n return new Node(this, this.start, this.startLoc)\n}\n\npp.startNodeAt = function(pos, loc) {\n return new Node(this, pos, loc)\n}\n\n// Finish an AST node, adding `type` and `end` properties.\n\nfunction finishNodeAt(node, type, pos, loc) {\n node.type = type\n node.end = pos\n if (this.options.locations)\n node.loc.end = loc\n if (this.options.ranges)\n node.range[1] = pos\n return node\n}\n\npp.finishNode = function(node, type) {\n return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc)\n}\n\n// Finish node at given position\n\npp.finishNodeAt = function(node, type, pos, loc) {\n return finishNodeAt.call(this, node, type, pos, loc)\n}\n","// The algorithm used to determine whether a regexp can appear at a\n// given point in the program is loosely based on sweet.js' approach.\n// See https://github.com/mozilla/sweet.js/wiki/design\n\nimport {Parser} from \"./state\"\nimport {types as tt} from \"./tokentype\"\nimport {lineBreak} from \"./whitespace\"\n\nexport class TokContext {\n constructor(token, isExpr, preserveSpace, override, generator) {\n this.token = token\n this.isExpr = !!isExpr\n this.preserveSpace = !!preserveSpace\n this.override = override\n this.generator = !!generator\n }\n}\n\nexport const types = {\n b_stat: new TokContext(\"{\", false),\n b_expr: new TokContext(\"{\", true),\n b_tmpl: new TokContext(\"${\", false),\n p_stat: new TokContext(\"(\", false),\n p_expr: new TokContext(\"(\", true),\n q_tmpl: new TokContext(\"`\", true, true, p => p.tryReadTemplateToken()),\n f_stat: new TokContext(\"function\", false),\n f_expr: new TokContext(\"function\", true),\n f_expr_gen: new TokContext(\"function\", true, false, null, true),\n f_gen: new TokContext(\"function\", false, false, null, true)\n}\n\nconst pp = Parser.prototype\n\npp.initialContext = function() {\n return [types.b_stat]\n}\n\npp.braceIsBlock = function(prevType) {\n let parent = this.curContext()\n if (parent === types.f_expr || parent === types.f_stat)\n return true\n if (prevType === tt.colon && (parent === types.b_stat || parent === types.b_expr))\n return !parent.isExpr\n\n // The check for `tt.name && exprAllowed` detects whether we are\n // after a `yield` or `of` construct. See the `updateContext` for\n // `tt.name`.\n if (prevType === tt._return || prevType === tt.name && this.exprAllowed)\n return lineBreak.test(this.input.slice(this.lastTokEnd, this.start))\n if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR || prevType === tt.arrow)\n return true\n if (prevType === tt.braceL)\n return parent === types.b_stat\n if (prevType === tt._var || prevType === tt.name)\n return false\n return !this.exprAllowed\n}\n\npp.inGeneratorContext = function() {\n for (let i = this.context.length - 1; i >= 1; i--) {\n let context = this.context[i]\n if (context.token === \"function\")\n return context.generator\n }\n return false\n}\n\npp.updateContext = function(prevType) {\n let update, type = this.type\n if (type.keyword && prevType === tt.dot)\n this.exprAllowed = false\n else if (update = type.updateContext)\n update.call(this, prevType)\n else\n this.exprAllowed = type.beforeExpr\n}\n\n// Token-specific context update code\n\ntt.parenR.updateContext = tt.braceR.updateContext = function() {\n if (this.context.length === 1) {\n this.exprAllowed = true\n return\n }\n let out = this.context.pop()\n if (out === types.b_stat && this.curContext().token === \"function\") {\n out = this.context.pop()\n }\n this.exprAllowed = !out.isExpr\n}\n\ntt.braceL.updateContext = function(prevType) {\n this.context.push(this.braceIsBlock(prevType) ? types.b_stat : types.b_expr)\n this.exprAllowed = true\n}\n\ntt.dollarBraceL.updateContext = function() {\n this.context.push(types.b_tmpl)\n this.exprAllowed = true\n}\n\ntt.parenL.updateContext = function(prevType) {\n let statementParens = prevType === tt._if || prevType === tt._for || prevType === tt._with || prevType === tt._while\n this.context.push(statementParens ? types.p_stat : types.p_expr)\n this.exprAllowed = true\n}\n\ntt.incDec.updateContext = function() {\n // tokExprAllowed stays unchanged\n}\n\ntt._function.updateContext = tt._class.updateContext = function(prevType) {\n if (prevType.beforeExpr && prevType !== tt.semi && prevType !== tt._else &&\n !((prevType === tt.colon || prevType === tt.braceL) && this.curContext() === types.b_stat))\n this.context.push(types.f_expr)\n else\n this.context.push(types.f_stat)\n this.exprAllowed = false\n}\n\ntt.backQuote.updateContext = function() {\n if (this.curContext() === types.q_tmpl)\n this.context.pop()\n else\n this.context.push(types.q_tmpl)\n this.exprAllowed = false\n}\n\ntt.star.updateContext = function(prevType) {\n if (prevType === tt._function) {\n let index = this.context.length - 1\n if (this.context[index] === types.f_expr)\n this.context[index] = types.f_expr_gen\n else\n this.context[index] = types.f_gen\n }\n this.exprAllowed = true\n}\n\ntt.name.updateContext = function(prevType) {\n let allowed = false\n if (this.options.ecmaVersion >= 6 && prevType !== tt.dot) {\n if (this.value === \"of\" && !this.exprAllowed ||\n this.value === \"yield\" && this.inGeneratorContext())\n allowed = true\n }\n this.exprAllowed = allowed\n}\n","const data = {\n \"$LONE\": [\n \"ASCII\",\n \"ASCII_Hex_Digit\",\n \"AHex\",\n \"Alphabetic\",\n \"Alpha\",\n \"Any\",\n \"Assigned\",\n \"Bidi_Control\",\n \"Bidi_C\",\n \"Bidi_Mirrored\",\n \"Bidi_M\",\n \"Case_Ignorable\",\n \"CI\",\n \"Cased\",\n \"Changes_When_Casefolded\",\n \"CWCF\",\n \"Changes_When_Casemapped\",\n \"CWCM\",\n \"Changes_When_Lowercased\",\n \"CWL\",\n \"Changes_When_NFKC_Casefolded\",\n \"CWKCF\",\n \"Changes_When_Titlecased\",\n \"CWT\",\n \"Changes_When_Uppercased\",\n \"CWU\",\n \"Dash\",\n \"Default_Ignorable_Code_Point\",\n \"DI\",\n \"Deprecated\",\n \"Dep\",\n \"Diacritic\",\n \"Dia\",\n \"Emoji\",\n \"Emoji_Component\",\n \"Emoji_Modifier\",\n \"Emoji_Modifier_Base\",\n \"Emoji_Presentation\",\n \"Extender\",\n \"Ext\",\n \"Grapheme_Base\",\n \"Gr_Base\",\n \"Grapheme_Extend\",\n \"Gr_Ext\",\n \"Hex_Digit\",\n \"Hex\",\n \"IDS_Binary_Operator\",\n \"IDSB\",\n \"IDS_Trinary_Operator\",\n \"IDST\",\n \"ID_Continue\",\n \"IDC\",\n \"ID_Start\",\n \"IDS\",\n \"Ideographic\",\n \"Ideo\",\n \"Join_Control\",\n \"Join_C\",\n \"Logical_Order_Exception\",\n \"LOE\",\n \"Lowercase\",\n \"Lower\",\n \"Math\",\n \"Noncharacter_Code_Point\",\n \"NChar\",\n \"Pattern_Syntax\",\n \"Pat_Syn\",\n \"Pattern_White_Space\",\n \"Pat_WS\",\n \"Quotation_Mark\",\n \"QMark\",\n \"Radical\",\n \"Regional_Indicator\",\n \"RI\",\n \"Sentence_Terminal\",\n \"STerm\",\n \"Soft_Dotted\",\n \"SD\",\n \"Terminal_Punctuation\",\n \"Term\",\n \"Unified_Ideograph\",\n \"UIdeo\",\n \"Uppercase\",\n \"Upper\",\n \"Variation_Selector\",\n \"VS\",\n \"White_Space\",\n \"space\",\n \"XID_Continue\",\n \"XIDC\",\n \"XID_Start\",\n \"XIDS\"\n ],\n \"General_Category\": [\n \"Cased_Letter\",\n \"LC\",\n \"Close_Punctuation\",\n \"Pe\",\n \"Connector_Punctuation\",\n \"Pc\",\n \"Control\",\n \"Cc\",\n \"cntrl\",\n \"Currency_Symbol\",\n \"Sc\",\n \"Dash_Punctuation\",\n \"Pd\",\n \"Decimal_Number\",\n \"Nd\",\n \"digit\",\n \"Enclosing_Mark\",\n \"Me\",\n \"Final_Punctuation\",\n \"Pf\",\n \"Format\",\n \"Cf\",\n \"Initial_Punctuation\",\n \"Pi\",\n \"Letter\",\n \"L\",\n \"Letter_Number\",\n \"Nl\",\n \"Line_Separator\",\n \"Zl\",\n \"Lowercase_Letter\",\n \"Ll\",\n \"Mark\",\n \"M\",\n \"Combining_Mark\",\n \"Math_Symbol\",\n \"Sm\",\n \"Modifier_Letter\",\n \"Lm\",\n \"Modifier_Symbol\",\n \"Sk\",\n \"Nonspacing_Mark\",\n \"Mn\",\n \"Number\",\n \"N\",\n \"Open_Punctuation\",\n \"Ps\",\n \"Other\",\n \"C\",\n \"Other_Letter\",\n \"Lo\",\n \"Other_Number\",\n \"No\",\n \"Other_Punctuation\",\n \"Po\",\n \"Other_Symbol\",\n \"So\",\n \"Paragraph_Separator\",\n \"Zp\",\n \"Private_Use\",\n \"Co\",\n \"Punctuation\",\n \"P\",\n \"punct\",\n \"Separator\",\n \"Z\",\n \"Space_Separator\",\n \"Zs\",\n \"Spacing_Mark\",\n \"Mc\",\n \"Surrogate\",\n \"Cs\",\n \"Symbol\",\n \"S\",\n \"Titlecase_Letter\",\n \"Lt\",\n \"Unassigned\",\n \"Cn\",\n \"Uppercase_Letter\",\n \"Lu\"\n ],\n \"Script\": [\n \"Adlam\",\n \"Adlm\",\n \"Ahom\",\n \"Anatolian_Hieroglyphs\",\n \"Hluw\",\n \"Arabic\",\n \"Arab\",\n \"Armenian\",\n \"Armn\",\n \"Avestan\",\n \"Avst\",\n \"Balinese\",\n \"Bali\",\n \"Bamum\",\n \"Bamu\",\n \"Bassa_Vah\",\n \"Bass\",\n \"Batak\",\n \"Batk\",\n \"Bengali\",\n \"Beng\",\n \"Bhaiksuki\",\n \"Bhks\",\n \"Bopomofo\",\n \"Bopo\",\n \"Brahmi\",\n \"Brah\",\n \"Braille\",\n \"Brai\",\n \"Buginese\",\n \"Bugi\",\n \"Buhid\",\n \"Buhd\",\n \"Canadian_Aboriginal\",\n \"Cans\",\n \"Carian\",\n \"Cari\",\n \"Caucasian_Albanian\",\n \"Aghb\",\n \"Chakma\",\n \"Cakm\",\n \"Cham\",\n \"Cherokee\",\n \"Cher\",\n \"Common\",\n \"Zyyy\",\n \"Coptic\",\n \"Copt\",\n \"Qaac\",\n \"Cuneiform\",\n \"Xsux\",\n \"Cypriot\",\n \"Cprt\",\n \"Cyrillic\",\n \"Cyrl\",\n \"Deseret\",\n \"Dsrt\",\n \"Devanagari\",\n \"Deva\",\n \"Duployan\",\n \"Dupl\",\n \"Egyptian_Hieroglyphs\",\n \"Egyp\",\n \"Elbasan\",\n \"Elba\",\n \"Ethiopic\",\n \"Ethi\",\n \"Georgian\",\n \"Geor\",\n \"Glagolitic\",\n \"Glag\",\n \"Gothic\",\n \"Goth\",\n \"Grantha\",\n \"Gran\",\n \"Greek\",\n \"Grek\",\n \"Gujarati\",\n \"Gujr\",\n \"Gurmukhi\",\n \"Guru\",\n \"Han\",\n \"Hani\",\n \"Hangul\",\n \"Hang\",\n \"Hanunoo\",\n \"Hano\",\n \"Hatran\",\n \"Hatr\",\n \"Hebrew\",\n \"Hebr\",\n \"Hiragana\",\n \"Hira\",\n \"Imperial_Aramaic\",\n \"Armi\",\n \"Inherited\",\n \"Zinh\",\n \"Qaai\",\n \"Inscriptional_Pahlavi\",\n \"Phli\",\n \"Inscriptional_Parthian\",\n \"Prti\",\n \"Javanese\",\n \"Java\",\n \"Kaithi\",\n \"Kthi\",\n \"Kannada\",\n \"Knda\",\n \"Katakana\",\n \"Kana\",\n \"Kayah_Li\",\n \"Kali\",\n \"Kharoshthi\",\n \"Khar\",\n \"Khmer\",\n \"Khmr\",\n \"Khojki\",\n \"Khoj\",\n \"Khudawadi\",\n \"Sind\",\n \"Lao\",\n \"Laoo\",\n \"Latin\",\n \"Latn\",\n \"Lepcha\",\n \"Lepc\",\n \"Limbu\",\n \"Limb\",\n \"Linear_A\",\n \"Lina\",\n \"Linear_B\",\n \"Linb\",\n \"Lisu\",\n \"Lycian\",\n \"Lyci\",\n \"Lydian\",\n \"Lydi\",\n \"Mahajani\",\n \"Mahj\",\n \"Malayalam\",\n \"Mlym\",\n \"Mandaic\",\n \"Mand\",\n \"Manichaean\",\n \"Mani\",\n \"Marchen\",\n \"Marc\",\n \"Masaram_Gondi\",\n \"Gonm\",\n \"Meetei_Mayek\",\n \"Mtei\",\n \"Mende_Kikakui\",\n \"Mend\",\n \"Meroitic_Cursive\",\n \"Merc\",\n \"Meroitic_Hieroglyphs\",\n \"Mero\",\n \"Miao\",\n \"Plrd\",\n \"Modi\",\n \"Mongolian\",\n \"Mong\",\n \"Mro\",\n \"Mroo\",\n \"Multani\",\n \"Mult\",\n \"Myanmar\",\n \"Mymr\",\n \"Nabataean\",\n \"Nbat\",\n \"New_Tai_Lue\",\n \"Talu\",\n \"Newa\",\n \"Nko\",\n \"Nkoo\",\n \"Nushu\",\n \"Nshu\",\n \"Ogham\",\n \"Ogam\",\n \"Ol_Chiki\",\n \"Olck\",\n \"Old_Hungarian\",\n \"Hung\",\n \"Old_Italic\",\n \"Ital\",\n \"Old_North_Arabian\",\n \"Narb\",\n \"Old_Permic\",\n \"Perm\",\n \"Old_Persian\",\n \"Xpeo\",\n \"Old_South_Arabian\",\n \"Sarb\",\n \"Old_Turkic\",\n \"Orkh\",\n \"Oriya\",\n \"Orya\",\n \"Osage\",\n \"Osge\",\n \"Osmanya\",\n \"Osma\",\n \"Pahawh_Hmong\",\n \"Hmng\",\n \"Palmyrene\",\n \"Palm\",\n \"Pau_Cin_Hau\",\n \"Pauc\",\n \"Phags_Pa\",\n \"Phag\",\n \"Phoenician\",\n \"Phnx\",\n \"Psalter_Pahlavi\",\n \"Phlp\",\n \"Rejang\",\n \"Rjng\",\n \"Runic\",\n \"Runr\",\n \"Samaritan\",\n \"Samr\",\n \"Saurashtra\",\n \"Saur\",\n \"Sharada\",\n \"Shrd\",\n \"Shavian\",\n \"Shaw\",\n \"Siddham\",\n \"Sidd\",\n \"SignWriting\",\n \"Sgnw\",\n \"Sinhala\",\n \"Sinh\",\n \"Sora_Sompeng\",\n \"Sora\",\n \"Soyombo\",\n \"Soyo\",\n \"Sundanese\",\n \"Sund\",\n \"Syloti_Nagri\",\n \"Sylo\",\n \"Syriac\",\n \"Syrc\",\n \"Tagalog\",\n \"Tglg\",\n \"Tagbanwa\",\n \"Tagb\",\n \"Tai_Le\",\n \"Tale\",\n \"Tai_Tham\",\n \"Lana\",\n \"Tai_Viet\",\n \"Tavt\",\n \"Takri\",\n \"Takr\",\n \"Tamil\",\n \"Taml\",\n \"Tangut\",\n \"Tang\",\n \"Telugu\",\n \"Telu\",\n \"Thaana\",\n \"Thaa\",\n \"Thai\",\n \"Tibetan\",\n \"Tibt\",\n \"Tifinagh\",\n \"Tfng\",\n \"Tirhuta\",\n \"Tirh\",\n \"Ugaritic\",\n \"Ugar\",\n \"Vai\",\n \"Vaii\",\n \"Warang_Citi\",\n \"Wara\",\n \"Yi\",\n \"Yiii\",\n \"Zanabazar_Square\",\n \"Zanb\"\n ]\n}\nArray.prototype.push.apply(data.$LONE, data.General_Category)\ndata.gc = data.General_Category\ndata.sc = data.Script_Extensions = data.scx = data.Script\n\nexport default data\n","import {isIdentifierStart, isIdentifierChar} from \"./identifier.js\"\nimport {Parser} from \"./state.js\"\nimport UNICODE_PROPERTY_VALUES from \"./unicode-property-data.js\"\n\nconst pp = Parser.prototype\n\nexport class RegExpValidationState {\n constructor(parser) {\n this.parser = parser\n this.validFlags = `gim${parser.options.ecmaVersion >= 6 ? \"uy\" : \"\"}${parser.options.ecmaVersion >= 9 ? \"s\" : \"\"}`\n this.source = \"\"\n this.flags = \"\"\n this.start = 0\n this.switchU = false\n this.switchN = false\n this.pos = 0\n this.lastIntValue = 0\n this.lastStringValue = \"\"\n this.lastAssertionIsQuantifiable = false\n this.numCapturingParens = 0\n this.maxBackReference = 0\n this.groupNames = []\n this.backReferenceNames = []\n }\n\n reset(start, pattern, flags) {\n const unicode = flags.indexOf(\"u\") !== -1\n this.start = start | 0\n this.source = pattern + \"\"\n this.flags = flags\n this.switchU = unicode && this.parser.options.ecmaVersion >= 6\n this.switchN = unicode && this.parser.options.ecmaVersion >= 9\n }\n\n raise(message) {\n this.parser.raiseRecoverable(this.start, `Invalid regular expression: /${this.source}/: ${message}`)\n }\n\n // If u flag is given, this returns the code point at the index (it combines a surrogate pair).\n // Otherwise, this returns the code unit of the index (can be a part of a surrogate pair).\n at(i) {\n const s = this.source\n const l = s.length\n if (i >= l) {\n return -1\n }\n const c = s.charCodeAt(i)\n if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) {\n return c\n }\n return (c << 10) + s.charCodeAt(i + 1) - 0x35FDC00\n }\n\n nextIndex(i) {\n const s = this.source\n const l = s.length\n if (i >= l) {\n return l\n }\n const c = s.charCodeAt(i)\n if (!this.switchU || c <= 0xD7FF || c >= 0xE000 || i + 1 >= l) {\n return i + 1\n }\n return i + 2\n }\n\n current() {\n return this.at(this.pos)\n }\n\n lookahead() {\n return this.at(this.nextIndex(this.pos))\n }\n\n advance() {\n this.pos = this.nextIndex(this.pos)\n }\n\n eat(ch) {\n if (this.current() === ch) {\n this.advance()\n return true\n }\n return false\n }\n}\n\nfunction codePointToString(ch) {\n if (ch <= 0xFFFF) return String.fromCharCode(ch)\n ch -= 0x10000\n return String.fromCharCode((ch >> 10) + 0xD800, (ch & 0x03FF) + 0xDC00)\n}\n\n/**\n * Validate the flags part of a given RegExpLiteral.\n *\n * @param {RegExpValidationState} state The state to validate RegExp.\n * @returns {void}\n */\npp.validateRegExpFlags = function(state) {\n const validFlags = state.validFlags\n const flags = state.flags\n\n for (let i = 0; i < flags.length; i++) {\n const flag = flags.charAt(i)\n if (validFlags.indexOf(flag) === -1) {\n this.raise(state.start, \"Invalid regular expression flag\")\n }\n if (flags.indexOf(flag, i + 1) > -1) {\n this.raise(state.start, \"Duplicate regular expression flag\")\n }\n }\n}\n\n/**\n * Validate the pattern part of a given RegExpLiteral.\n *\n * @param {RegExpValidationState} state The state to validate RegExp.\n * @returns {void}\n */\npp.validateRegExpPattern = function(state) {\n this.regexp_pattern(state)\n\n // The goal symbol for the parse is |Pattern[~U, ~N]|. If the result of\n // parsing contains a |GroupName|, reparse with the goal symbol\n // |Pattern[~U, +N]| and use this result instead. Throw a *SyntaxError*\n // exception if _P_ did not conform to the grammar, if any elements of _P_\n // were not matched by the parse, or if any Early Error conditions exist.\n if (!state.switchN && this.options.ecmaVersion >= 9 && state.groupNames.length > 0) {\n state.switchN = true\n this.regexp_pattern(state)\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Pattern\npp.regexp_pattern = function(state) {\n state.pos = 0\n state.lastIntValue = 0\n state.lastStringValue = \"\"\n state.lastAssertionIsQuantifiable = false\n state.numCapturingParens = 0\n state.maxBackReference = 0\n state.groupNames.length = 0\n state.backReferenceNames.length = 0\n\n this.regexp_disjunction(state)\n\n if (state.pos !== state.source.length) {\n // Make the same messages as V8.\n if (state.eat(0x29 /* ) */)) {\n state.raise(\"Unmatched ')'\")\n }\n if (state.eat(0x5D /* [ */) || state.eat(0x7D /* } */)) {\n state.raise(\"Lone quantifier brackets\")\n }\n }\n if (state.maxBackReference > state.numCapturingParens) {\n state.raise(\"Invalid escape\")\n }\n for (const name of state.backReferenceNames) {\n if (state.groupNames.indexOf(name) === -1) {\n state.raise(\"Invalid named capture referenced\")\n }\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Disjunction\npp.regexp_disjunction = function(state) {\n this.regexp_alternative(state)\n while (state.eat(0x7C /* | */)) {\n this.regexp_alternative(state)\n }\n\n // Make the same message as V8.\n if (this.regexp_eatQuantifier(state, true)) {\n state.raise(\"Nothing to repeat\")\n }\n if (state.eat(0x7B /* { */)) {\n state.raise(\"Lone quantifier brackets\")\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Alternative\npp.regexp_alternative = function(state) {\n while (state.pos < state.source.length && this.regexp_eatTerm(state))\n ;\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-Term\npp.regexp_eatTerm = function(state) {\n if (this.regexp_eatAssertion(state)) {\n // Handle `QuantifiableAssertion Quantifier` alternative.\n // `state.lastAssertionIsQuantifiable` is true if the last eaten Assertion\n // is a QuantifiableAssertion.\n if (state.lastAssertionIsQuantifiable && this.regexp_eatQuantifier(state)) {\n // Make the same message as V8.\n if (state.switchU) {\n state.raise(\"Invalid quantifier\")\n }\n }\n return true\n }\n\n if (state.switchU ? this.regexp_eatAtom(state) : this.regexp_eatExtendedAtom(state)) {\n this.regexp_eatQuantifier(state)\n return true\n }\n\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-Assertion\npp.regexp_eatAssertion = function(state) {\n const start = state.pos\n state.lastAssertionIsQuantifiable = false\n\n // ^, $\n if (state.eat(0x5E /* ^ */) || state.eat(0x24 /* $ */)) {\n return true\n }\n\n // \\b \\B\n if (state.eat(0x5C /* \\ */)) {\n if (state.eat(0x42 /* B */) || state.eat(0x62 /* b */)) {\n return true\n }\n state.pos = start\n }\n\n // Lookahead / Lookbehind\n if (state.eat(0x28 /* ( */) && state.eat(0x3F /* ? */)) {\n let lookbehind = false\n if (this.options.ecmaVersion >= 9) {\n lookbehind = state.eat(0x3C /* < */)\n }\n if (state.eat(0x3D /* = */) || state.eat(0x21 /* ! */)) {\n this.regexp_disjunction(state)\n if (!state.eat(0x29 /* ) */)) {\n state.raise(\"Unterminated group\")\n }\n state.lastAssertionIsQuantifiable = !lookbehind\n return true\n }\n }\n\n state.pos = start\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Quantifier\npp.regexp_eatQuantifier = function(state, noError = false) {\n if (this.regexp_eatQuantifierPrefix(state, noError)) {\n state.eat(0x3F /* ? */)\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-QuantifierPrefix\npp.regexp_eatQuantifierPrefix = function(state, noError) {\n return (\n state.eat(0x2A /* * */) ||\n state.eat(0x2B /* + */) ||\n state.eat(0x3F /* ? */) ||\n this.regexp_eatBracedQuantifier(state, noError)\n )\n}\npp.regexp_eatBracedQuantifier = function(state, noError) {\n const start = state.pos\n if (state.eat(0x7B /* { */)) {\n let min = 0, max = -1\n if (this.regexp_eatDecimalDigits(state)) {\n min = state.lastIntValue\n if (state.eat(0x2C /* , */) && this.regexp_eatDecimalDigits(state)) {\n max = state.lastIntValue\n }\n if (state.eat(0x7D /* } */)) {\n // SyntaxError in https://www.ecma-international.org/ecma-262/8.0/#sec-term\n if (max !== -1 && max < min && !noError) {\n state.raise(\"numbers out of order in {} quantifier\")\n }\n return true\n }\n }\n if (state.switchU && !noError) {\n state.raise(\"Incomplete quantifier\")\n }\n state.pos = start\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Atom\npp.regexp_eatAtom = function(state) {\n return (\n this.regexp_eatPatternCharacters(state) ||\n state.eat(0x2E /* . */) ||\n this.regexp_eatReverseSolidusAtomEscape(state) ||\n this.regexp_eatCharacterClass(state) ||\n this.regexp_eatUncapturingGroup(state) ||\n this.regexp_eatCapturingGroup(state)\n )\n}\npp.regexp_eatReverseSolidusAtomEscape = function(state) {\n const start = state.pos\n if (state.eat(0x5C /* \\ */)) {\n if (this.regexp_eatAtomEscape(state)) {\n return true\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatUncapturingGroup = function(state) {\n const start = state.pos\n if (state.eat(0x28 /* ( */)) {\n if (state.eat(0x3F /* ? */) && state.eat(0x3A /* : */)) {\n this.regexp_disjunction(state)\n if (state.eat(0x29 /* ) */)) {\n return true\n }\n state.raise(\"Unterminated group\")\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatCapturingGroup = function(state) {\n if (state.eat(0x28 /* ( */)) {\n if (this.options.ecmaVersion >= 9) {\n this.regexp_groupSpecifier(state)\n } else if (state.current() === 0x3F /* ? */) {\n state.raise(\"Invalid group\")\n }\n this.regexp_disjunction(state)\n if (state.eat(0x29 /* ) */)) {\n state.numCapturingParens += 1\n return true\n }\n state.raise(\"Unterminated group\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ExtendedAtom\npp.regexp_eatExtendedAtom = function(state) {\n return (\n state.eat(0x2E /* . */) ||\n this.regexp_eatReverseSolidusAtomEscape(state) ||\n this.regexp_eatCharacterClass(state) ||\n this.regexp_eatUncapturingGroup(state) ||\n this.regexp_eatCapturingGroup(state) ||\n this.regexp_eatInvalidBracedQuantifier(state) ||\n this.regexp_eatExtendedPatternCharacter(state)\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-InvalidBracedQuantifier\npp.regexp_eatInvalidBracedQuantifier = function(state) {\n if (this.regexp_eatBracedQuantifier(state, true)) {\n state.raise(\"Nothing to repeat\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-SyntaxCharacter\npp.regexp_eatSyntaxCharacter = function(state) {\n const ch = state.current()\n if (isSyntaxCharacter(ch)) {\n state.lastIntValue = ch\n state.advance()\n return true\n }\n return false\n}\nfunction isSyntaxCharacter(ch) {\n return (\n ch === 0x24 /* $ */ ||\n ch >= 0x28 /* ( */ && ch <= 0x2B /* + */ ||\n ch === 0x2E /* . */ ||\n ch === 0x3F /* ? */ ||\n ch >= 0x5B /* [ */ && ch <= 0x5E /* ^ */ ||\n ch >= 0x7B /* { */ && ch <= 0x7D /* } */\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-PatternCharacter\n// But eat eager.\npp.regexp_eatPatternCharacters = function(state) {\n const start = state.pos\n let ch = 0\n while ((ch = state.current()) !== -1 && !isSyntaxCharacter(ch)) {\n state.advance()\n }\n return state.pos !== start\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ExtendedPatternCharacter\npp.regexp_eatExtendedPatternCharacter = function(state) {\n const ch = state.current()\n if (\n ch !== -1 &&\n ch !== 0x24 /* $ */ &&\n !(ch >= 0x28 /* ( */ && ch <= 0x2B /* + */) &&\n ch !== 0x2E /* . */ &&\n ch !== 0x3F /* ? */ &&\n ch !== 0x5B /* [ */ &&\n ch !== 0x5E /* ^ */ &&\n ch !== 0x7C /* | */\n ) {\n state.advance()\n return true\n }\n return false\n}\n\n// GroupSpecifier[U] ::\n// [empty]\n// `?` GroupName[?U]\npp.regexp_groupSpecifier = function(state) {\n if (state.eat(0x3F /* ? */)) {\n if (this.regexp_eatGroupName(state)) {\n if (state.groupNames.indexOf(state.lastStringValue) !== -1) {\n state.raise(\"Duplicate capture group name\")\n }\n state.groupNames.push(state.lastStringValue)\n return\n }\n state.raise(\"Invalid group\")\n }\n}\n\n// GroupName[U] ::\n// `<` RegExpIdentifierName[?U] `>`\n// Note: this updates `state.lastStringValue` property with the eaten name.\npp.regexp_eatGroupName = function(state) {\n state.lastStringValue = \"\"\n if (state.eat(0x3C /* < */)) {\n if (this.regexp_eatRegExpIdentifierName(state) && state.eat(0x3E /* > */)) {\n return true\n }\n state.raise(\"Invalid capture group name\")\n }\n return false\n}\n\n// RegExpIdentifierName[U] ::\n// RegExpIdentifierStart[?U]\n// RegExpIdentifierName[?U] RegExpIdentifierPart[?U]\n// Note: this updates `state.lastStringValue` property with the eaten name.\npp.regexp_eatRegExpIdentifierName = function(state) {\n state.lastStringValue = \"\"\n if (this.regexp_eatRegExpIdentifierStart(state)) {\n state.lastStringValue += codePointToString(state.lastIntValue)\n while (this.regexp_eatRegExpIdentifierPart(state)) {\n state.lastStringValue += codePointToString(state.lastIntValue)\n }\n return true\n }\n return false\n}\n\n// RegExpIdentifierStart[U] ::\n// UnicodeIDStart\n// `$`\n// `_`\n// `\\` RegExpUnicodeEscapeSequence[?U]\npp.regexp_eatRegExpIdentifierStart = function(state) {\n const start = state.pos\n let ch = state.current()\n state.advance()\n\n if (ch === 0x5C /* \\ */ && this.regexp_eatRegExpUnicodeEscapeSequence(state)) {\n ch = state.lastIntValue\n }\n if (isRegExpIdentifierStart(ch)) {\n state.lastIntValue = ch\n return true\n }\n\n state.pos = start\n return false\n}\nfunction isRegExpIdentifierStart(ch) {\n return isIdentifierStart(ch, true) || ch === 0x24 /* $ */ || ch === 0x5F /* _ */\n}\n\n// RegExpIdentifierPart[U] ::\n// UnicodeIDContinue\n// `$`\n// `_`\n// `\\` RegExpUnicodeEscapeSequence[?U]\n// \n// \npp.regexp_eatRegExpIdentifierPart = function(state) {\n const start = state.pos\n let ch = state.current()\n state.advance()\n\n if (ch === 0x5C /* \\ */ && this.regexp_eatRegExpUnicodeEscapeSequence(state)) {\n ch = state.lastIntValue\n }\n if (isRegExpIdentifierPart(ch)) {\n state.lastIntValue = ch\n return true\n }\n\n state.pos = start\n return false\n}\nfunction isRegExpIdentifierPart(ch) {\n return isIdentifierChar(ch, true) || ch === 0x24 /* $ */ || ch === 0x5F /* _ */ || ch === 0x200C /* */ || ch === 0x200D /* */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-AtomEscape\npp.regexp_eatAtomEscape = function(state) {\n if (\n this.regexp_eatBackReference(state) ||\n this.regexp_eatCharacterClassEscape(state) ||\n this.regexp_eatCharacterEscape(state) ||\n (state.switchN && this.regexp_eatKGroupName(state))\n ) {\n return true\n }\n if (state.switchU) {\n // Make the same message as V8.\n if (state.current() === 0x63 /* c */) {\n state.raise(\"Invalid unicode escape\")\n }\n state.raise(\"Invalid escape\")\n }\n return false\n}\npp.regexp_eatBackReference = function(state) {\n const start = state.pos\n if (this.regexp_eatDecimalEscape(state)) {\n const n = state.lastIntValue\n if (state.switchU) {\n // For SyntaxError in https://www.ecma-international.org/ecma-262/8.0/#sec-atomescape\n if (n > state.maxBackReference) {\n state.maxBackReference = n\n }\n return true\n }\n if (n <= state.numCapturingParens) {\n return true\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatKGroupName = function(state) {\n if (state.eat(0x6B /* k */)) {\n if (this.regexp_eatGroupName(state)) {\n state.backReferenceNames.push(state.lastStringValue)\n return true\n }\n state.raise(\"Invalid named reference\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-CharacterEscape\npp.regexp_eatCharacterEscape = function(state) {\n return (\n this.regexp_eatControlEscape(state) ||\n this.regexp_eatCControlLetter(state) ||\n this.regexp_eatZero(state) ||\n this.regexp_eatHexEscapeSequence(state) ||\n this.regexp_eatRegExpUnicodeEscapeSequence(state) ||\n (!state.switchU && this.regexp_eatLegacyOctalEscapeSequence(state)) ||\n this.regexp_eatIdentityEscape(state)\n )\n}\npp.regexp_eatCControlLetter = function(state) {\n const start = state.pos\n if (state.eat(0x63 /* c */)) {\n if (this.regexp_eatControlLetter(state)) {\n return true\n }\n state.pos = start\n }\n return false\n}\npp.regexp_eatZero = function(state) {\n if (state.current() === 0x30 /* 0 */ && !isDecimalDigit(state.lookahead())) {\n state.lastIntValue = 0\n state.advance()\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ControlEscape\npp.regexp_eatControlEscape = function(state) {\n const ch = state.current()\n if (ch === 0x74 /* t */) {\n state.lastIntValue = 0x09 /* \\t */\n state.advance()\n return true\n }\n if (ch === 0x6E /* n */) {\n state.lastIntValue = 0x0A /* \\n */\n state.advance()\n return true\n }\n if (ch === 0x76 /* v */) {\n state.lastIntValue = 0x0B /* \\v */\n state.advance()\n return true\n }\n if (ch === 0x66 /* f */) {\n state.lastIntValue = 0x0C /* \\f */\n state.advance()\n return true\n }\n if (ch === 0x72 /* r */) {\n state.lastIntValue = 0x0D /* \\r */\n state.advance()\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ControlLetter\npp.regexp_eatControlLetter = function(state) {\n const ch = state.current()\n if (isControlLetter(ch)) {\n state.lastIntValue = ch % 0x20\n state.advance()\n return true\n }\n return false\n}\nfunction isControlLetter(ch) {\n return (\n (ch >= 0x41 /* A */ && ch <= 0x5A /* Z */) ||\n (ch >= 0x61 /* a */ && ch <= 0x7A /* z */)\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-RegExpUnicodeEscapeSequence\npp.regexp_eatRegExpUnicodeEscapeSequence = function(state) {\n const start = state.pos\n\n if (state.eat(0x75 /* u */)) {\n if (this.regexp_eatFixedHexDigits(state, 4)) {\n const lead = state.lastIntValue\n if (state.switchU && lead >= 0xD800 && lead <= 0xDBFF) {\n const leadSurrogateEnd = state.pos\n if (state.eat(0x5C /* \\ */) && state.eat(0x75 /* u */) && this.regexp_eatFixedHexDigits(state, 4)) {\n const trail = state.lastIntValue\n if (trail >= 0xDC00 && trail <= 0xDFFF) {\n state.lastIntValue = (lead - 0xD800) * 0x400 + (trail - 0xDC00) + 0x10000\n return true\n }\n }\n state.pos = leadSurrogateEnd\n state.lastIntValue = lead\n }\n return true\n }\n if (\n state.switchU &&\n state.eat(0x7B /* { */) &&\n this.regexp_eatHexDigits(state) &&\n state.eat(0x7D /* } */) &&\n isValidUnicode(state.lastIntValue)\n ) {\n return true\n }\n if (state.switchU) {\n state.raise(\"Invalid unicode escape\")\n }\n state.pos = start\n }\n\n return false\n}\nfunction isValidUnicode(ch) {\n return ch >= 0 && ch <= 0x10FFFF\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-IdentityEscape\npp.regexp_eatIdentityEscape = function(state) {\n if (state.switchU) {\n if (this.regexp_eatSyntaxCharacter(state)) {\n return true\n }\n if (state.eat(0x2F /* / */)) {\n state.lastIntValue = 0x2F /* / */\n return true\n }\n return false\n }\n\n const ch = state.current()\n if (ch !== 0x63 /* c */ && (!state.switchN || ch !== 0x6B /* k */)) {\n state.lastIntValue = ch\n state.advance()\n return true\n }\n\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-DecimalEscape\npp.regexp_eatDecimalEscape = function(state) {\n state.lastIntValue = 0\n let ch = state.current()\n if (ch >= 0x31 /* 1 */ && ch <= 0x39 /* 9 */) {\n do {\n state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30 /* 0 */)\n state.advance()\n } while ((ch = state.current()) >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */)\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-CharacterClassEscape\npp.regexp_eatCharacterClassEscape = function(state) {\n const ch = state.current()\n\n if (isCharacterClassEscape(ch)) {\n state.lastIntValue = -1\n state.advance()\n return true\n }\n\n if (\n state.switchU &&\n this.options.ecmaVersion >= 9 &&\n (ch === 0x50 /* P */ || ch === 0x70 /* p */)\n ) {\n state.lastIntValue = -1\n state.advance()\n if (\n state.eat(0x7B /* { */) &&\n this.regexp_eatUnicodePropertyValueExpression(state) &&\n state.eat(0x7D /* } */)\n ) {\n return true\n }\n state.raise(\"Invalid property name\")\n }\n\n return false\n}\nfunction isCharacterClassEscape(ch) {\n return (\n ch === 0x64 /* d */ ||\n ch === 0x44 /* D */ ||\n ch === 0x73 /* s */ ||\n ch === 0x53 /* S */ ||\n ch === 0x77 /* w */ ||\n ch === 0x57 /* W */\n )\n}\n\n// UnicodePropertyValueExpression ::\n// UnicodePropertyName `=` UnicodePropertyValue\n// LoneUnicodePropertyNameOrValue\npp.regexp_eatUnicodePropertyValueExpression = function(state) {\n const start = state.pos\n\n // UnicodePropertyName `=` UnicodePropertyValue\n if (this.regexp_eatUnicodePropertyName(state) && state.eat(0x3D /* = */)) {\n const name = state.lastStringValue\n if (this.regexp_eatUnicodePropertyValue(state)) {\n const value = state.lastStringValue\n this.regexp_validateUnicodePropertyNameAndValue(state, name, value)\n return true\n }\n }\n state.pos = start\n\n // LoneUnicodePropertyNameOrValue\n if (this.regexp_eatLoneUnicodePropertyNameOrValue(state)) {\n const nameOrValue = state.lastStringValue\n this.regexp_validateUnicodePropertyNameOrValue(state, nameOrValue)\n return true\n }\n return false\n}\npp.regexp_validateUnicodePropertyNameAndValue = function(state, name, value) {\n if (!UNICODE_PROPERTY_VALUES.hasOwnProperty(name) || UNICODE_PROPERTY_VALUES[name].indexOf(value) === -1) {\n state.raise(\"Invalid property name\")\n }\n}\npp.regexp_validateUnicodePropertyNameOrValue = function(state, nameOrValue) {\n if (UNICODE_PROPERTY_VALUES.$LONE.indexOf(nameOrValue) === -1) {\n state.raise(\"Invalid property name\")\n }\n}\n\n// UnicodePropertyName ::\n// UnicodePropertyNameCharacters\npp.regexp_eatUnicodePropertyName = function(state) {\n let ch = 0\n state.lastStringValue = \"\"\n while (isUnicodePropertyNameCharacter(ch = state.current())) {\n state.lastStringValue += codePointToString(ch)\n state.advance()\n }\n return state.lastStringValue !== \"\"\n}\nfunction isUnicodePropertyNameCharacter(ch) {\n return isControlLetter(ch) || ch === 0x5F /* _ */\n}\n\n// UnicodePropertyValue ::\n// UnicodePropertyValueCharacters\npp.regexp_eatUnicodePropertyValue = function(state) {\n let ch = 0\n state.lastStringValue = \"\"\n while (isUnicodePropertyValueCharacter(ch = state.current())) {\n state.lastStringValue += codePointToString(ch)\n state.advance()\n }\n return state.lastStringValue !== \"\"\n}\nfunction isUnicodePropertyValueCharacter(ch) {\n return isUnicodePropertyNameCharacter(ch) || isDecimalDigit(ch)\n}\n\n// LoneUnicodePropertyNameOrValue ::\n// UnicodePropertyValueCharacters\npp.regexp_eatLoneUnicodePropertyNameOrValue = function(state) {\n return this.regexp_eatUnicodePropertyValue(state)\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-CharacterClass\npp.regexp_eatCharacterClass = function(state) {\n if (state.eat(0x5B /* [ */)) {\n state.eat(0x5E /* ^ */)\n this.regexp_classRanges(state)\n if (state.eat(0x5D /* [ */)) {\n return true\n }\n // Unreachable since it threw \"unterminated regular expression\" error before.\n state.raise(\"Unterminated character class\")\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ClassRanges\n// https://www.ecma-international.org/ecma-262/8.0/#prod-NonemptyClassRanges\n// https://www.ecma-international.org/ecma-262/8.0/#prod-NonemptyClassRangesNoDash\npp.regexp_classRanges = function(state) {\n while (this.regexp_eatClassAtom(state)) {\n const left = state.lastIntValue\n if (state.eat(0x2D /* - */) && this.regexp_eatClassAtom(state)) {\n const right = state.lastIntValue\n if (state.switchU && (left === -1 || right === -1)) {\n state.raise(\"Invalid character class\")\n }\n if (left !== -1 && right !== -1 && left > right) {\n state.raise(\"Range out of order in character class\")\n }\n }\n }\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ClassAtom\n// https://www.ecma-international.org/ecma-262/8.0/#prod-ClassAtomNoDash\npp.regexp_eatClassAtom = function(state) {\n const start = state.pos\n\n if (state.eat(0x5C /* \\ */)) {\n if (this.regexp_eatClassEscape(state)) {\n return true\n }\n if (state.switchU) {\n // Make the same message as V8.\n const ch = state.current()\n if (ch === 0x63 /* c */ || isOctalDigit(ch)) {\n state.raise(\"Invalid class escape\")\n }\n state.raise(\"Invalid escape\")\n }\n state.pos = start\n }\n\n const ch = state.current()\n if (ch !== 0x5D /* [ */) {\n state.lastIntValue = ch\n state.advance()\n return true\n }\n\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ClassEscape\npp.regexp_eatClassEscape = function(state) {\n const start = state.pos\n\n if (state.eat(0x62 /* b */)) {\n state.lastIntValue = 0x08 /* */\n return true\n }\n\n if (state.switchU && state.eat(0x2D /* - */)) {\n state.lastIntValue = 0x2D /* - */\n return true\n }\n\n if (!state.switchU && state.eat(0x63 /* c */)) {\n if (this.regexp_eatClassControlLetter(state)) {\n return true\n }\n state.pos = start\n }\n\n return (\n this.regexp_eatCharacterClassEscape(state) ||\n this.regexp_eatCharacterEscape(state)\n )\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-ClassControlLetter\npp.regexp_eatClassControlLetter = function(state) {\n const ch = state.current()\n if (isDecimalDigit(ch) || ch === 0x5F /* _ */) {\n state.lastIntValue = ch % 0x20\n state.advance()\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-HexEscapeSequence\npp.regexp_eatHexEscapeSequence = function(state) {\n const start = state.pos\n if (state.eat(0x78 /* x */)) {\n if (this.regexp_eatFixedHexDigits(state, 2)) {\n return true\n }\n if (state.switchU) {\n state.raise(\"Invalid escape\")\n }\n state.pos = start\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-DecimalDigits\npp.regexp_eatDecimalDigits = function(state) {\n const start = state.pos\n let ch = 0\n state.lastIntValue = 0\n while (isDecimalDigit(ch = state.current())) {\n state.lastIntValue = 10 * state.lastIntValue + (ch - 0x30 /* 0 */)\n state.advance()\n }\n return state.pos !== start\n}\nfunction isDecimalDigit(ch) {\n return ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-HexDigits\npp.regexp_eatHexDigits = function(state) {\n const start = state.pos\n let ch = 0\n state.lastIntValue = 0\n while (isHexDigit(ch = state.current())) {\n state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch)\n state.advance()\n }\n return state.pos !== start\n}\nfunction isHexDigit(ch) {\n return (\n (ch >= 0x30 /* 0 */ && ch <= 0x39 /* 9 */) ||\n (ch >= 0x41 /* A */ && ch <= 0x46 /* F */) ||\n (ch >= 0x61 /* a */ && ch <= 0x66 /* f */)\n )\n}\nfunction hexToInt(ch) {\n if (ch >= 0x41 /* A */ && ch <= 0x46 /* F */) {\n return 10 + (ch - 0x41 /* A */)\n }\n if (ch >= 0x61 /* a */ && ch <= 0x66 /* f */) {\n return 10 + (ch - 0x61 /* a */)\n }\n return ch - 0x30 /* 0 */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-annexB-LegacyOctalEscapeSequence\n// Allows only 0-377(octal) i.e. 0-255(decimal).\npp.regexp_eatLegacyOctalEscapeSequence = function(state) {\n if (this.regexp_eatOctalDigit(state)) {\n const n1 = state.lastIntValue\n if (this.regexp_eatOctalDigit(state)) {\n const n2 = state.lastIntValue\n if (n1 <= 3 && this.regexp_eatOctalDigit(state)) {\n state.lastIntValue = n1 * 64 + n2 * 8 + state.lastIntValue\n } else {\n state.lastIntValue = n1 * 8 + n2\n }\n } else {\n state.lastIntValue = n1\n }\n return true\n }\n return false\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-OctalDigit\npp.regexp_eatOctalDigit = function(state) {\n const ch = state.current()\n if (isOctalDigit(ch)) {\n state.lastIntValue = ch - 0x30 /* 0 */\n state.advance()\n return true\n }\n state.lastIntValue = 0\n return false\n}\nfunction isOctalDigit(ch) {\n return ch >= 0x30 /* 0 */ && ch <= 0x37 /* 7 */\n}\n\n// https://www.ecma-international.org/ecma-262/8.0/#prod-Hex4Digits\n// https://www.ecma-international.org/ecma-262/8.0/#prod-HexDigit\n// And HexDigit HexDigit in https://www.ecma-international.org/ecma-262/8.0/#prod-HexEscapeSequence\npp.regexp_eatFixedHexDigits = function(state, length) {\n const start = state.pos\n state.lastIntValue = 0\n for (let i = 0; i < length; ++i) {\n const ch = state.current()\n if (!isHexDigit(ch)) {\n state.pos = start\n return false\n }\n state.lastIntValue = 16 * state.lastIntValue + hexToInt(ch)\n state.advance()\n }\n return true\n}\n","import {isIdentifierStart, isIdentifierChar} from \"./identifier\"\nimport {types as tt, keywords as keywordTypes} from \"./tokentype\"\nimport {Parser} from \"./state\"\nimport {SourceLocation} from \"./locutil\"\nimport {RegExpValidationState} from \"./regexp\"\nimport {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from \"./whitespace\"\n\n// Object type used to represent tokens. Note that normally, tokens\n// simply exist as properties on the parser object. This is only\n// used for the onToken callback and the external tokenizer.\n\nexport class Token {\n constructor(p) {\n this.type = p.type\n this.value = p.value\n this.start = p.start\n this.end = p.end\n if (p.options.locations)\n this.loc = new SourceLocation(p, p.startLoc, p.endLoc)\n if (p.options.ranges)\n this.range = [p.start, p.end]\n }\n}\n\n// ## Tokenizer\n\nconst pp = Parser.prototype\n\n// Move to the next token\n\npp.next = function() {\n if (this.options.onToken)\n this.options.onToken(new Token(this))\n\n this.lastTokEnd = this.end\n this.lastTokStart = this.start\n this.lastTokEndLoc = this.endLoc\n this.lastTokStartLoc = this.startLoc\n this.nextToken()\n}\n\npp.getToken = function() {\n this.next()\n return new Token(this)\n}\n\n// If we're in an ES6 environment, make parsers iterable\nif (typeof Symbol !== \"undefined\")\n pp[Symbol.iterator] = function() {\n return {\n next: () => {\n let token = this.getToken()\n return {\n done: token.type === tt.eof,\n value: token\n }\n }\n }\n }\n\n// Toggle strict mode. Re-reads the next number or string to please\n// pedantic tests (`\"use strict\"; 010;` should fail).\n\npp.curContext = function() {\n return this.context[this.context.length - 1]\n}\n\n// Read a single token, updating the parser object's token-related\n// properties.\n\npp.nextToken = function() {\n let curContext = this.curContext()\n if (!curContext || !curContext.preserveSpace) this.skipSpace()\n\n this.start = this.pos\n if (this.options.locations) this.startLoc = this.curPosition()\n if (this.pos >= this.input.length) return this.finishToken(tt.eof)\n\n if (curContext.override) return curContext.override(this)\n else this.readToken(this.fullCharCodeAtPos())\n}\n\npp.readToken = function(code) {\n // Identifier or keyword. '\\uXXXX' sequences are allowed in\n // identifiers, so '\\' also dispatches to that.\n if (isIdentifierStart(code, this.options.ecmaVersion >= 6) || code === 92 /* '\\' */)\n return this.readWord()\n\n return this.getTokenFromCode(code)\n}\n\npp.fullCharCodeAtPos = function() {\n let code = this.input.charCodeAt(this.pos)\n if (code <= 0xd7ff || code >= 0xe000) return code\n let next = this.input.charCodeAt(this.pos + 1)\n return (code << 10) + next - 0x35fdc00\n}\n\npp.skipBlockComment = function() {\n let startLoc = this.options.onComment && this.curPosition()\n let start = this.pos, end = this.input.indexOf(\"*/\", this.pos += 2)\n if (end === -1) this.raise(this.pos - 2, \"Unterminated comment\")\n this.pos = end + 2\n if (this.options.locations) {\n lineBreakG.lastIndex = start\n let match\n while ((match = lineBreakG.exec(this.input)) && match.index < this.pos) {\n ++this.curLine\n this.lineStart = match.index + match[0].length\n }\n }\n if (this.options.onComment)\n this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos,\n startLoc, this.curPosition())\n}\n\npp.skipLineComment = function(startSkip) {\n let start = this.pos\n let startLoc = this.options.onComment && this.curPosition()\n let ch = this.input.charCodeAt(this.pos += startSkip)\n while (this.pos < this.input.length && !isNewLine(ch)) {\n ch = this.input.charCodeAt(++this.pos)\n }\n if (this.options.onComment)\n this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos,\n startLoc, this.curPosition())\n}\n\n// Called at the start of the parse and after every token. Skips\n// whitespace and comments, and.\n\npp.skipSpace = function() {\n loop: while (this.pos < this.input.length) {\n let ch = this.input.charCodeAt(this.pos)\n switch (ch) {\n case 32: case 160: // ' '\n ++this.pos\n break\n case 13:\n if (this.input.charCodeAt(this.pos + 1) === 10) {\n ++this.pos\n }\n case 10: case 8232: case 8233:\n ++this.pos\n if (this.options.locations) {\n ++this.curLine\n this.lineStart = this.pos\n }\n break\n case 47: // '/'\n switch (this.input.charCodeAt(this.pos + 1)) {\n case 42: // '*'\n this.skipBlockComment()\n break\n case 47:\n this.skipLineComment(2)\n break\n default:\n break loop\n }\n break\n default:\n if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {\n ++this.pos\n } else {\n break loop\n }\n }\n }\n}\n\n// Called at the end of every token. Sets `end`, `val`, and\n// maintains `context` and `exprAllowed`, and skips the space after\n// the token, so that the next one's `start` will point at the\n// right position.\n\npp.finishToken = function(type, val) {\n this.end = this.pos\n if (this.options.locations) this.endLoc = this.curPosition()\n let prevType = this.type\n this.type = type\n this.value = val\n\n this.updateContext(prevType)\n}\n\n// ### Token reading\n\n// This is the function that is called to fetch the next token. It\n// is somewhat obscure, because it works in character codes rather\n// than characters, and because operator parsing has been inlined\n// into it.\n//\n// All in the name of speed.\n//\npp.readToken_dot = function() {\n let next = this.input.charCodeAt(this.pos + 1)\n if (next >= 48 && next <= 57) return this.readNumber(true)\n let next2 = this.input.charCodeAt(this.pos + 2)\n if (this.options.ecmaVersion >= 6 && next === 46 && next2 === 46) { // 46 = dot '.'\n this.pos += 3\n return this.finishToken(tt.ellipsis)\n } else {\n ++this.pos\n return this.finishToken(tt.dot)\n }\n}\n\npp.readToken_slash = function() { // '/'\n let next = this.input.charCodeAt(this.pos + 1)\n if (this.exprAllowed) { ++this.pos; return this.readRegexp() }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.slash, 1)\n}\n\npp.readToken_mult_modulo_exp = function(code) { // '%*'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n let tokentype = code === 42 ? tt.star : tt.modulo\n\n // exponentiation operator ** and **=\n if (this.options.ecmaVersion >= 7 && code === 42 && next === 42) {\n ++size\n tokentype = tt.starstar\n next = this.input.charCodeAt(this.pos + 2)\n }\n\n if (next === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tokentype, size)\n}\n\npp.readToken_pipe_amp = function(code) { // '|&'\n let next = this.input.charCodeAt(this.pos + 1)\n if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2)\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1)\n}\n\npp.readToken_caret = function() { // '^'\n let next = this.input.charCodeAt(this.pos + 1)\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.bitwiseXOR, 1)\n}\n\npp.readToken_plus_min = function(code) { // '+-'\n let next = this.input.charCodeAt(this.pos + 1)\n if (next === code) {\n if (next === 45 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 62 &&\n (this.lastTokEnd === 0 || lineBreak.test(this.input.slice(this.lastTokEnd, this.pos)))) {\n // A `-->` line comment\n this.skipLineComment(3)\n this.skipSpace()\n return this.nextToken()\n }\n return this.finishOp(tt.incDec, 2)\n }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.plusMin, 1)\n}\n\npp.readToken_lt_gt = function(code) { // '<>'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n if (next === code) {\n size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2\n if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tt.bitShift, size)\n }\n if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&\n this.input.charCodeAt(this.pos + 3) === 45) {\n // `` line comment\n this.skipLineComment(3)\n this.skipSpace()\n return this.nextToken()\n }\n return this.finishOp(tt.incDec, 2)\n }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.plusMin, 1)\n}\n\npp.readToken_lt_gt = function(code) { // '<>'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n if (next === code) {\n size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2\n if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tt.bitShift, size)\n }\n if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&\n this.input.charCodeAt(this.pos + 3) === 45) {\n // `` line comment\n this.skipLineComment(3)\n this.skipSpace()\n return this.nextToken()\n }\n return this.finishOp(tt.incDec, 2)\n }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.plusMin, 1)\n}\n\npp.readToken_lt_gt = function(code) { // '<>'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n if (next === code) {\n size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2\n if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tt.bitShift, size)\n }\n if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&\n this.input.charCodeAt(this.pos + 3) === 45) {\n // `` line comment\n this.skipLineComment(3)\n this.skipSpace()\n return this.nextToken()\n }\n return this.finishOp(tt.incDec, 2)\n }\n if (next === 61) return this.finishOp(tt.assign, 2)\n return this.finishOp(tt.plusMin, 1)\n}\n\npp.readToken_lt_gt = function(code) { // '<>'\n let next = this.input.charCodeAt(this.pos + 1)\n let size = 1\n if (next === code) {\n size = code === 62 && this.input.charCodeAt(this.pos + 2) === 62 ? 3 : 2\n if (this.input.charCodeAt(this.pos + size) === 61) return this.finishOp(tt.assign, size + 1)\n return this.finishOp(tt.bitShift, size)\n }\n if (next === 33 && code === 60 && !this.inModule && this.input.charCodeAt(this.pos + 2) === 45 &&\n this.input.charCodeAt(this.pos + 3) === 45) {\n // ` - - - -Implementation of function.prototype.bind - -## Example - -I mainly do this for unit tests I run on phantomjs. -PhantomJS does not have Function.prototype.bind :( - -```js -Function.prototype.bind = require("function-bind") -``` - -## Installation - -`npm install function-bind` - -## Contributors - - - Raynos - -## MIT Licenced - - [travis-svg]: https://travis-ci.org/Raynos/function-bind.svg - [travis-url]: https://travis-ci.org/Raynos/function-bind - [npm-badge-svg]: https://badge.fury.io/js/function-bind.svg - [npm-url]: https://npmjs.org/package/function-bind - [5]: https://coveralls.io/repos/Raynos/function-bind/badge.png - [6]: https://coveralls.io/r/Raynos/function-bind - [7]: https://gemnasium.com/Raynos/function-bind.png - [8]: https://gemnasium.com/Raynos/function-bind - [deps-svg]: https://david-dm.org/Raynos/function-bind.svg - [deps-url]: https://david-dm.org/Raynos/function-bind - [dev-deps-svg]: https://david-dm.org/Raynos/function-bind/dev-status.svg - [dev-deps-url]: https://david-dm.org/Raynos/function-bind#info=devDependencies - [11]: https://ci.testling.com/Raynos/function-bind.png - [12]: https://ci.testling.com/Raynos/function-bind diff --git a/tools/node_modules/eslint/node_modules/function-bind/implementation.js b/tools/node_modules/eslint/node_modules/function-bind/implementation.js deleted file mode 100644 index cc4daec1b080a1..00000000000000 --- a/tools/node_modules/eslint/node_modules/function-bind/implementation.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -/* eslint no-invalid-this: 1 */ - -var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; -var slice = Array.prototype.slice; -var toStr = Object.prototype.toString; -var funcType = '[object Function]'; - -module.exports = function bind(that) { - var target = this; - if (typeof target !== 'function' || toStr.call(target) !== funcType) { - throw new TypeError(ERROR_MESSAGE + target); - } - var args = slice.call(arguments, 1); - - var bound; - var binder = function () { - if (this instanceof bound) { - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - } - }; - - var boundLength = Math.max(0, target.length - args.length); - var boundArgs = []; - for (var i = 0; i < boundLength; i++) { - boundArgs.push('$' + i); - } - - bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); - - if (target.prototype) { - var Empty = function Empty() {}; - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - Empty.prototype = null; - } - - return bound; -}; diff --git a/tools/node_modules/eslint/node_modules/function-bind/index.js b/tools/node_modules/eslint/node_modules/function-bind/index.js deleted file mode 100644 index 3bb6b9609889f8..00000000000000 --- a/tools/node_modules/eslint/node_modules/function-bind/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var implementation = require('./implementation'); - -module.exports = Function.prototype.bind || implementation; diff --git a/tools/node_modules/eslint/node_modules/function-bind/package.json b/tools/node_modules/eslint/node_modules/function-bind/package.json deleted file mode 100644 index 6574255758b8bc..00000000000000 --- a/tools/node_modules/eslint/node_modules/function-bind/package.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "author": { - "name": "Raynos", - "email": "raynos2@gmail.com" - }, - "bugs": { - "url": "https://github.com/Raynos/function-bind/issues", - "email": "raynos2@gmail.com" - }, - "bundleDependencies": false, - "contributors": [ - { - "name": "Raynos" - }, - { - "name": "Jordan Harband", - "url": "https://github.com/ljharb" - } - ], - "dependencies": {}, - "deprecated": false, - "description": "Implementation of Function.prototype.bind", - "devDependencies": { - "@ljharb/eslint-config": "^12.2.1", - "covert": "^1.1.0", - "eslint": "^4.5.0", - "jscs": "^3.0.7", - "tape": "^4.8.0" - }, - "homepage": "https://github.com/Raynos/function-bind", - "keywords": [ - "function", - "bind", - "shim", - "es5" - ], - "license": "MIT", - "main": "index", - "name": "function-bind", - "repository": { - "type": "git", - "url": "git://github.com/Raynos/function-bind.git" - }, - "scripts": { - "coverage": "covert test/*.js", - "eslint": "eslint *.js */*.js", - "jscs": "jscs *.js */*.js", - "lint": "npm run jscs && npm run eslint", - "posttest": "npm run coverage -- --quiet", - "pretest": "npm run lint", - "test": "npm run tests-only", - "tests-only": "node test" - }, - "testling": { - "files": "test/index.js", - "browsers": [ - "ie/8..latest", - "firefox/16..latest", - "firefox/nightly", - "chrome/22..latest", - "chrome/canary", - "opera/12..latest", - "opera/next", - "safari/5.1..latest", - "ipad/6.0..latest", - "iphone/6.0..latest", - "android-browser/4.2..latest" - ] - }, - "version": "1.1.1" -} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/globby/index.js b/tools/node_modules/eslint/node_modules/globby/index.js index 39da9f64d1ee42..587a0fdd1cc0fb 100644 --- a/tools/node_modules/eslint/node_modules/globby/index.js +++ b/tools/node_modules/eslint/node_modules/globby/index.js @@ -3,7 +3,6 @@ var Promise = require('pinkie-promise'); var arrayUnion = require('array-union'); var objectAssign = require('object-assign'); var glob = require('glob'); -var arrify = require('arrify'); var pify = require('pify'); var globP = pify(glob, Promise).bind(glob); @@ -12,10 +11,22 @@ function isNegative(pattern) { return pattern[0] === '!'; } +function isString(value) { + return typeof value === 'string'; +} + +function assertPatternsInput(patterns) { + if (!patterns.every(isString)) { + throw new TypeError('patterns must be a string or an array of strings'); + } +} + function generateGlobTasks(patterns, opts) { + patterns = [].concat(patterns); + assertPatternsInput(patterns); + var globTasks = []; - patterns = arrify(patterns); opts = objectAssign({ cache: Object.create(null), statCache: Object.create(null), @@ -45,7 +56,13 @@ function generateGlobTasks(patterns, opts) { } module.exports = function (patterns, opts) { - var globTasks = generateGlobTasks(patterns, opts); + var globTasks; + + try { + globTasks = generateGlobTasks(patterns, opts); + } catch (err) { + return Promise.reject(err); + } return Promise.all(globTasks.map(function (task) { return globP(task.pattern, task.opts); @@ -63,3 +80,9 @@ module.exports.sync = function (patterns, opts) { }; module.exports.generateGlobTasks = generateGlobTasks; + +module.exports.hasMagic = function (patterns, opts) { + return [].concat(patterns).some(function (pattern) { + return glob.hasMagic(pattern, opts); + }); +}; diff --git a/tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js new file mode 100644 index 00000000000000..7c720ebee88727 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/index.js @@ -0,0 +1,68 @@ +'use strict'; + +var processFn = function (fn, P, opts) { + return function () { + var that = this; + var args = new Array(arguments.length); + + for (var i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } + + return new P(function (resolve, reject) { + args.push(function (err, result) { + if (err) { + reject(err); + } else if (opts.multiArgs) { + var results = new Array(arguments.length - 1); + + for (var i = 1; i < arguments.length; i++) { + results[i - 1] = arguments[i]; + } + + resolve(results); + } else { + resolve(result); + } + }); + + fn.apply(that, args); + }); + }; +}; + +var pify = module.exports = function (obj, P, opts) { + if (typeof P !== 'function') { + opts = P; + P = Promise; + } + + opts = opts || {}; + opts.exclude = opts.exclude || [/.+Sync$/]; + + var filter = function (key) { + var match = function (pattern) { + return typeof pattern === 'string' ? key === pattern : pattern.test(key); + }; + + return opts.include ? opts.include.some(match) : !opts.exclude.some(match); + }; + + var ret = typeof obj === 'function' ? function () { + if (opts.excludeMain) { + return obj.apply(this, arguments); + } + + return processFn(obj, P, opts).apply(this, arguments); + } : {}; + + return Object.keys(obj).reduce(function (ret, key) { + var x = obj[key]; + + ret[key] = typeof x === 'function' && filter(key) ? processFn(x, P, opts) : x; + + return ret; + }, ret); +}; + +pify.all = pify; diff --git a/tools/node_modules/eslint/node_modules/arrify/license b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/license similarity index 100% rename from tools/node_modules/eslint/node_modules/arrify/license rename to tools/node_modules/eslint/node_modules/globby/node_modules/pify/license diff --git a/tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json new file mode 100644 index 00000000000000..40780115cf1d0a --- /dev/null +++ b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/package.json @@ -0,0 +1,57 @@ +{ + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/sindresorhus/pify/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Promisify a callback-style function", + "devDependencies": { + "ava": "*", + "pinkie-promise": "^1.0.0", + "v8-natives": "0.0.2", + "xo": "*" + }, + "engines": { + "node": ">=0.10.0" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/sindresorhus/pify#readme", + "keywords": [ + "promise", + "promises", + "promisify", + "denodify", + "denodeify", + "callback", + "cb", + "node", + "then", + "thenify", + "convert", + "transform", + "wrap", + "wrapper", + "bind", + "to", + "async", + "es2015" + ], + "license": "MIT", + "name": "pify", + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/pify.git" + }, + "scripts": { + "optimization-test": "node --allow-natives-syntax optimization-test.js", + "test": "xo && ava && npm run optimization-test" + }, + "version": "2.3.0" +} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md new file mode 100644 index 00000000000000..97aeeb628b0897 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/globby/node_modules/pify/readme.md @@ -0,0 +1,119 @@ +# pify [![Build Status](https://travis-ci.org/sindresorhus/pify.svg?branch=master)](https://travis-ci.org/sindresorhus/pify) + +> Promisify a callback-style function + + +## Install + +``` +$ npm install --save pify +``` + + +## Usage + +```js +const fs = require('fs'); +const pify = require('pify'); + +// promisify a single function + +pify(fs.readFile)('package.json', 'utf8').then(data => { + console.log(JSON.parse(data).name); + //=> 'pify' +}); + +// or promisify all methods in a module + +pify(fs).readFile('package.json', 'utf8').then(data => { + console.log(JSON.parse(data).name); + //=> 'pify' +}); +``` + + +## API + +### pify(input, [promiseModule], [options]) + +Returns a promise wrapped version of the supplied function or module. + +#### input + +Type: `function`, `object` + +Callback-style function or module whose methods you want to promisify. + +#### promiseModule + +Type: `function` + +Custom promise module to use instead of the native one. + +Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill. + +#### options + +##### multiArgs + +Type: `boolean` +Default: `false` + +By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. + +```js +const request = require('request'); +const pify = require('pify'); + +pify(request, {multiArgs: true})('https://sindresorhus.com').then(result => { + const [httpResponse, body] = result; +}); +``` + +##### include + +Type: `array` of (`string`|`regex`) + +Methods in a module to promisify. Remaining methods will be left untouched. + +##### exclude + +Type: `array` of (`string`|`regex`) +Default: `[/.+Sync$/]` + +Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default. + +##### excludeMain + +Type: `boolean` +Default: `false` + +By default, if given module is a function itself, this function will be promisified. Turn this option on if you want to promisify only methods of the module. + +```js +const pify = require('pify'); + +function fn() { + return true; +} + +fn.method = (data, callback) => { + setImmediate(() => { + callback(data, null); + }); +}; + +// promisify methods but not fn() +const promiseFn = pify(fn, {excludeMain: true}); + +if (promiseFn()) { + promiseFn.method('hi').then(data => { + console.log(data); + }); +} +``` + + +## License + +MIT © [Sindre Sorhus](http://sindresorhus.com) diff --git a/tools/node_modules/eslint/node_modules/globby/package.json b/tools/node_modules/eslint/node_modules/globby/package.json index 34b15123bb0008..fad7fc179674cb 100644 --- a/tools/node_modules/eslint/node_modules/globby/package.json +++ b/tools/node_modules/eslint/node_modules/globby/package.json @@ -10,7 +10,6 @@ "bundleDependencies": false, "dependencies": { "array-union": "^1.0.1", - "arrify": "^1.0.0", "glob": "^7.0.3", "object-assign": "^4.0.1", "pify": "^2.0.0", @@ -20,11 +19,11 @@ "description": "Extends `glob` with support for multiple patterns and exposes a Promise API", "devDependencies": { "ava": "*", - "glob-stream": "github:wearefractal/glob-stream#master", + "glob-stream": "github:gulpjs/glob-stream#master", "globby": "github:sindresorhus/globby#master", "matcha": "^0.7.0", "rimraf": "^2.2.8", - "xo": "*" + "xo": "^0.16.0" }, "engines": { "node": ">=0.10.0" @@ -72,8 +71,8 @@ "url": "git+https://github.com/sindresorhus/globby.git" }, "scripts": { - "bench": "npm update globby glob-stream && matcha bench.js", + "bench": "npm update glob-stream && matcha bench.js", "test": "xo && ava" }, - "version": "5.0.0" + "version": "6.1.0" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/globby/readme.md b/tools/node_modules/eslint/node_modules/globby/readme.md index aad991d020b1b5..e10a48868f9e29 100644 --- a/tools/node_modules/eslint/node_modules/globby/readme.md +++ b/tools/node_modules/eslint/node_modules/globby/readme.md @@ -42,11 +42,17 @@ Returns an array of matching paths. Returns an array of objects in the format `{ pattern: string, opts: Object }`, which can be passed as arguments to [`node-glob`](https://github.com/isaacs/node-glob). This is useful for other globbing-related packages. -Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, create a new tasks list to ensure that file system changes are taken in consideration. +Note that you should avoid running the same tasks multiple times as they contain a file system cache. Instead, run this method each time to ensure file system changes are taken into consideration. + +### globby.hasMagic(patterns, [options]) + +Returns a `boolean` of whether there are any special glob characters in the `patterns`. + +Note that the options affect the results. If `noext: true` is set, then `+(a|b)` will not be considered a magic pattern. If the pattern has a brace expansion, like `a/{b/c,x/y}`, then that is considered magical, unless `nobrace: true` is set. #### patterns -Type: `string`, `Array` +Type: `string` `Array` See supported `minimatch` [patterns](https://github.com/isaacs/minimatch#usage). diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/fs.js b/tools/node_modules/eslint/node_modules/graceful-fs/clone.js similarity index 88% rename from tools/node_modules/eslint/node_modules/graceful-fs/fs.js rename to tools/node_modules/eslint/node_modules/graceful-fs/clone.js index 8ad4a383965b7b..028356c96ed536 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/fs.js +++ b/tools/node_modules/eslint/node_modules/graceful-fs/clone.js @@ -1,8 +1,6 @@ 'use strict' -var fs = require('fs') - -module.exports = clone(fs) +module.exports = clone function clone (obj) { if (obj === null || typeof obj !== 'object') diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js b/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js index 33b30d2e986eba..ac206757e63c5a 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js +++ b/tools/node_modules/eslint/node_modules/graceful-fs/graceful-fs.js @@ -1,6 +1,8 @@ var fs = require('fs') var polyfills = require('./polyfills.js') var legacy = require('./legacy-streams.js') +var clone = require('./clone.js') + var queue = [] var util = require('util') @@ -24,17 +26,17 @@ if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { }) } -module.exports = patch(require('./fs.js')) -if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) { - module.exports = patch(fs) +module.exports = patch(clone(fs)) +if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { + module.exports = patch(fs) + fs.__patched = true; } // Always patch fs.close/closeSync, because we want to // retry() whenever a close happens *anywhere* in the program. // This is essential when multiple graceful-fs instances are // in play at the same time. -module.exports.close = -fs.close = (function (fs$close) { return function (fd, cb) { +module.exports.close = (function (fs$close) { return function (fd, cb) { return fs$close.call(fs, fd, function (err) { if (!err) retry() @@ -44,8 +46,7 @@ fs.close = (function (fs$close) { return function (fd, cb) { }) }})(fs.close) -module.exports.closeSync = -fs.closeSync = (function (fs$closeSync) { return function (fd) { +module.exports.closeSync = (function (fs$closeSync) { return function (fd) { // Note that graceful-fs also retries when fs.closeSync() fails. // Looks like a bug to me, although it's probably a harmless one. var rval = fs$closeSync.apply(fs, arguments) @@ -53,6 +54,17 @@ fs.closeSync = (function (fs$closeSync) { return function (fd) { return rval }})(fs.closeSync) +// Only patch fs once, otherwise we'll run into a memory leak if +// graceful-fs is loaded multiple times, such as in test environments that +// reset the loaded modules between tests. +// We look for the string `graceful-fs` from the comment above. This +// way we are not adding any extra properties and it will detect if older +// versions of graceful-fs are installed. +if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) { + fs.closeSync = module.exports.closeSync; + fs.close = module.exports.close; +} + function patch (fs) { // Everything that references the open() function needs to be in here polyfills(fs) @@ -144,6 +156,7 @@ function patch (fs) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$readdir, [args]]) + else { if (typeof cb === 'function') cb.apply(this, arguments) @@ -163,12 +176,16 @@ function patch (fs) { } var fs$ReadStream = fs.ReadStream - ReadStream.prototype = Object.create(fs$ReadStream.prototype) - ReadStream.prototype.open = ReadStream$open + if (fs$ReadStream) { + ReadStream.prototype = Object.create(fs$ReadStream.prototype) + ReadStream.prototype.open = ReadStream$open + } var fs$WriteStream = fs.WriteStream - WriteStream.prototype = Object.create(fs$WriteStream.prototype) - WriteStream.prototype.open = WriteStream$open + if (fs$WriteStream) { + WriteStream.prototype = Object.create(fs$WriteStream.prototype) + WriteStream.prototype.open = WriteStream$open + } fs.ReadStream = ReadStream fs.WriteStream = WriteStream diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/package.json b/tools/node_modules/eslint/node_modules/graceful-fs/package.json index ea35fce0aa2359..b585bfe22fd54f 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/package.json +++ b/tools/node_modules/eslint/node_modules/graceful-fs/package.json @@ -6,21 +6,20 @@ "deprecated": false, "description": "A drop-in replacement for fs, making various improvements.", "devDependencies": { + "import-fresh": "^2.0.0", "mkdirp": "^0.5.0", "rimraf": "^2.2.8", - "tap": "^5.4.2" + "tap": "^12.0.1" }, "directories": { "test": "test" }, - "engines": { - "node": ">=0.4.0" - }, "files": [ "fs.js", "graceful-fs.js", "legacy-streams.js", - "polyfills.js" + "polyfills.js", + "clone.js" ], "homepage": "https://github.com/isaacs/node-graceful-fs#readme", "keywords": [ @@ -47,7 +46,10 @@ "url": "git+https://github.com/isaacs/node-graceful-fs.git" }, "scripts": { + "postpublish": "git push origin --all; git push origin --tags", + "postversion": "npm publish", + "preversion": "npm test", "test": "node test.js | tap -" }, - "version": "4.1.11" + "version": "4.1.15" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js b/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js index 4c6aca78a3dc8b..b964ed0806ceeb 100644 --- a/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js +++ b/tools/node_modules/eslint/node_modules/graceful-fs/polyfills.js @@ -1,4 +1,3 @@ -var fs = require('./fs.js') var constants = require('constants') var origCwd = process.cwd @@ -145,73 +144,36 @@ function patch (fs) { } } }})(fs.readSync) -} - -function patchLchmod (fs) { - fs.lchmod = function (path, mode, callback) { - fs.open( path - , constants.O_WRONLY | constants.O_SYMLINK - , mode - , function (err, fd) { - if (err) { - if (callback) callback(err) - return - } - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - fs.fchmod(fd, mode, function (err) { - fs.close(fd, function(err2) { - if (callback) callback(err || err2) - }) - }) - }) - } - - fs.lchmodSync = function (path, mode) { - var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) - - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - var threw = true - var ret - try { - ret = fs.fchmodSync(fd, mode) - threw = false - } finally { - if (threw) { - try { - fs.closeSync(fd) - } catch (er) {} - } else { - fs.closeSync(fd) - } - } - return ret - } -} -function patchLutimes (fs) { - if (constants.hasOwnProperty("O_SYMLINK")) { - fs.lutimes = function (path, at, mt, cb) { - fs.open(path, constants.O_SYMLINK, function (er, fd) { - if (er) { - if (cb) cb(er) + function patchLchmod (fs) { + fs.lchmod = function (path, mode, callback) { + fs.open( path + , constants.O_WRONLY | constants.O_SYMLINK + , mode + , function (err, fd) { + if (err) { + if (callback) callback(err) return } - fs.futimes(fd, at, mt, function (er) { - fs.close(fd, function (er2) { - if (cb) cb(er || er2) + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + fs.fchmod(fd, mode, function (err) { + fs.close(fd, function(err2) { + if (callback) callback(err || err2) }) }) }) } - fs.lutimesSync = function (path, at, mt) { - var fd = fs.openSync(path, constants.O_SYMLINK) - var ret + fs.lchmodSync = function (path, mode) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) + + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. var threw = true + var ret try { - ret = fs.futimesSync(fd, at, mt) + ret = fs.fchmodSync(fd, mode) threw = false } finally { if (threw) { @@ -224,107 +186,144 @@ function patchLutimes (fs) { } return ret } + } + + function patchLutimes (fs) { + if (constants.hasOwnProperty("O_SYMLINK")) { + fs.lutimes = function (path, at, mt, cb) { + fs.open(path, constants.O_SYMLINK, function (er, fd) { + if (er) { + if (cb) cb(er) + return + } + fs.futimes(fd, at, mt, function (er) { + fs.close(fd, function (er2) { + if (cb) cb(er || er2) + }) + }) + }) + } + + fs.lutimesSync = function (path, at, mt) { + var fd = fs.openSync(path, constants.O_SYMLINK) + var ret + var threw = true + try { + ret = fs.futimesSync(fd, at, mt) + threw = false + } finally { + if (threw) { + try { + fs.closeSync(fd) + } catch (er) {} + } else { + fs.closeSync(fd) + } + } + return ret + } - } else { - fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } - fs.lutimesSync = function () {} + } else { + fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } + fs.lutimesSync = function () {} + } } -} -function chmodFix (orig) { - if (!orig) return orig - return function (target, mode, cb) { - return orig.call(fs, target, mode, function (er) { - if (chownErOk(er)) er = null - if (cb) cb.apply(this, arguments) - }) + function chmodFix (orig) { + if (!orig) return orig + return function (target, mode, cb) { + return orig.call(fs, target, mode, function (er) { + if (chownErOk(er)) er = null + if (cb) cb.apply(this, arguments) + }) + } } -} -function chmodFixSync (orig) { - if (!orig) return orig - return function (target, mode) { - try { - return orig.call(fs, target, mode) - } catch (er) { - if (!chownErOk(er)) throw er + function chmodFixSync (orig) { + if (!orig) return orig + return function (target, mode) { + try { + return orig.call(fs, target, mode) + } catch (er) { + if (!chownErOk(er)) throw er + } } } -} -function chownFix (orig) { - if (!orig) return orig - return function (target, uid, gid, cb) { - return orig.call(fs, target, uid, gid, function (er) { - if (chownErOk(er)) er = null - if (cb) cb.apply(this, arguments) - }) + function chownFix (orig) { + if (!orig) return orig + return function (target, uid, gid, cb) { + return orig.call(fs, target, uid, gid, function (er) { + if (chownErOk(er)) er = null + if (cb) cb.apply(this, arguments) + }) + } } -} -function chownFixSync (orig) { - if (!orig) return orig - return function (target, uid, gid) { - try { - return orig.call(fs, target, uid, gid) - } catch (er) { - if (!chownErOk(er)) throw er + function chownFixSync (orig) { + if (!orig) return orig + return function (target, uid, gid) { + try { + return orig.call(fs, target, uid, gid) + } catch (er) { + if (!chownErOk(er)) throw er + } } } -} -function statFix (orig) { - if (!orig) return orig - // Older versions of Node erroneously returned signed integers for - // uid + gid. - return function (target, cb) { - return orig.call(fs, target, function (er, stats) { - if (!stats) return cb.apply(this, arguments) + function statFix (orig) { + if (!orig) return orig + // Older versions of Node erroneously returned signed integers for + // uid + gid. + return function (target, cb) { + return orig.call(fs, target, function (er, stats) { + if (!stats) return cb.apply(this, arguments) + if (stats.uid < 0) stats.uid += 0x100000000 + if (stats.gid < 0) stats.gid += 0x100000000 + if (cb) cb.apply(this, arguments) + }) + } + } + + function statFixSync (orig) { + if (!orig) return orig + // Older versions of Node erroneously returned signed integers for + // uid + gid. + return function (target) { + var stats = orig.call(fs, target) if (stats.uid < 0) stats.uid += 0x100000000 if (stats.gid < 0) stats.gid += 0x100000000 - if (cb) cb.apply(this, arguments) - }) + return stats; + } } -} -function statFixSync (orig) { - if (!orig) return orig - // Older versions of Node erroneously returned signed integers for - // uid + gid. - return function (target) { - var stats = orig.call(fs, target) - if (stats.uid < 0) stats.uid += 0x100000000 - if (stats.gid < 0) stats.gid += 0x100000000 - return stats; - } -} + // ENOSYS means that the fs doesn't support the op. Just ignore + // that, because it doesn't matter. + // + // if there's no getuid, or if getuid() is something other + // than 0, and the error is EINVAL or EPERM, then just ignore + // it. + // + // This specific case is a silent failure in cp, install, tar, + // and most other unix tools that manage permissions. + // + // When running as root, or if other types of errors are + // encountered, then it's strict. + function chownErOk (er) { + if (!er) + return true -// ENOSYS means that the fs doesn't support the op. Just ignore -// that, because it doesn't matter. -// -// if there's no getuid, or if getuid() is something other -// than 0, and the error is EINVAL or EPERM, then just ignore -// it. -// -// This specific case is a silent failure in cp, install, tar, -// and most other unix tools that manage permissions. -// -// When running as root, or if other types of errors are -// encountered, then it's strict. -function chownErOk (er) { - if (!er) - return true - - if (er.code === "ENOSYS") - return true - - var nonroot = !process.getuid || process.getuid() !== 0 - if (nonroot) { - if (er.code === "EINVAL" || er.code === "EPERM") + if (er.code === "ENOSYS") return true - } - return false + var nonroot = !process.getuid || process.getuid() !== 0 + if (nonroot) { + if (er.code === "EINVAL" || er.code === "EPERM") + return true + } + + return false + } } diff --git a/tools/node_modules/eslint/node_modules/has/LICENSE-MIT b/tools/node_modules/eslint/node_modules/has/LICENSE-MIT deleted file mode 100644 index ae7014d385df3d..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Thiago de Arruda - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/node_modules/eslint/node_modules/has/README.md b/tools/node_modules/eslint/node_modules/has/README.md deleted file mode 100644 index 635e3a4baab00b..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# has - -> Object.prototype.hasOwnProperty.call shortcut - -## Installation - -```sh -npm install --save has -``` - -## Usage - -```js -var has = require('has'); - -has({}, 'hasOwnProperty'); // false -has(Object.prototype, 'hasOwnProperty'); // true -``` diff --git a/tools/node_modules/eslint/node_modules/has/package.json b/tools/node_modules/eslint/node_modules/has/package.json deleted file mode 100644 index 4b061b0e838104..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "author": { - "name": "Thiago de Arruda", - "email": "tpadilha84@gmail.com" - }, - "bugs": { - "url": "https://github.com/tarruda/has/issues" - }, - "bundleDependencies": false, - "contributors": [ - { - "name": "Jordan Harband", - "email": "ljharb@gmail.com", - "url": "http://ljharb.codes" - } - ], - "dependencies": { - "function-bind": "^1.1.1" - }, - "deprecated": false, - "description": "Object.prototype.hasOwnProperty.call shortcut", - "devDependencies": { - "@ljharb/eslint-config": "^12.2.1", - "eslint": "^4.19.1", - "tape": "^4.9.0" - }, - "engines": { - "node": ">= 0.4.0" - }, - "homepage": "https://github.com/tarruda/has", - "license": "MIT", - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/tarruda/has/blob/master/LICENSE-MIT" - } - ], - "main": "./src", - "name": "has", - "repository": { - "type": "git", - "url": "git://github.com/tarruda/has.git" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "tape test" - }, - "version": "1.0.3" -} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/has/src/index.js b/tools/node_modules/eslint/node_modules/has/src/index.js deleted file mode 100644 index dd92dd9094edb0..00000000000000 --- a/tools/node_modules/eslint/node_modules/has/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var bind = require('function-bind'); - -module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); diff --git a/tools/node_modules/eslint/node_modules/p-map/index.js b/tools/node_modules/eslint/node_modules/p-map/index.js new file mode 100644 index 00000000000000..f91477e1f5b3f3 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/index.js @@ -0,0 +1,67 @@ +'use strict'; +module.exports = (iterable, mapper, opts) => new Promise((resolve, reject) => { + opts = Object.assign({ + concurrency: Infinity + }, opts); + + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } + + const concurrency = opts.concurrency; + + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } + + const ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let iterableDone = false; + let resolvingCount = 0; + let currentIdx = 0; + + const next = () => { + if (isRejected) { + return; + } + + const nextItem = iterator.next(); + const i = currentIdx; + currentIdx++; + + if (nextItem.done) { + iterableDone = true; + + if (resolvingCount === 0) { + resolve(ret); + } + + return; + } + + resolvingCount++; + + Promise.resolve(nextItem.value) + .then(el => mapper(el, i)) + .then( + val => { + ret[i] = val; + resolvingCount--; + next(); + }, + err => { + isRejected = true; + reject(err); + } + ); + }; + + for (let i = 0; i < concurrency; i++) { + next(); + + if (iterableDone) { + break; + } + } +}); diff --git a/tools/node_modules/eslint/node_modules/p-map/license b/tools/node_modules/eslint/node_modules/p-map/license new file mode 100644 index 00000000000000..e7af2f77107d73 --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/node_modules/eslint/node_modules/p-map/package.json b/tools/node_modules/eslint/node_modules/p-map/package.json new file mode 100644 index 00000000000000..455e05c8bf2ebf --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/package.json @@ -0,0 +1,56 @@ +{ + "author": { + "name": "Sindre Sorhus", + "email": "sindresorhus@gmail.com", + "url": "sindresorhus.com" + }, + "bugs": { + "url": "https://github.com/sindresorhus/p-map/issues" + }, + "bundleDependencies": false, + "deprecated": false, + "description": "Map over promises concurrently", + "devDependencies": { + "ava": "*", + "delay": "^2.0.0", + "in-range": "^1.0.0", + "random-int": "^1.0.0", + "time-span": "^2.0.0", + "xo": "*" + }, + "engines": { + "node": ">=4" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/sindresorhus/p-map#readme", + "keywords": [ + "promise", + "map", + "resolved", + "wait", + "collection", + "iterable", + "iterator", + "race", + "fulfilled", + "async", + "await", + "promises", + "concurrently", + "concurrency", + "parallel", + "bluebird" + ], + "license": "MIT", + "name": "p-map", + "repository": { + "type": "git", + "url": "git+https://github.com/sindresorhus/p-map.git" + }, + "scripts": { + "test": "xo && ava" + }, + "version": "1.2.0" +} \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/p-map/readme.md b/tools/node_modules/eslint/node_modules/p-map/readme.md new file mode 100644 index 00000000000000..7727581a0e578c --- /dev/null +++ b/tools/node_modules/eslint/node_modules/p-map/readme.md @@ -0,0 +1,81 @@ +# p-map [![Build Status](https://travis-ci.org/sindresorhus/p-map.svg?branch=master)](https://travis-ci.org/sindresorhus/p-map) + +> Map over promises concurrently + +Useful when you need to run promise-returning & async functions multiple times with different inputs concurrently. + + +## Install + +``` +$ npm install p-map +``` + + +## Usage + +```js +const pMap = require('p-map'); +const got = require('got'); + +const sites = [ + getWebsiteFromUsername('sindresorhus'), //=> Promise + 'ava.li', + 'todomvc.com', + 'github.com' +]; + +const mapper = el => got.head(el).then(res => res.requestUrl); + +pMap(sites, mapper, {concurrency: 2}).then(result => { + console.log(result); + //=> ['http://sindresorhus.com/', 'http://ava.li/', 'http://todomvc.com/', 'http://github.com/'] +}); +``` + + +## API + +### pMap(input, mapper, [options]) + +Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled, or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned from `mapper` in `input` order. + +#### input + +Type: `Iterable` + +Iterated over concurrently in the `mapper` function. + +#### mapper(element, index) + +Type: `Function` + +Expected to return a `Promise` or value. + +#### options + +Type: `Object` + +##### concurrency + +Type: `number`
+Default: `Infinity`
+Minimum: `1` + +Number of concurrently pending promises returned by `mapper`. + + +## Related + +- [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency +- [p-filter](https://github.com/sindresorhus/p-filter) - Filter promises concurrently +- [p-times](https://github.com/sindresorhus/p-times) - Run promise-returning & async functions a specific number of times concurrently +- [p-props](https://github.com/sindresorhus/p-props) - Like `Promise.all()` but for `Map` and `Object` +- [p-map-series](https://github.com/sindresorhus/p-map-series) - Map over promises serially +- [p-queue](https://github.com/sindresorhus/p-queue) - Promise queue with concurrency control +- [More…](https://github.com/sindresorhus/promise-fun) + + +## License + +MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/tools/node_modules/eslint/node_modules/pify/index.js b/tools/node_modules/eslint/node_modules/pify/index.js index 7c720ebee88727..1dee43ad08f62b 100644 --- a/tools/node_modules/eslint/node_modules/pify/index.js +++ b/tools/node_modules/eslint/node_modules/pify/index.js @@ -1,68 +1,84 @@ 'use strict'; -var processFn = function (fn, P, opts) { - return function () { - var that = this; - var args = new Array(arguments.length); +const processFn = (fn, opts) => function () { + const P = opts.promiseModule; + const args = new Array(arguments.length); - for (var i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; - } + for (let i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } - return new P(function (resolve, reject) { + return new P((resolve, reject) => { + if (opts.errorFirst) { args.push(function (err, result) { - if (err) { - reject(err); - } else if (opts.multiArgs) { - var results = new Array(arguments.length - 1); + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); - for (var i = 1; i < arguments.length; i++) { + for (let i = 1; i < arguments.length; i++) { results[i - 1] = arguments[i]; } - resolve(results); + if (err) { + results.unshift(err); + reject(results); + } else { + resolve(results); + } + } else if (err) { + reject(err); } else { resolve(result); } }); + } else { + args.push(function (result) { + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); - fn.apply(that, args); - }); - }; -}; + for (let i = 0; i < arguments.length; i++) { + results[i] = arguments[i]; + } -var pify = module.exports = function (obj, P, opts) { - if (typeof P !== 'function') { - opts = P; - P = Promise; - } + resolve(results); + } else { + resolve(result); + } + }); + } - opts = opts || {}; - opts.exclude = opts.exclude || [/.+Sync$/]; + fn.apply(this, args); + }); +}; - var filter = function (key) { - var match = function (pattern) { - return typeof pattern === 'string' ? key === pattern : pattern.test(key); - }; +module.exports = (obj, opts) => { + opts = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, opts); + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); return opts.include ? opts.include.some(match) : !opts.exclude.some(match); }; - var ret = typeof obj === 'function' ? function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } - - return processFn(obj, P, opts).apply(this, arguments); - } : {}; + let ret; + if (typeof obj === 'function') { + ret = function () { + if (opts.excludeMain) { + return obj.apply(this, arguments); + } - return Object.keys(obj).reduce(function (ret, key) { - var x = obj[key]; + return processFn(obj, opts).apply(this, arguments); + }; + } else { + ret = Object.create(Object.getPrototypeOf(obj)); + } - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, P, opts) : x; + for (const key in obj) { // eslint-disable-line guard-for-in + const x = obj[key]; + ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; + } - return ret; - }, ret); + return ret; }; - -pify.all = pify; diff --git a/tools/node_modules/eslint/node_modules/pify/license b/tools/node_modules/eslint/node_modules/pify/license index 654d0bfe943437..e7af2f77107d73 100644 --- a/tools/node_modules/eslint/node_modules/pify/license +++ b/tools/node_modules/eslint/node_modules/pify/license @@ -1,21 +1,9 @@ -The MIT License (MIT) +MIT License Copyright (c) Sindre Sorhus (sindresorhus.com) -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/node_modules/eslint/node_modules/pify/package.json b/tools/node_modules/eslint/node_modules/pify/package.json index 40780115cf1d0a..37d6bd41a0aeb6 100644 --- a/tools/node_modules/eslint/node_modules/pify/package.json +++ b/tools/node_modules/eslint/node_modules/pify/package.json @@ -12,12 +12,12 @@ "description": "Promisify a callback-style function", "devDependencies": { "ava": "*", - "pinkie-promise": "^1.0.0", - "v8-natives": "0.0.2", + "pinkie-promise": "^2.0.0", + "v8-natives": "^1.0.0", "xo": "*" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" }, "files": [ "index.js" @@ -27,6 +27,7 @@ "promise", "promises", "promisify", + "all", "denodify", "denodeify", "callback", @@ -41,7 +42,9 @@ "bind", "to", "async", - "es2015" + "await", + "es2015", + "bluebird" ], "license": "MIT", "name": "pify", @@ -53,5 +56,5 @@ "optimization-test": "node --allow-natives-syntax optimization-test.js", "test": "xo && ava && npm run optimization-test" }, - "version": "2.3.0" + "version": "3.0.0" } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/pify/readme.md b/tools/node_modules/eslint/node_modules/pify/readme.md index c79ca8bf643927..376ca4e59d74c4 100644 --- a/tools/node_modules/eslint/node_modules/pify/readme.md +++ b/tools/node_modules/eslint/node_modules/pify/readme.md @@ -16,15 +16,13 @@ $ npm install --save pify const fs = require('fs'); const pify = require('pify'); -// promisify a single function - +// Promisify a single function pify(fs.readFile)('package.json', 'utf8').then(data => { console.log(JSON.parse(data).name); //=> 'pify' }); -// or promisify all methods in a module - +// Promisify all methods in a module pify(fs).readFile('package.json', 'utf8').then(data => { console.log(JSON.parse(data).name); //=> 'pify' @@ -34,32 +32,24 @@ pify(fs).readFile('package.json', 'utf8').then(data => { ## API -### pify(input, [promiseModule], [options]) +### pify(input, [options]) -Returns a promise wrapped version of the supplied function or module. +Returns a `Promise` wrapped version of the supplied function or module. #### input -Type: `function`, `object` +Type: `Function` `Object` Callback-style function or module whose methods you want to promisify. -#### promiseModule - -Type: `function` - -Custom promise module to use instead of the native one. - -Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill. - #### options ##### multiArgs -Type: `boolean` +Type: `boolean`
Default: `false` -By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. +By default, the promisified function will only return the second argument from the callback, which works fine for most APIs. This option can be useful for modules like `request` that return multiple arguments. Turning this on will make it return an array of all arguments from the callback, excluding the error argument, instead of just the second argument. This also applies to rejections, where it returns an array of all the callback arguments, including the error. ```js const request = require('request'); @@ -72,23 +62,23 @@ pify(request, {multiArgs: true})('https://sindresorhus.com').then(result => { ##### include -Type: `array` of (`string`|`regex`) +Type: `string[]` `RegExp[]` Methods in a module to promisify. Remaining methods will be left untouched. ##### exclude -Type: `array` of (`string`|`regex`) -Default: `[/.+Sync$/]` +Type: `string[]` `RegExp[]`
+Default: `[/.+(Sync|Stream)$/]` Methods in a module **not** to promisify. Methods with names ending with `'Sync'` are excluded by default. ##### excludeMain -Type: `boolean` +Type: `boolean`
Default: `false` -By default, if given module is a function itself, this function will be promisified. Turn this option on if you want to promisify only methods of the module. +If given module is a function itself, it will be promisified. Turn this option on if you want to promisify only methods of the module. ```js const pify = require('pify'); @@ -99,11 +89,11 @@ function fn() { fn.method = (data, callback) => { setImmediate(() => { - callback(data, null); + callback(null, data); }); }; -// promisify methods but not fn() +// Promisify methods but not `fn()` const promiseFn = pify(fn, {excludeMain: true}); if (promiseFn()) { @@ -113,7 +103,29 @@ if (promiseFn()) { } ``` +##### errorFirst + +Type: `boolean`
+Default: `true` + +Whether the callback has an error as the first argument. You'll want to set this to `false` if you're dealing with an API that doesn't have an error as the first argument, like `fs.exists()`, some browser APIs, Chrome Extension APIs, etc. + +##### promiseModule + +Type: `Function` + +Custom promise module to use instead of the native one. + +Check out [`pinkie-promise`](https://github.com/floatdrop/pinkie-promise) if you need a tiny promise polyfill. + + +## Related + +- [p-event](https://github.com/sindresorhus/p-event) - Promisify an event by waiting for it to be emitted +- [p-map](https://github.com/sindresorhus/p-map) - Map over promises concurrently +- [More…](https://github.com/sindresorhus/promise-fun) + ## License -MIT © [Sindre Sorhus](http://sindresorhus.com) +MIT © [Sindre Sorhus](https://sindresorhus.com) diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js index 75116385eed36c..fd45b729d069e1 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/decode.js @@ -1,13 +1,6 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:decode - * @fileoverview Decode entities. - */ - 'use strict'; +var xtend = require('xtend'); var entities = require('parse-entities'); module.exports = factory; @@ -62,10 +55,10 @@ function factory(ctx) { } /* Decode `value` (at `position`) into a string. */ - function decodeRaw(value, position) { - return entities(value, { + function decodeRaw(value, position, options) { + return entities(value, xtend(options, { position: normalize(position), warning: handleWarning - }); + })); } } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js index ccb3fabd485901..37846f3930a35a 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/defaults.js @@ -1,21 +1,10 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:defaults - * @fileoverview Default options for `parse`. - */ - 'use strict'; -/* Expose. */ module.exports = { position: true, gfm: true, - yaml: true, commonmark: false, footnotes: false, pedantic: false, - blocks: require('./block-elements'), - breaks: false + blocks: require('./block-elements.json') }; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js index b5550e10076605..295bdc9855126e 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/break.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:break - * @fileoverview Locate a break. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js index 010e74dcec4b00..981c81698254fe 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/code-inline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:code-inline - * @fileoverview Locate inline code. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js index 1a892e1be7716e..d208aef2fff386 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/delete.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:delete - * @fileoverview Locate strikethrough. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js index 270daad0f9e00c..6a1f24227d05bb 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/emphasis.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:emphasis - * @fileoverview Locate italics / emphasis. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js index 45f9b449a7873c..f6c63715827ef3 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/escape.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:escape - * @fileoverview Locate an escape. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js index dab2a3c54f1774..0f16fd8016bd36 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/link.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:link - * @fileoverview Locate a link. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js index 717259f36eae22..da1cac0a499f2e 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/strong.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:strong - * @fileoverview Locate bold / strong / importance. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js index 56e2d49e564587..3c5534268abe1d 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/tag.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:tag - * @fileoverview Locate a tag. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js index 53b239241c104a..59b63e2563693e 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/locate/url.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:locate:url - * @fileoverview Locate a URL. - */ - 'use strict'; module.exports = locate; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js index 53a50b181e67d4..5a8d8119556792 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/parse.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:parse - * @fileoverview Parse the document - */ - 'use strict'; var xtend = require('xtend'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js index 8fe982b661c41c..9291109f16f3ec 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/parser.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse - * @fileoverview Markdown parser. - */ - 'use strict'; var xtend = require('xtend'); @@ -17,7 +9,6 @@ var tokenizer = require('./tokenizer'); module.exports = Parser; -/* Construct a new parser. */ function Parser(doc, file) { this.file = file; this.offset = {}; @@ -34,7 +25,6 @@ function Parser(doc, file) { this.decode = decode(this); } -/* Prototype. */ var proto = Parser.prototype; /* Expose core. */ @@ -80,6 +70,7 @@ proto.interruptParagraph = [ * In the above example, the thematic break “interupts” * the list. */ proto.interruptList = [ + ['atxHeading', {pedantic: false}], ['fencedCode', {pedantic: false}], ['thematicBreak', {pedantic: false}], ['definition', {commonmark: false}], @@ -109,7 +100,6 @@ proto.interruptBlockquote = [ /* Handlers. */ proto.blockTokenizers = { - yamlFrontMatter: require('./tokenize/yaml'), newline: require('./tokenize/newline'), indentedCode: require('./tokenize/code-indented'), fencedCode: require('./tokenize/code-fenced'), diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js index 3f9abad7c49a06..c55f7f32f31def 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/set-options.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse - * @fileoverview Markdown parser. - */ - 'use strict'; var xtend = require('xtend'); @@ -14,7 +6,6 @@ var defaults = require('./defaults'); module.exports = setOptions; -/* Set options. */ function setOptions(options) { var self = this; var current = self.options; @@ -43,10 +34,7 @@ function setOptions(options) { (key !== 'blocks' && typeof value !== 'boolean') || (key === 'blocks' && typeof value !== 'object') ) { - throw new Error( - 'Invalid value `' + value + '` ' + - 'for setting `options.' + key + '`' - ); + throw new Error('Invalid value `' + value + '` for setting `options.' + key + '`'); } options[key] = value; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js index 3861b48a14aead..c945a2c1f88f58 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/auto-link.js @@ -1,13 +1,6 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:auto-link - * @fileoverview Tokenise an auto-link. - */ - 'use strict'; +var whitespace = require('is-whitespace-character'); var decode = require('parse-entities'); var locate = require('../locate/tag'); @@ -34,7 +27,7 @@ function autoLink(eat, value, silent) { var link; var now; var content; - var tokenize; + var tokenizers; var exit; if (value.charAt(0) !== C_LT) { @@ -56,7 +49,7 @@ function autoLink(eat, value, silent) { character = value.charAt(index); if ( - character === ' ' || + whitespace(character) || character === C_GT || character === C_AT_SIGN || (character === ':' && value.charAt(index + 1) === C_SLASH) @@ -96,7 +89,7 @@ function autoLink(eat, value, silent) { while (index < length) { character = value.charAt(index); - if (character === ' ' || character === C_GT) { + if (whitespace(character) || character === C_GT) { break; } @@ -132,20 +125,21 @@ function autoLink(eat, value, silent) { } } - /* Temporarily remove support for escapes in autolinks. */ - tokenize = self.inlineTokenizers.escape; - self.inlineTokenizers.escape = null; + /* Temporarily remove all tokenizers except text in autolinks. */ + tokenizers = self.inlineTokenizers; + self.inlineTokenizers = {text: tokenizers.text}; + exit = self.enterLink(); content = self.tokenizeInline(content, now); - self.inlineTokenizers.escape = tokenize; + self.inlineTokenizers = tokenizers; exit(); return eat(subvalue)({ type: 'link', title: null, - url: decode(link), + url: decode(link, {nonTerminated: false}), children: content }); } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js index 764e0aa010392c..bd700d6a6c8276 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/blockquote.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:blockquote - * @fileoverview Tokenise blockquote. - */ - 'use strict'; var trim = require('trim'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js index 6d2d0dcff9552b..eb531342bfebcb 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/break.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:break - * @fileoverview Tokenise a break. - */ - 'use strict'; var locate = require('../locate/break'); @@ -15,10 +7,7 @@ hardBreak.locator = locate; var MIN_BREAK_LENGTH = 2; -/* Tokenise a break. */ function hardBreak(eat, value, silent) { - var self = this; - var breaks = self.options.breaks; var length = value.length; var index = -1; var queue = ''; @@ -28,7 +17,7 @@ function hardBreak(eat, value, silent) { character = value.charAt(index); if (character === '\n') { - if (!breaks && index < MIN_BREAK_LENGTH) { + if (index < MIN_BREAK_LENGTH) { return; } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js index f2577405b26587..65f2bc73273ab3 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-fenced.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:code-fenced - * @fileoverview Tokenise fenced code. - */ - 'use strict'; var trim = require('trim-trailing-lines'); @@ -21,7 +13,6 @@ var C_TICK = '`'; var MIN_FENCE_COUNT = 3; var CODE_INDENT_COUNT = 4; -/* Tokenise fenced code. */ function fencedCode(eat, value, silent) { var self = this; var settings = self.options; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js index 50c581fe26e2e4..c73849d9ad8bf2 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-indented.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:code-indented - * @fileoverview Tokenise indented code. - */ - 'use strict'; var repeat = require('repeat-string'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js index 9157412753ad1a..c0a496b49255ba 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/code-inline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:code-inline - * @fileoverview Tokenise inline code. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js index 3f7345a2c901c8..1cce274cfbdd71 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/definition.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:definition - * @fileoverview Tokenise a definition. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -29,7 +21,6 @@ var C_COLON = ':'; var C_LT = '<'; var C_GT = '>'; -/* Tokenise a definition. */ function definition(eat, value, silent) { var self = this; var commonmark = self.options.commonmark; @@ -254,7 +245,7 @@ function definition(eat, value, silent) { } beforeURL = eat(beforeURL).test().end; - url = self.decode.raw(self.unescape(url), beforeURL); + url = self.decode.raw(self.unescape(url), beforeURL, {nonTerminated: false}); if (title) { beforeTitle = eat(beforeTitle).test().end; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js index 60ae9c4936c61f..ca7c68a8c5c1be 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/delete.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:delete - * @fileoverview Tokenise strikethrough. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -17,7 +9,6 @@ strikethrough.locator = locate; var C_TILDE = '~'; var DOUBLE = '~~'; -/* Tokenise strikethrough. */ function strikethrough(eat, value, silent) { var self = this; var character = ''; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js index 46249369224bc5..b2c87b4497de38 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/emphasis.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:emphasis - * @fileoverview Tokenise emphasis. - */ - 'use strict'; var trim = require('trim'); @@ -19,7 +11,6 @@ emphasis.locator = locate; var C_ASTERISK = '*'; var C_UNDERSCORE = '_'; -/* Tokenise emphasis. */ function emphasis(eat, value, silent) { var self = this; var index = 0; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js index 3e41a4cec5e6ea..d6f99bcc10381d 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/escape.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:escape - * @fileoverview Tokenise an escape. - */ - 'use strict'; var locate = require('../locate/escape'); @@ -13,7 +5,6 @@ var locate = require('../locate/escape'); module.exports = escape; escape.locator = locate; -/* Tokenise an escape. */ function escape(eat, value, silent) { var self = this; var character; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js index 3537ccb6115017..f48ff9bb7eb187 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/footnote-definition.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:footnote-definition - * @fileoverview Tokenise footnote definition. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -26,7 +18,6 @@ var C_COLON = ':'; var EXPRESSION_INITIAL_TAB = /^( {4}|\t)?/gm; -/* Tokenise a footnote definition. */ function footnoteDefinition(eat, value, silent) { var self = this; var offsets = self.offset; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js index e5fdedc537ad0b..aafeabb54910f6 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-atx.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:heading-atx - * @fileoverview Tokenise an ATX-style heading. - */ - 'use strict'; module.exports = atxHeading; @@ -17,7 +9,6 @@ var C_HASH = '#'; var MAX_ATX_COUNT = 6; -/* Tokenise an ATX-style heading. */ function atxHeading(eat, value, silent) { var self = this; var settings = self.options; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js index db8bbcfb73c2c9..96c6130da744e1 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/heading-setext.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:heading-setext - * @fileoverview Tokenise an setext-style heading. - */ - 'use strict'; module.exports = setextHeading; @@ -25,7 +17,6 @@ var SETEXT_MARKERS = {}; SETEXT_MARKERS[C_EQUALS] = 1; SETEXT_MARKERS[C_DASH] = 2; -/* Tokenise an setext-style heading. */ function setextHeading(eat, value, silent) { var self = this; var now = eat.now(); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js index dc861b53c3a37b..6e81eb290a3993 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-block.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:html-block - * @fileoverview Tokenise block HTML. - */ - 'use strict'; var openCloseTag = require('../util/html').openCloseTag; @@ -17,7 +9,6 @@ var C_SPACE = ' '; var C_NEWLINE = '\n'; var C_LT = '<'; -/* Tokenise block HTML. */ function blockHTML(eat, value, silent) { var self = this; var blocks = self.options.blocks; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js index d8c0b9ab21829a..c204e962b15ae8 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/html-inline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:html-inline - * @fileoverview Tokenise inline HTML. - */ - 'use strict'; var alphabetical = require('is-alphabetical'); @@ -18,7 +10,6 @@ inlineHTML.locator = locate; var EXPRESSION_HTML_LINK_OPEN = /^/i; -/* Tokenise inline HTML. */ function inlineHTML(eat, value, silent) { var self = this; var length = value.length; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js index fb11c5099054df..3ef5e1ba312d75 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/link.js @@ -1,20 +1,13 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:link - * @fileoverview Tokenise a link. - */ - 'use strict'; -var has = require('has'); var whitespace = require('is-whitespace-character'); var locate = require('../locate/link'); module.exports = link; link.locator = locate; +var own = {}.hasOwnProperty; + var C_BACKSLASH = '\\'; var C_BRACKET_OPEN = '['; var C_BRACKET_CLOSE = ']'; @@ -41,12 +34,12 @@ COMMONMARK_LINK_MARKERS[C_DOUBLE_QUOTE] = C_DOUBLE_QUOTE; COMMONMARK_LINK_MARKERS[C_SINGLE_QUOTE] = C_SINGLE_QUOTE; COMMONMARK_LINK_MARKERS[C_PAREN_OPEN] = C_PAREN_CLOSE; -/* Tokenise a link. */ function link(eat, value, silent) { var self = this; var subvalue = ''; var index = 0; var character = value.charAt(0); + var pedantic = self.options.pedantic; var commonmark = self.options.commonmark; var gfm = self.options.gfm; var closed; @@ -134,7 +127,7 @@ function link(eat, value, silent) { } else { /* Allow white-space between content and * url in GFM mode. */ - if (gfm) { + if (!pedantic) { while (index < length) { character = value.charAt(index + 1); @@ -224,12 +217,12 @@ function link(eat, value, silent) { while (index < length) { character = value.charAt(index); - if (subqueue && has(markers, character)) { + if (subqueue && own.call(markers, character)) { break; } if (whitespace(character)) { - if (commonmark) { + if (!pedantic) { break; } @@ -282,7 +275,7 @@ function link(eat, value, silent) { subvalue += queue; /* Eat the title. */ - if (queue && has(markers, character)) { + if (queue && own.call(markers, character)) { index++; subvalue += character; queue = ''; @@ -374,7 +367,7 @@ function link(eat, value, silent) { subvalue += C_PAREN_CLOSE; - url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end); + url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end, {nonTerminated: false}); if (title) { beforeTitle = eat(beforeTitle).test().end; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js index da8002e574196c..9164c8167f8dc1 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/list.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:list - * @fileoverview Tokenise a list. - */ - 'use strict'; /* eslint-disable max-params */ @@ -58,7 +50,6 @@ var LIST_ORDERED_COMMONMARK_MARKERS = {}; LIST_ORDERED_COMMONMARK_MARKERS[C_DOT] = true; LIST_ORDERED_COMMONMARK_MARKERS[C_PAREN_CLOSE] = true; -/* Tokenise a list. */ function list(eat, value, silent) { var self = this; var commonmark = self.options.commonmark; @@ -371,17 +362,6 @@ function list(eat, value, silent) { return node; } -/** - * Create a list-item node. - * - * @example - * listItem('- _foo_', now()); - * - * @param {Object} ctx - Parser. - * @param {Object} value - List-item. - * @param {Object} position - List-item location. - * @return {Object} - `listItem` node. - */ function listItem(ctx, value, position) { var offsets = ctx.offset; var fn = ctx.options.pedantic ? pedanticListItem : normalListItem; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js index f710e0ef976603..6008670cc5e742 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/newline.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:newline - * @fileoverview Tokenise a newline. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js index 7d064522ffecbd..1492a027e78237 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/paragraph.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:paragraph - * @fileoverview Tokenise a paragraph. - */ - 'use strict'; var trim = require('trim'); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js index 1fa150d9e6b958..50713f1ccfc8fa 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/reference.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:reference - * @fileoverview Tokenise a reference. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); @@ -26,7 +18,6 @@ var C_BACKSLASH = '\\'; var C_BRACKET_OPEN = '['; var C_BRACKET_CLOSE = ']'; -/* Tokenise a reference. */ function reference(eat, value, silent) { var self = this; var character = value.charAt(0); @@ -61,11 +52,13 @@ function reference(eat, value, silent) { queue = ''; /* Check whether we’re eating a footnote. */ - if ( - self.options.footnotes && - type === T_LINK && - value.charAt(index) === C_CARET - ) { + if (self.options.footnotes && value.charAt(index) === C_CARET) { + /* Exit if `![^` is found, so the `!` will be seen as text after this, + * and we’ll enter this function again when `[^` is found. */ + if (type === T_IMAGE) { + return; + } + intro += C_CARET; index++; type = T_FOOTNOTE; @@ -122,7 +115,8 @@ function reference(eat, value, silent) { character = value.charAt(index); - if (character === C_BRACKET_OPEN) { + /* Inline footnotes cannot have an identifier. */ + if (type !== T_FOOTNOTE && character === C_BRACKET_OPEN) { identifier = ''; queue += character; index++; @@ -168,13 +162,6 @@ function reference(eat, value, silent) { return; } - /* Inline footnotes cannot have an identifier. */ - if (type === T_FOOTNOTE && referenceType !== REFERENCE_TYPE_SHORTCUT) { - type = T_LINK; - intro = C_BRACKET_OPEN + C_CARET; - content = C_CARET + content; - } - subvalue = intro + subvalue; if (type === T_LINK && self.inLink) { diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js index 765993fa0bd4b3..12d5785bc64a74 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/strong.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:strong - * @fileoverview Tokenise strong. - */ - 'use strict'; var trim = require('trim'); @@ -18,7 +10,6 @@ strong.locator = locate; var C_ASTERISK = '*'; var C_UNDERSCORE = '_'; -/* Tokenise strong. */ function strong(eat, value, silent) { var self = this; var index = 0; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js index c440067e1011d7..ce93b1d22f0f31 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/table.js @@ -1,17 +1,8 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:table - * @fileoverview Tokenise a table. - */ - 'use strict'; var whitespace = require('is-whitespace-character'); module.exports = table; -table.notInList = true; var C_BACKSLASH = '\\'; var C_TICK = '`'; @@ -30,7 +21,6 @@ var TABLE_ALIGN_CENTER = 'center'; var TABLE_ALIGN_RIGHT = 'right'; var TABLE_ALIGN_NONE = null; -/* Tokenise a table. */ function table(eat, value, silent) { var self = this; var index; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js index ef6d3f2879d46e..4aedfa90d5d9b8 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/text.js @@ -1,16 +1,7 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:text - * @fileoverview Tokenise text. - */ - 'use strict'; module.exports = text; -/* Tokenise text. */ function text(eat, value, silent) { var self = this; var methods; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js index a580d09fe09c0b..2391e3f592cb25 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/thematic-break.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:thematic-break - * @fileoverview Tokenise a thematic break. - */ - 'use strict'; module.exports = thematicBreak; @@ -19,7 +11,6 @@ var C_DASH = '-'; var THEMATIC_BREAK_MARKER_COUNT = 3; -/* Tokenise a thematic break. */ function thematicBreak(eat, value, silent) { var index = -1; var length = value.length + 1; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js index fd2debd32f35fe..297940bf4ab922 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/url.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:url - * @fileoverview Tokenise a URL. - */ - 'use strict'; var decode = require('parse-entities'); @@ -35,7 +27,6 @@ var PROTOCOLS = [ var PROTOCOLS_LENGTH = PROTOCOLS.length; -/* Tokenise a URL. */ function url(eat, value, silent) { var self = this; var subvalue; @@ -147,7 +138,7 @@ function url(eat, value, silent) { return eat(subvalue)({ type: 'link', title: null, - url: decode(subvalue), + url: decode(subvalue, {nonTerminated: false}), children: content }); } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js deleted file mode 100644 index 78dec31a0f9eb8..00000000000000 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenize/yaml.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenize:yaml - * @fileoverview Tokenise YAML. - */ - -'use strict'; - -module.exports = yaml; -yaml.onlyAtStart = true; - -var FENCE = '---'; -var C_DASH = '-'; -var C_NEWLINE = '\n'; - -/* Tokenise YAML. */ -function yaml(eat, value, silent) { - var self = this; - var subvalue; - var content; - var index; - var length; - var character; - var queue; - - if ( - !self.options.yaml || - value.charAt(0) !== C_DASH || - value.charAt(1) !== C_DASH || - value.charAt(2) !== C_DASH || - value.charAt(3) !== C_NEWLINE - ) { - return; - } - - subvalue = FENCE + C_NEWLINE; - content = ''; - queue = ''; - index = 3; - length = value.length; - - while (++index < length) { - character = value.charAt(index); - - if ( - character === C_DASH && - (queue || !content) && - value.charAt(index + 1) === C_DASH && - value.charAt(index + 2) === C_DASH - ) { - /* istanbul ignore if - never used (yet) */ - if (silent) { - return true; - } - - subvalue += queue + FENCE; - - return eat(subvalue)({ - type: 'yaml', - value: content - }); - } - - if (character === C_NEWLINE) { - queue += character; - } else { - subvalue += queue + character; - content += queue + character; - queue = ''; - } - } -} diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js index aefe551fc37993..498ef22ad949af 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/tokenizer.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:tokenizer - * @fileoverview Markdown tokenizer. - */ - 'use strict'; module.exports = factory; @@ -101,7 +93,7 @@ function factory(type) { if ( method && - (!method.onlyAtStart || self.atStart) && + /* istanbul ignore next */ (!method.onlyAtStart || self.atStart) && (!method.notInList || !self.inList) && (!method.notInBlock || !self.inBlock) && (!method.notInLink || !self.inLink) @@ -128,15 +120,8 @@ function factory(type) { return tokens; - /** - * Update line, column, and offset based on - * `value`. - * - * @example - * updatePosition('foo'); - * - * @param {string} subvalue - Subvalue to eat. - */ + /* Update line, column, and offset based on + * `value`. */ function updatePosition(subvalue) { var lastIndex = -1; var index = subvalue.indexOf('\n'); @@ -162,23 +147,14 @@ function factory(type) { } } - /** - * Get offset. Called before the first character is - * eaten to retrieve the range's offsets. - * - * @return {Function} - `done`, to be called when - * the last character is eaten. - */ + /* Get offset. Called before the first character is + * eaten to retrieve the range's offsets. */ function getOffset() { var indentation = []; var pos = line + 1; - /** - * Done. Called when the last character is - * eaten to retrieve the range’s offsets. - * - * @return {Array.} - Offset. - */ + /* Done. Called when the last character is + * eaten to retrieve the range’s offsets. */ return function () { var last = line + 1; @@ -192,14 +168,7 @@ function factory(type) { }; } - /** - * Get the current position. - * - * @example - * position = now(); // {line: 1, column: 1, offset: 0} - * - * @return {Object} - Current Position. - */ + /* Get the current position. */ function now() { var pos = {line: line, column: column}; @@ -208,41 +177,15 @@ function factory(type) { return pos; } - /** - * Store position information for a node. - * - * @example - * start = now(); - * updatePosition('foo'); - * location = new Position(start); - * // { - * // start: {line: 1, column: 1, offset: 0}, - * // end: {line: 1, column: 3, offset: 2} - * // } - * - * @param {Object} start - Starting position. - */ + /* Store position information for a node. */ function Position(start) { this.start = start; this.end = now(); } - /** - * Throw when a value is incorrectly eaten. + /* Throw when a value is incorrectly eaten. * This shouldn’t happen but will throw on new, - * incorrect rules. - * - * @example - * // When the current value is set to `foo bar`. - * validateEat('foo'); - * eat('foo'); - * - * validateEat('bar'); - * // throws, because the space is not eaten. - * - * @param {string} subvalue - Value to be eaten. - * @throws {Error} - When `subvalue` cannot be eaten. - */ + * incorrect rules. */ function validateEat(subvalue) { /* istanbul ignore if */ if (value.substring(0, subvalue.length) !== subvalue) { @@ -257,39 +200,13 @@ function factory(type) { } } - /** - * Mark position and patch `node.position`. - * - * @example - * var update = position(); - * updatePosition('foo'); - * update({}); - * // { - * // position: { - * // start: {line: 1, column: 1, offset: 0}, - * // end: {line: 1, column: 3, offset: 2} - * // } - * // } - * - * @returns {Function} - Updater. - */ + /* Mark position and patch `node.position`. */ function position() { var before = now(); return update; - /** - * Add the position to a node. - * - * @example - * update({type: 'text', value: 'foo'}); - * - * @param {Node} node - Node to attach position - * on. - * @param {Array} [indent] - Indentation for - * `node`. - * @return {Node} - `node`. - */ + /* Add the position to a node. */ function update(node, indent) { var prev = node.position; var start = prev ? prev.start : before; @@ -327,19 +244,8 @@ function factory(type) { } } - /** - * Add `node` to `parent`s children or to `tokens`. - * Performs merges where possible. - * - * @example - * add({}); - * - * add({}, {children: []}); - * - * @param {Object} node - Node to add. - * @param {Object} [parent] - Parent to insert into. - * @return {Object} - Added or merged into node. - */ + /* Add `node` to `parent`s children or to `tokens`. + * Performs merges where possible. */ function add(node, parent) { var children = parent ? parent.children : tokens; var prev = children[children.length - 1]; @@ -365,18 +271,8 @@ function factory(type) { return node; } - /** - * Remove `subvalue` from `value`. - * `subvalue` must be at the start of `value`. - * - * @example - * eat('foo')({type: 'text', value: 'foo'}); - * - * @param {string} subvalue - Removed from `value`, - * and passed to `updatePosition`. - * @return {Function} - Wrapper around `add`, which - * also adds `position` to node. - */ + /* Remove `subvalue` from `value`. + * `subvalue` must be at the start of `value`. */ function eat(subvalue) { var indent = getOffset(); var pos = position(); @@ -396,31 +292,19 @@ function factory(type) { return apply; - /** - * Add the given arguments, add `position` to - * the returned node, and return the node. - * - * @param {Object} node - Node to add. - * @param {Object} [parent] - Node to insert into. - * @return {Node} - Added node. - */ + /* Add the given arguments, add `position` to + * the returned node, and return the node. */ function apply(node, parent) { return pos(add(pos(node), parent), indent); } - /** - * Functions just like apply, but resets the + /* Functions just like apply, but resets the * content: the line and column are reversed, * and the eaten value is re-added. - * * This is useful for nodes with a single * type of content, such as lists and tables. - * * See `apply` above for what parameters are - * expected. - * - * @return {Node} - Added node. - */ + * expected. */ function reset() { var node = apply.apply(null, arguments); @@ -431,12 +315,8 @@ function factory(type) { return node; } - /** - * Test the position, after eating, and reverse - * to a not-eaten state. - * - * @return {Position} - Position after eating `subvalue`. - */ + /* Test the position, after eating, and reverse + * to a not-eaten state. */ function test() { var result = pos({}); diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js index dc83486126112c..321900e7eacd73 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/unescape.js @@ -1,14 +1,5 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:unescape - * @fileoverview Unescape escapes. - */ - 'use strict'; -/* Expose. */ module.exports = factory; /* Factory to de-escape a value, based on a list at `key` diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js index eebd40c94ac26b..3e09e1411ed67c 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/get-indentation.js @@ -1,26 +1,12 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:get-indentation - * @fileoverview Get indentation. - */ - 'use strict'; -/* Expose. */ module.exports = indentation; /* Map of characters, and their column length, * which can be used as indentation. */ var characters = {' ': 1, '\t': 4}; -/** - * Gets indentation information for a line. - * - * @param {string} value - Indented line. - * @return {Object} - Indetation information. - */ +/* Gets indentation information for a line. */ function indentation(value) { var index = 0; var indent = 0; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js index 234ba342e1d3fa..5f211f13f8f534 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/html.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:html - * @fileoverview HTML regexes. - */ - 'use strict'; var attributeName = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js index b8dc2305501db1..e3178ab45c60df 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/interrupt.js @@ -1,11 +1,3 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:get-indentation - * @fileoverview Get indentation. - */ - 'use strict'; module.exports = interrupt; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js index 3602a18f788317..846ceeecac5ade 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/normalize.js @@ -1,29 +1,11 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:normalize - * @fileoverview Normalize an identifier. - */ - 'use strict'; -/* Dependencies. */ var collapseWhiteSpace = require('collapse-white-space'); -/* Expose. */ module.exports = normalize; -/** - * Normalize an identifier. Collapses multiple white space - * characters into a single space, and removes casing. - * - * @example - * normalizeIdentifier('FOO\t bar'); // 'foo bar' - * - * @param {string} value - Content to normalize. - * @return {string} - Normalized content. - */ +/* Normalize an identifier. Collapses multiple white space + * characters into a single space, and removes casing. */ function normalize(value) { return collapseWhiteSpace(value).toLowerCase(); } diff --git a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js index d56db0bad4b735..20f18be74087eb 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js +++ b/tools/node_modules/eslint/node_modules/remark-parse/lib/util/remove-indentation.js @@ -1,42 +1,18 @@ -/** - * @author Titus Wormer - * @copyright 2015 Titus Wormer - * @license MIT - * @module remark:parse:util:remove-indentation - * @fileoverview Remove indentation. - */ - 'use strict'; -/* Dependencies. */ var trim = require('trim'); var repeat = require('repeat-string'); var getIndent = require('./get-indentation'); -/* Expose. */ module.exports = indentation; -/* Characters. */ var C_SPACE = ' '; var C_NEWLINE = '\n'; var C_TAB = '\t'; -/** - * Remove the minimum indent from every line in `value`. +/* Remove the minimum indent from every line in `value`. * Supports both tab, spaced, and mixed indentation (as - * well as possible). - * - * @example - * removeIndentation(' foo'); // 'foo' - * removeIndentation(' foo', 2); // ' foo' - * removeIndentation('\tfoo', 2); // ' foo' - * removeIndentation(' foo\n bar'); // ' foo\n bar' - * - * @param {string} value - Value to trim. - * @param {number?} [maximum] - Maximum indentation - * to remove. - * @return {string} - Unindented `value`. - */ + * well as possible). */ function indentation(value, maximum) { var values = value.split(C_NEWLINE); var position = values.length + 1; diff --git a/tools/node_modules/eslint/node_modules/remark-parse/package.json b/tools/node_modules/eslint/node_modules/remark-parse/package.json index fcecf978cd74e0..b47866c95b256b 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/package.json +++ b/tools/node_modules/eslint/node_modules/remark-parse/package.json @@ -5,7 +5,7 @@ "url": "http://wooorm.com" }, "bugs": { - "url": "https://github.com/wooorm/remark/issues" + "url": "https://github.com/remarkjs/remark/issues" }, "bundleDependencies": false, "contributors": [ @@ -21,13 +21,12 @@ ], "dependencies": { "collapse-white-space": "^1.0.2", - "has": "^1.0.1", "is-alphabetical": "^1.0.0", "is-decimal": "^1.0.0", "is-whitespace-character": "^1.0.0", "is-word-character": "^1.0.0", "markdown-escapes": "^1.0.0", - "parse-entities": "^1.0.2", + "parse-entities": "^1.1.0", "repeat-string": "^1.5.4", "state-toggle": "^1.0.0", "trim": "0.0.1", @@ -56,8 +55,8 @@ "name": "remark-parse", "repository": { "type": "git", - "url": "https://github.com/wooorm/remark/tree/master/packages/remark-parse" + "url": "https://github.com/remarkjs/remark/tree/master/packages/remark-parse" }, - "version": "3.0.1", + "version": "5.0.0", "xo": false } \ No newline at end of file diff --git a/tools/node_modules/eslint/node_modules/remark-parse/readme.md b/tools/node_modules/eslint/node_modules/remark-parse/readme.md index 53426f41eee224..ecaa6c093c0ab2 100644 --- a/tools/node_modules/eslint/node_modules/remark-parse/readme.md +++ b/tools/node_modules/eslint/node_modules/remark-parse/readme.md @@ -33,7 +33,7 @@ process.stdin ## Table of Contents * [API](#api) - * [processor.use(parse)](#processoruseparse) + * [processor.use(parse\[, options\])](#processoruseparse-options) * [parse.Parser](#parseparser) * [Extending the Parser](#extending-the-parser) * [Parser#blockTokenizers](#parserblocktokenizers) @@ -46,29 +46,19 @@ process.stdin * [add(node\[, parent\])](#addnode-parent) * [add.test()](#addtest) * [add.reset(node\[, parent\])](#addresetnode-parent) + * [Turning off a tokenizer](#turning-off-a-tokenizer) * [License](#license) ## API -### `processor.use(parse)` +### `processor.use(parse[, options])` Configure the `processor` to read markdown as input and process an [**MDAST**][mdast] syntax tree. -#### `options` +##### `options` -Options are passed later through [`processor.parse()`][parse], -[`processor.process()`][process], or [`processor.pipe()`][pipe]. -The following settings are supported: - -* [`gfm`][options-gfm] (`boolean`, default: `true`) -* [`yaml`][options-yaml] (`boolean`, default: `true`) -* [`commonmark`][options-commonmark] (`boolean`, default: `false`) -* [`footnotes`][options-footnotes] (`boolean`, default: `false`) -* [`pedantic`][options-pedantic] (`boolean`, default: `false`) -* [`breaks`][options-breaks] (`boolean`, default: `false`) -* [`blocks`][options-blocks] (`Array.`, default: list of block HTML - elements) +Options are passed directly, or passed later through [`processor.data()`][data]. ##### `options.gfm` @@ -76,7 +66,7 @@ The following settings are supported: hello ~~hi~~ world ``` -GFM mode (default: `true`) turns on: +GFM mode (`boolean`, default: `true`) turns on: * [Fenced code blocks](https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks) * [Autolinking of URLs](https://help.github.com/articles/github-flavored-markdown/#url-autolinking) @@ -84,19 +74,6 @@ GFM mode (default: `true`) turns on: * [Task lists](https://help.github.com/articles/writing-on-github/#task-lists) * [Tables](https://help.github.com/articles/github-flavored-markdown/#tables) -##### `options.yaml` - -```md ---- -title: YAML is Cool ---- - -# YAML is Cool -``` - -YAML mode (default: `true`) enables raw YAML front matter to be detected -at the top. - ##### `options.commonmark` ```md @@ -104,7 +81,7 @@ This is a paragraph and this is also part of the preceding paragraph. ``` -CommonMark mode (default: `false`) allows: +CommonMark mode (`boolean`, default: `false`) allows: * Empty lines to split blockquotes * Parentheses (`(` and `)`) around for link and image titles @@ -136,20 +113,10 @@ And something else[^1]. * ...and a list ``` -Footnotes mode (default: `false`) enables reference footnotes and inline -footnotes. Both are wrapped in square brackets and preceded by a caret +Footnotes mode (`boolean`, default: `false`) enables reference footnotes and +inline footnotes. Both are wrapped in square brackets and preceded by a caret (`^`), and can be referenced from inside other footnotes. -##### `options.breaks` - -```md -This is a -paragraph. -``` - -Breaks mode (default: `false`) exposes newline characters inside -paragraphs as breaks. - ##### `options.blocks` ```md @@ -157,8 +124,8 @@ paragraphs as breaks. ``` -Blocks (default: a list of HTML block elements) exposes -let’s users define block-level HTML elements. +Blocks (`Array.`, default: list of [block HTML elements][blocks]) +exposes let’s users define block-level HTML elements. ##### `options.pedantic` @@ -166,7 +133,7 @@ let’s users define block-level HTML elements. Check out some_file_name.txt ``` -Pedantic mode (default: `false`) turns on: +Pedantic mode (`boolean`, default: `false`) turns on: * Emphasis (`_alpha_`) and importance (`__bravo__`) with underscores in words @@ -187,11 +154,11 @@ the desired output. Sometimes, mainly when introducing new syntactic entities with a certain level of precedence, interfacing with the parser is necessary. -If this plug-in is used, it adds a [`Parser`][parser] constructor to -the `processor`. Other plug-ins can add tokenizers to the parser’s -prototype to change how markdown is parsed. +If the `remark-parse` plugin is used, it adds a [`Parser`][parser] constructor +to the `processor`. Other plugins can add tokenizers to the parser’s prototype +to change how markdown is parsed. -The below plug-in adds a [tokenizer][] for at-mentions. +The below plugin adds a [tokenizer][] for at-mentions. ```js module.exports = mentions; @@ -215,22 +182,63 @@ An object mapping tokenizer names to [tokenizer][]s. These tokenizers (for example: `fencedCode`, `table`, and `paragraph`) eat from the start of a value to a line ending. +See `#blockMethods` below for a list of methods that are included by +default. + ### `Parser#blockMethods` Array of `blockTokenizers` names (`string`) specifying the order in which they run. + + +* `newline` +* `indentedCode` +* `fencedCode` +* `blockquote` +* `atxHeading` +* `thematicBreak` +* `list` +* `setextHeading` +* `html` +* `footnote` +* `definition` +* `table` +* `paragraph` + + + ### `Parser#inlineTokenizers` An object mapping tokenizer names to [tokenizer][]s. These tokenizers (for example: `url`, `reference`, and `emphasis`) eat from the start of a value. To increase performance, they depend on [locator][]s. +See `#inlineMethods` below for a list of methods that are included by +default. + ### `Parser#inlineMethods` Array of `inlineTokenizers` names (`string`) specifying the order in which they run. + + +* `escape` +* `autoLink` +* `url` +* `html` +* `link` +* `reference` +* `strong` +* `emphasis` +* `deletion` +* `code` +* `break` +* `text` + + + ### `function tokenizer(eat, value, silent)` ```js @@ -379,63 +387,58 @@ for list items The given `node`. +### Turning off a tokenizer + +In rare situations, you may want to turn off a tokenizer to avoid parsing +that syntactic feature. This can be done by deleting the tokenizer from +your Parser’s `blockTokenizers` (or `blockMethods`) or `inlineTokenizers` +(or `inlineMethods`). + +The following example turns off indented code blocks: + +```js +delete remarkParse.Parser.prototype.blockTokenizers.indentedCode; +``` + ## License [MIT][license] © [Titus Wormer][author] -[build-badge]: https://img.shields.io/travis/wooorm/remark.svg +[build-badge]: https://img.shields.io/travis/remarkjs/remark.svg -[build-status]: https://travis-ci.org/wooorm/remark +[build-status]: https://travis-ci.org/remarkjs/remark -[coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/remark.svg +[coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark.svg -[coverage-status]: https://codecov.io/github/wooorm/remark +[coverage-status]: https://codecov.io/github/remarkjs/remark -[chat-badge]: https://img.shields.io/gitter/room/wooorm/remark.svg +[chat-badge]: https://img.shields.io/gitter/room/remarkjs/Lobby.svg -[chat]: https://gitter.im/wooorm/remark +[chat]: https://gitter.im/remarkjs/Lobby -[license]: https://github.com/wooorm/remark/blob/master/LICENSE +[license]: https://github.com/remarkjs/remark/blob/master/LICENSE [author]: http://wooorm.com [npm]: https://docs.npmjs.com/cli/install -[unified]: https://github.com/wooorm/unified - -[parse]: https://github.com/wooorm/unified#processorparsefilevalue-options +[unified]: https://github.com/unifiedjs/unified -[process]: https://github.com/wooorm/unified#processorprocessfilevalue-options-done +[data]: https://github.com/unifiedjs/unified#processordatakey-value -[pipe]: https://github.com/wooorm/unified#processorpipestream-options +[processor]: https://github.com/unifiedjs/remark/blob/master/packages/remark -[processor]: https://github.com/wooorm/remark/blob/master/packages/remark - -[mdast]: https://github.com/wooorm/mdast +[mdast]: https://github.com/syntax-tree/mdast [escapes]: http://spec.commonmark.org/0.25/#backslash-escapes -[node]: https://github.com/wooorm/unist#node - -[location]: https://github.com/wooorm/unist#location - -[options-gfm]: #optionsgfm - -[options-yaml]: #optionsyaml - -[options-commonmark]: #optionscommonmark +[node]: https://github.com/syntax-tree/unist#node -[options-footnotes]: #optionsfootnotes +[location]: https://github.com/syntax-tree/unist#location -[options-pedantic]: #optionspedantic - -[options-breaks]: #optionsbreaks - -[options-blocks]: #optionsblocks - -[parser]: https://github.com/wooorm/unified#processorparser +[parser]: https://github.com/unifiedjs/unified#processorparser [extend]: #extending-the-parser @@ -446,3 +449,5 @@ The given `node`. [eat]: #eatsubvalue [add]: #addnode-parent + +[blocks]: https://github.com/remarkjs/remark/blob/master/packages/remark-parse/lib/block-elements.json diff --git a/tools/node_modules/eslint/package.json b/tools/node_modules/eslint/package.json index 7b47dbd691f1ce..f35659fc8a1c23 100644 --- a/tools/node_modules/eslint/package.json +++ b/tools/node_modules/eslint/package.json @@ -17,7 +17,7 @@ "cross-spawn": "^6.0.5", "debug": "^4.0.1", "doctrine": "^2.1.0", - "eslint-plugin-markdown": "^1.0.0-beta.8", + "eslint-plugin-markdown": "^1.0.0-rc.1", "eslint-scope": "^4.0.0", "eslint-utils": "^1.3.1", "eslint-visitor-keys": "^1.0.0", @@ -66,8 +66,8 @@ "coveralls": "^3.0.1", "dateformat": "^3.0.3", "ejs": "^2.6.1", - "eslint-plugin-eslint-plugin": "^1.2.0", - "eslint-plugin-node": "^7.0.1", + "eslint-plugin-eslint-plugin": "^1.4.1", + "eslint-plugin-node": "^8.0.0", "eslint-plugin-rulesdir": "^0.1.0", "eslint-release": "^1.0.0", "eslint-rule-composer": "^0.3.0", @@ -135,5 +135,5 @@ "publish-release": "node Makefile.js publishRelease", "test": "node Makefile.js test" }, - "version": "5.8.0" + "version": "5.9.0" } \ No newline at end of file From ea5d1841af0625254502360fabe7f7079cc39c2f Mon Sep 17 00:00:00 2001 From: Paul Hodgson Date: Fri, 9 Nov 2018 08:02:26 +0000 Subject: [PATCH 207/249] test: remove unused parameters in function definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused parameters triggerAsyncId and resource from oninit function in test-async-await.js. PR-URL: https://github.com/nodejs/node/pull/24268 Reviewed-By: Weijia Wang Reviewed-By: Daniel Bevenius Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater Reviewed-By: Tobias Nießen --- test/async-hooks/test-async-await.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/async-hooks/test-async-await.js b/test/async-hooks/test-async-await.js index f5e886e9d50001..0103f63621e3ba 100644 --- a/test/async-hooks/test-async-await.js +++ b/test/async-hooks/test-async-await.js @@ -26,7 +26,7 @@ const hooks = initHooks({ }); hooks.enable(); -function oninit(asyncId, type, triggerAsyncId, resource) { +function oninit(asyncId, type) { if (type === 'PROMISE') { promisesInitState.set(asyncId, 'inited'); } From 89c3388a77ac0d7bf05af4cf9c4a8f574721fdf9 Mon Sep 17 00:00:00 2001 From: Emanuel Kluge Date: Tue, 6 Nov 2018 16:15:02 +0100 Subject: [PATCH 208/249] test: fix arguments order in assertions Have the actual value first & the expected value second. PR-URL: https://github.com/nodejs/node/pull/24149 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil Reviewed-By: Ruben Bridgewater --- test/parallel/test-process-env.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/parallel/test-process-env.js b/test/parallel/test-process-env.js index 69379f60061985..60f4d6f4faf13b 100644 --- a/test/parallel/test-process-env.js +++ b/test/parallel/test-process-env.js @@ -26,12 +26,12 @@ const assert = require('assert'); // changes in environment should be visible to child processes if (process.argv[2] === 'you-are-the-child') { - assert.strictEqual(false, 'NODE_PROCESS_ENV_DELETED' in process.env); - assert.strictEqual('42', process.env.NODE_PROCESS_ENV); - assert.strictEqual('asdf', process.env.hasOwnProperty); + assert.strictEqual('NODE_PROCESS_ENV_DELETED' in process.env, false); + assert.strictEqual(process.env.NODE_PROCESS_ENV, '42'); + assert.strictEqual(process.env.hasOwnProperty, 'asdf'); const hasOwnProperty = Object.prototype.hasOwnProperty; const has = hasOwnProperty.call(process.env, 'hasOwnProperty'); - assert.strictEqual(true, has); + assert.strictEqual(has, true); process.exit(0); } @@ -41,18 +41,18 @@ if (process.argv[2] === 'you-are-the-child') { assert.strictEqual(Object.prototype.hasOwnProperty, process.env.hasOwnProperty); const has = process.env.hasOwnProperty('hasOwnProperty'); - assert.strictEqual(false, has); + assert.strictEqual(has, false); process.env.hasOwnProperty = 'asdf'; process.env.NODE_PROCESS_ENV = 42; - assert.strictEqual('42', process.env.NODE_PROCESS_ENV); + assert.strictEqual(process.env.NODE_PROCESS_ENV, '42'); process.env.NODE_PROCESS_ENV_DELETED = 42; - assert.strictEqual(true, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual('NODE_PROCESS_ENV_DELETED' in process.env, true); delete process.env.NODE_PROCESS_ENV_DELETED; - assert.strictEqual(false, 'NODE_PROCESS_ENV_DELETED' in process.env); + assert.strictEqual('NODE_PROCESS_ENV_DELETED' in process.env, false); const child = spawn(process.argv[0], [process.argv[1], 'you-are-the-child']); child.stdout.on('data', function(data) { console.log(data.toString()); }); From c2599a14deb18c611ca5c796fd096a0bc0e2829e Mon Sep 17 00:00:00 2001 From: Lauri Piisang Date: Tue, 6 Nov 2018 16:19:07 +0000 Subject: [PATCH 209/249] http: remove obsolete function escapeHeaderValue There are test cases which validate the useful path of the function never runs the functionality of it is obsoleted by checkInvalidHeaderChar PR-URL: https://github.com/nodejs/node/pull/24173 Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- lib/_http_outgoing.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index 67d0090d7dabf7..04a36d2be2fde3 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -409,7 +409,7 @@ function processHeader(self, state, key, value, validate) { function storeHeader(self, state, key, value, validate) { if (validate) validateHeaderValue(key, value); - state.header += key + ': ' + escapeHeaderValue(value) + CRLF; + state.header += key + ': ' + value + CRLF; matchHeader(self, state, key, value); } @@ -642,13 +642,6 @@ function connectionCorkNT(msg, conn) { } -function escapeHeaderValue(value) { - // Protect against response splitting. The regex test is there to - // minimize the performance impact in the common case. - return /[\r\n]/.test(value) ? value.replace(/[\r\n]+[ \t]*/g, '') : value; -} - - OutgoingMessage.prototype.addTrailers = function addTrailers(headers) { this._trailer = ''; var keys = Object.keys(headers); @@ -670,7 +663,7 @@ OutgoingMessage.prototype.addTrailers = function addTrailers(headers) { debug('Trailer "%s" contains invalid characters', field); throw new ERR_INVALID_CHAR('trailer content', field); } - this._trailer += field + ': ' + escapeHeaderValue(value) + CRLF; + this._trailer += field + ': ' + value + CRLF; } }; From f5945c927927d19d92423de57fc368442b9d1c09 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 10 Nov 2018 16:09:33 -0500 Subject: [PATCH 210/249] src: sort internal binding list PR-URL: https://github.com/nodejs/node/pull/24292 Reviewed-By: Gus Caplan Reviewed-By: Richard Lau Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Weijia Wang Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Franziska Hinkelmann --- lib/internal/bootstrap/loaders.js | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index 6e06e560a5728f..1879c0154c3179 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -75,31 +75,31 @@ // to provide a transition path for modules that are being moved over to // internalBinding. const internalBindingWhitelist = [ + 'async_wrap', + 'buffer', 'cares_wrap', + 'constants', + 'contextify', + 'crypto', 'fs_event_wrap', + 'http_parser', 'icu', - 'udp_wrap', - 'uv', + 'js_stream', + 'natives', 'pipe_wrap', - 'http_parser', 'process_wrap', - 'v8', - 'tty_wrap', - 'stream_wrap', 'signal_wrap', - 'crypto', - 'contextify', + 'spawn_sync', + 'stream_wrap', 'tcp_wrap', 'tls_wrap', - 'util', - 'async_wrap', + 'tty_wrap', + 'udp_wrap', 'url', - 'spawn_sync', - 'js_stream', - 'zlib', - 'buffer', - 'natives', - 'constants' + 'util', + 'uv', + 'v8', + 'zlib' ]; // We will use a lazy loaded SafeSet in internalBindingWhitelistHas // for checking existence in this list. From 7601cdfe8bd47a1eee0851029258d24553be5364 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 7 Nov 2018 07:09:40 -0500 Subject: [PATCH 211/249] src: bundle persistent-to-local methods as class Create a class `PersistentToLocal` which contains three methods, `Strong`, `Weak`, and `Default`: * `Strong` returns a `Local` from a strong persistent reference, * `Weak` returns a `Local` from a weak persistent reference, and * `Default` decides based on `IsWeak()` which of the above two to call. These replace `node::StrongPersistentToLocal()`, `node::WeakPersistentToLocal()`, and `node::PersistentToLocal()`, respectively. PR-URL: https://github.com/nodejs/node/pull/24276 Reviewed-By: Joyee Cheung Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Refael Ackermann --- src/async_wrap.cc | 3 ++- src/base_object-inl.h | 2 +- src/env-inl.h | 2 +- src/heap_utils.cc | 2 +- src/memory_tracker.h | 2 +- src/node_api.cc | 2 +- src/node_contextify.cc | 4 ++-- src/node_contextify.h | 2 +- src/node_crypto.cc | 3 ++- src/node_internals.h | 8 -------- src/node_persistent.h | 36 ++++++++++++++++++++++++++++++++++++ src/node_zlib.cc | 4 ++-- src/util-inl.h | 25 ------------------------- src/util.h | 22 ---------------------- 14 files changed, 50 insertions(+), 67 deletions(-) diff --git a/src/async_wrap.cc b/src/async_wrap.cc index d23e59f69e721c..21206e7208ea68 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -358,7 +358,8 @@ void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo& info) { HandleScope scope(info.GetIsolate()); std::unique_ptr p{info.GetParameter()}; - Local prop_bag = PersistentToLocal(info.GetIsolate(), p->propBag); + Local prop_bag = PersistentToLocal::Default(info.GetIsolate(), + p->propBag); Local val; if (!prop_bag->Get(p->env->context(), p->env->destroyed_string()) diff --git a/src/base_object-inl.h b/src/base_object-inl.h index 8c8fa1699c3069..0b8fbb8520c283 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -62,7 +62,7 @@ Persistent& BaseObject::persistent() { v8::Local BaseObject::object() const { - return PersistentToLocal(env_->isolate(), persistent_handle_); + return PersistentToLocal::Default(env_->isolate(), persistent_handle_); } v8::Local BaseObject::object(v8::Isolate* isolate) const { diff --git a/src/env-inl.h b/src/env-inl.h index 30fed57b71fbed..70a8e052258531 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -899,7 +899,7 @@ void Environment::ForEachBaseObject(T&& iterator) { #define V(PropertyName, TypeName) \ inline v8::Local Environment::PropertyName() const { \ - return StrongPersistentToLocal(PropertyName ## _); \ + return PersistentToLocal::Strong(PropertyName ## _); \ } \ inline void Environment::set_ ## PropertyName(v8::Local value) { \ PropertyName ## _.Reset(isolate(), value); \ diff --git a/src/heap_utils.cc b/src/heap_utils.cc index 72ad33c99a1e80..d1e3fad0980280 100644 --- a/src/heap_utils.cc +++ b/src/heap_utils.cc @@ -26,7 +26,7 @@ class JSGraphJSNode : public EmbedderGraph::Node { const char* Name() override { return ""; } size_t SizeInBytes() override { return 0; } bool IsEmbedderNode() override { return false; } - Local JSValue() { return StrongPersistentToLocal(persistent_); } + Local JSValue() { return PersistentToLocal::Strong(persistent_); } int IdentityHash() { Local v = JSValue(); diff --git a/src/memory_tracker.h b/src/memory_tracker.h index 17992792128809..11dd2be7af35c9 100644 --- a/src/memory_tracker.h +++ b/src/memory_tracker.h @@ -69,7 +69,7 @@ class NodeBIO; * // a BaseObject or an AsyncWrap class * bool IsRootNode() const override { return !wrapped_.IsWeak(); } * v8::Local WrappedObject() const override { - * return node::PersistentToLocal(wrapped_); + * return node::PersistentToLocal::Default(wrapped_); * } * private: * AnotherRetainerClass another_retainer_; diff --git a/src/node_api.cc b/src/node_api.cc index c023920da41f74..500312750974ef 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -30,7 +30,7 @@ struct napi_env__ { node::Persistent context_persistent; inline v8::Local context() const { - return StrongPersistentToLocal(context_persistent); + return node::PersistentToLocal::Strong(context_persistent); } inline node::Environment* node_env() const { diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 37afead80896d0..bc08e31a065306 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -767,7 +767,7 @@ void ContextifyScript::CreateCachedData( ContextifyScript* wrapped_script; ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); Local unbound_script = - PersistentToLocal(env->isolate(), wrapped_script->script_); + PersistentToLocal::Default(env->isolate(), wrapped_script->script_); std::unique_ptr cached_data( ScriptCompiler::CreateCodeCache(unbound_script)); if (!cached_data) { @@ -867,7 +867,7 @@ bool ContextifyScript::EvalMachine(Environment* env, ContextifyScript* wrapped_script; ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false); Local unbound_script = - PersistentToLocal(env->isolate(), wrapped_script->script_); + PersistentToLocal::Default(env->isolate(), wrapped_script->script_); Local