From c9a80a771d88f180160f5e5c43b7e87b858083b4 Mon Sep 17 00:00:00 2001 From: Ali Ince Date: Thu, 16 May 2019 14:45:24 +0100 Subject: [PATCH 1/5] Remove gc and query logging options for test instance --- test/internal/shared-neo4j.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/test/internal/shared-neo4j.js b/test/internal/shared-neo4j.js index 17ec0b972..17f4cc574 100644 --- a/test/internal/shared-neo4j.js +++ b/test/internal/shared-neo4j.js @@ -110,12 +110,9 @@ const additionalConfig = { // shorten the default time to wait for the bookmark from 30 to 5 seconds 'dbms.transaction.bookmark_ready_timeout': '5s', - // enable GC logging - 'dbms.logs.gc.enabled': true, - - // enable query logging - 'dbms.logs.query.enabled': true -}; + // page cache size + 'dbms.memory.pagecache.size': '512m' +} const neoCtrlVersionParam = '-e'; const defaultNeo4jVersion = '3.5'; From 51bc9d7d4c4abb5331d346fa6eba16223abce3d4 Mon Sep 17 00:00:00 2001 From: Ali Ince Date: Mon, 20 May 2019 14:16:15 +0100 Subject: [PATCH 2/5] Upgrade dependencies to their latest versions --- .babelrc | 8 +- gulpfile.babel.js | 413 +- package-lock.json | 12701 +++++++++++++++----------- package.json | 89 +- support/inject-browser-transform.js | 20 + test/browser/karma-chrome.conf.js | 24 +- test/browser/karma-firefox.conf.js | 28 +- test/v1/result.test.js | 6 +- 8 files changed, 7779 insertions(+), 5510 deletions(-) create mode 100644 support/inject-browser-transform.js diff --git a/.babelrc b/.babelrc index 378c8290f..15ce28a39 100644 --- a/.babelrc +++ b/.babelrc @@ -1,6 +1,10 @@ { "presets": [ - "env" + [ + "@babel/preset-env" + ] ], - "plugins": ["transform-runtime"] + "plugins": [ + "@babel/plugin-transform-runtime" + ] } diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 9778a3a1b..8b380e74c 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -17,302 +17,223 @@ * limitations under the License. */ -var browserify = require('browserify'); -var source = require('vinyl-source-stream'); -var buffer = require('vinyl-buffer'); -var gulp = require('gulp'); -var through = require('through2'); -var uglify = require('gulp-uglify'); -var gutil = require('gulp-util'); -var download = require("gulp-download"); -var jasmine = require('gulp-jasmine'); -var babelify = require('babelify'); -var babel = require('gulp-babel'); -var watch = require('gulp-watch'); -var batch = require('gulp-batch'); -var replace = require('gulp-replace'); -var decompress = require('gulp-decompress'); -var fs = require("fs-extra"); -var runSequence = require('run-sequence'); -var path = require('path'); -var minimist = require('minimist'); -var install = require("gulp-install"); -var file = require('gulp-file'); -var semver = require('semver'); -var sharedNeo4j = require('./test/internal/shared-neo4j').default; -var ts = require('gulp-typescript'); -var JasmineConsoleReporter = require('jasmine-console-reporter'); -var karmaServer = require('karma').Server; -var transformTools = require('browserify-transform-tools'); +const browserify = require('browserify') +const source = require('vinyl-source-stream') +const buffer = require('vinyl-buffer') +const gulp = require('gulp') +const uglify = require('gulp-uglify') +const jasmine = require('gulp-jasmine') +const babel = require('gulp-babel') +const watch = require('gulp-watch') +const batch = require('gulp-batch') +const replace = require('gulp-replace') +const fs = require('fs-extra') +const path = require('path') +const minimist = require('minimist') +const install = require('gulp-install') +const file = require('gulp-file') +const semver = require('semver') +const sharedNeo4j = require('./test/internal/shared-neo4j').default +const ts = require('gulp-typescript') +const JasmineConsoleReporter = require('jasmine-console-reporter') +const karma = require('karma') +const log = require('fancy-log') /** * Useful to investigate resource leaks in tests. Enable to see active sockets and file handles after the 'test' task. */ -var enableActiveNodeHandlesLogging = false; - -gulp.task('default', ["test"]); - -gulp.task('browser', function(cb){ - runSequence('build-browser-test', 'build-browser', cb); -}); +const enableActiveNodeHandlesLogging = false /** Build all-in-one files for use in the browser */ -gulp.task('build-browser', function () { - var browserOutput = 'lib/browser'; +gulp.task('browser', async function () { + const browserOutput = 'lib/browser' // Our app bundler - var appBundler = browserify({ + const appBundler = browserify({ entries: ['src/index.js'], cache: {}, standalone: 'neo4j', - packageCache: {} - }).transform(babelifyTransform()) - .transform(browserifyTransformNodeToBrowserRequire()) - .bundle(); + packageCache: {}, + transform: ['babelify', './support/inject-browser-transform'] + }).bundle() // Un-minified browser package - appBundler - .on('error', gutil.log) + await appBundler + .on('error', log.error) .pipe(source('neo4j-web.js')) - .pipe(gulp.dest(browserOutput)); + .pipe(gulp.dest(browserOutput)) - return appBundler - .on('error', gutil.log) + await appBundler + .on('error', log.error) .pipe(source('neo4j-web.min.js')) .pipe(buffer()) .pipe(uglify()) - .pipe(gulp.dest(browserOutput)); -}); - -gulp.task('build-browser-test', function(){ - var browserOutput = 'build/browser/'; - var testFiles = []; - return gulp.src(['./test/**/*.test.js', '!./test/**/node/*.js']) - .pipe( through.obj( function( file, enc, cb ) { - if(file.path.indexOf('examples.test.js') < 0) { - testFiles.push( file.path ); - } - cb(); - }, function(cb) { - // At end-of-stream, push the list of files to the next step - this.push( testFiles ); - cb(); - })) - .pipe( through.obj( function( testFiles, enc, cb) { - browserify({ - entries: testFiles, - cache: {}, - debug: true - }).transform(babelifyTransform()) - .transform(browserifyTransformNodeToBrowserRequire()) - .bundle(function () { - cb(); - }) - .on('error', gutil.log) - .pipe(source('neo4j-web.test.js')) - .pipe(gulp.dest(browserOutput)); - }, - function(cb) { - cb() - } - )); -}); - -var buildNode = function(options) { - return gulp.src(options.src) - .pipe(babel(babelConfig())) - .pipe(gulp.dest(options.dest)) -}; - -gulp.task('nodejs', function(){ - return buildNode({ - src: 'src/**/*.js', - dest: 'lib' - }); -}); + .pipe(gulp.dest(browserOutput)) +}) -gulp.task('all', function(cb){ - runSequence('nodejs', 'browser', cb); -}); +gulp.task('nodejs', function () { + return gulp + .src('src/**/*.js') + .pipe(babel()) + .pipe(gulp.dest('lib')) +}) // prepares directory for package.test.js -gulp.task('install-driver-into-sandbox', ['nodejs'], function(){ - var testDir = path.join('build', 'sandbox'); - fs.emptyDirSync(testDir); - - var packageJsonContent = JSON.stringify({ - 'private': true, - 'dependencies': { - 'neo4j-driver': __dirname - } - }); +gulp.task( + 'install-driver-into-sandbox', + gulp.series('nodejs', function () { + const testDir = path.join('build', 'sandbox') + fs.emptyDirSync(testDir) + + const packageJsonContent = JSON.stringify({ + private: true, + dependencies: { + 'neo4j-driver': __dirname + } + }) - return file('package.json', packageJsonContent, {src:true}) + return file('package.json', packageJsonContent, { src: true }) .pipe(gulp.dest(testDir)) - .pipe(install()); -}); - -gulp.task('test', function (cb) { - runSequence('run-ts-declaration-tests', 'test-nodejs', 'test-browser', function (err) { - if (err) { - var exitCode = 2; - console.log('[FAIL] test task failed - exiting with code ' + exitCode); - return process.exit(exitCode); - } - return cb(); - }); -}); - -gulp.task('test-nodejs', ['install-driver-into-sandbox'], function () { - return gulp.src(['./test/**/*.test.js', '!./test/**/browser/*.js']) - .pipe(jasmine({ - includeStackTrace: true, - reporter: newJasmineConsoleReporter() - })).on('end', logActiveNodeHandles); -}); - -gulp.task('test-browser', function (cb) { - runSequence('all', 'run-browser-test', cb) -}); - -gulp.task('run-browser-test', function(cb){ - runSequence('run-browser-test-firefox', cb); -}); - -gulp.task('run-browser-test-chrome', function(cb){ - new karmaServer({ - configFile: __dirname + '/test/browser/karma-chrome.conf.js', - }, cb).start(); -}); - -gulp.task('run-browser-test-firefox', function(cb){ - new karmaServer({ - configFile: __dirname + '/test/browser/karma-firefox.conf.js', - }, cb).start(); -}); - -gulp.task('run-browser-test-edge', function(cb){ - new karmaServer({ - configFile: __dirname + '/test/browser/karma-edge.conf.js', - }, cb).start(); -}); - -gulp.task('run-browser-test-ie', function (cb) { - new karmaServer({ - configFile: __dirname + '/test/browser/karma-ie.conf.js', - }, cb).start(); -}); + .pipe(install()) + }) +) + +gulp.task( + 'test-nodejs', + gulp.series('install-driver-into-sandbox', function () { + return gulp + .src(['./test/**/*.test.js', '!./test/**/browser/*.js']) + .pipe( + jasmine({ + includeStackTrace: true, + reporter: newJasmineConsoleReporter() + }) + ) + .on('end', logActiveNodeHandles) + }) +) + +gulp.task('run-browser-test-chrome', function (cb) { + runKarma('chrome', cb) +}) + +gulp.task('run-browser-test-firefox', function (cb) { + runKarma('firefox', cb) +}) + +gulp.task('run-browser-test', gulp.series('run-browser-test-firefox')) gulp.task('watch', function () { - return watch('src/**/*.js', batch(function (events, done) { - gulp.start('all', done); - })); -}); + return watch( + 'src/**/*.js', + batch(function (events, done) { + gulp.start('all', done) + }) + ) +}) -gulp.task('watch-n-test', ['test-nodejs'], function () { - return gulp.watch(['src/**/*.js', "test/**/*.js"], ['test-nodejs'] ); -}); +gulp.task( + 'watch-n-test', + gulp.series('test-nodejs', function () { + return gulp.watch(['src/**/*.js', 'test/**/*.js'], ['test-nodejs']) + }) +) /** Set the project version, controls package.json and version.js */ -gulp.task('set', function() { +gulp.task('set', function () { // Get the --version arg from command line - var version = minimist(process.argv.slice(2), { string: 'version' }).version; + const version = minimist(process.argv.slice(2), { string: 'version' }).version if (!semver.valid(version)) { - throw 'Invalid version "' + version + '"'; + throw new Error(`Invalid version "${version}"`) } // Change the version in relevant files - var versionFile = path.join('src', 'version.js'); - return gulp.src([versionFile], {base: "./"}) - .pipe(replace('0.0.0-dev', version)) - .pipe(gulp.dest('./')); - -}); - + const versionFile = path.join('src', 'version.js') + return gulp + .src([versionFile], { base: './' }) + .pipe(replace('0.0.0-dev', version)) + .pipe(gulp.dest('./')) +}) -var neo4jHome = path.resolve('./build/neo4j'); +const neo4jHome = path.resolve('./build/neo4j') gulp.task('start-neo4j', function (done) { - sharedNeo4j.start(neo4jHome, process.env.NEOCTRL_ARGS); - done(); -}); + sharedNeo4j.start(neo4jHome, process.env.NEOCTRL_ARGS) + done() +}) gulp.task('stop-neo4j', function (done) { - sharedNeo4j.stop(neo4jHome); - done(); -}); + sharedNeo4j.stop(neo4jHome) + done() +}) gulp.task('run-stress-tests', function () { - return gulp.src('test/**/stress.test.js') - .pipe(jasmine({ - includeStackTrace: true, - reporter: newJasmineConsoleReporter() - })).on('end', logActiveNodeHandles); -}); - -gulp.task('run-ts-declaration-tests', function () { - var failed = false; - - return gulp.src(['test/types/**/*', 'types/**/*'], {base: '.'}) - .pipe(ts({ - module: 'es6', - target: 'es6', - noImplicitAny: true, - noImplicitReturns: true, - strictNullChecks: true, - })) - .on('error', function () { - failed = true; - }) - .on('finish', function () { - if (failed) { - console.log('[ERROR] TypeScript declarations contain errors. Exiting...'); - process.exit(1); - } - }) - .pipe(gulp.dest('build/test/types')); -}); - -function logActiveNodeHandles() { + return gulp + .src('test/**/stress.test.js') + .pipe( + jasmine({ + includeStackTrace: true, + reporter: newJasmineConsoleReporter() + }) + ) + .on('end', logActiveNodeHandles) +}) + +gulp.task('run-ts-declaration-tests', function (done) { + return gulp + .src(['test/types/**/*', 'types/**/*'], { base: '.' }) + .pipe( + ts({ + module: 'es6', + target: 'es6', + noImplicitAny: true, + noImplicitReturns: true, + strictNullChecks: true + }) + ) + .pipe(gulp.dest('build/test/types')) + .on('error', err => done(err)) + .on('end', () => done()) +}) + +gulp.task('all', gulp.series('nodejs', 'browser')) + +gulp.task('test-browser', gulp.series('browser', 'run-browser-test')) + +gulp.task( + 'test', + gulp.series('run-ts-declaration-tests', 'test-nodejs', 'test-browser') +) + +gulp.task('default', gulp.series('test')) + +function logActiveNodeHandles () { if (enableActiveNodeHandlesLogging) { - console.log('-- Active NodeJS handles START\n', process._getActiveHandles(), '\n-- Active NodeJS handles END'); + console.log( + '-- Active NodeJS handles START\n', + process._getActiveHandles(), + '\n-- Active NodeJS handles END' + ) } } -function newJasmineConsoleReporter() { +function newJasmineConsoleReporter () { return new JasmineConsoleReporter({ colors: 1, cleanStack: 1, verbosity: 4, listStyle: 'indent', activity: false - }); -} - -function babelifyTransform() { - return babelify.configure(babelConfig()); -} - -function babelConfig() { - return { - presets: ['env'], plugins: ['transform-runtime'] - }; + }) } -function browserifyTransformNodeToBrowserRequire() { - var nodeRequire = '/node'; - var browserRequire = '/browser'; - - return transformTools.makeRequireTransform('bodeToBrowserRequireTransform', - {evaluateArguments: true}, - function (args, opts, cb) { - var requireArg = args[0]; - var endsWithNodeRequire = requireArg.slice(-nodeRequire.length) === nodeRequire; - if (endsWithNodeRequire) { - var newRequireArg = requireArg.replace(nodeRequire, browserRequire); - return cb(null, 'require(\'' + newRequireArg + '\')'); - } else { - return cb(); - } - }); +function runKarma (browser, cb) { + new karma.Server( + { + configFile: path.join(__dirname, `/test/browser/karma-${browser}.conf.js`) + }, + function (exitCode) { + exitCode ? process.exit(exitCode) : cb() + } + ).start() } diff --git a/package-lock.json b/package-lock.json index f00af9110..26353d378 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,1349 +4,1906 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@types/node": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.1.3.tgz", - "integrity": "sha512-GiCx7dRvta0hbxXoJFAUxz+CKX6bZSCKjM5slq2vPp/5zwK01T4ibYZkGr6EN4F2QmxDQR76/ZHg6q+7iFWCWw==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.6.tgz", - "integrity": "sha512-8nkZS48EVsMUU0v6F1LCIOw4RYWLm2plMtbhFTjNgeXmsTNLuU3xTRtnljt9BFQB+iPbLRobkNrCWftWnNC7wQ==", + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@webassemblyjs/helper-module-context": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/wast-parser": "1.7.6", - "mamacro": "^0.0.3" + "@babel/highlight": "^7.0.0" } }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz", - "integrity": "sha512-VBOZvaOyBSkPZdIt5VBMg3vPWxouuM13dPXGWI1cBh3oFLNcFJ8s9YA7S9l4mPI7+Q950QqOmqj06oa83hNWBA==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz", - "integrity": "sha512-SCzhcQWHXfrfMSKcj8zHg1/kL9kb3aa5TN4plc/EREOs5Xop0ci5bdVBApbk2yfVi8aL+Ly4Qpp3/TRAUInjrg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz", - "integrity": "sha512-1/gW5NaGsEOZ02fjnFiU8/OEEXU1uVbv2um0pQ9YVL3IHSkyk6xOwokzyqqO1qDZQUAllb+V8irtClPWntbVqw==", - "dev": true - }, - "@webassemblyjs/helper-code-frame": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz", - "integrity": "sha512-+suMJOkSn9+vEvDvgyWyrJo5vJsWSDXZmJAjtoUq4zS4eqHyXImpktvHOZwXp1XQjO5H+YQwsBgqTQEc0J/5zg==", + "@babel/core": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.4.tgz", + "integrity": "sha512-lQgGX3FPRgbz2SKmhMtYgJvVzGZrmjaF4apZ2bLwofAKiSjxU0drPh4S/VasyYXwaTs+A1gvQ45BN8SQJzHsQQ==", "dev": true, "requires": { - "@webassemblyjs/wast-printer": "1.7.6" + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helpers": "^7.4.4", + "@babel/parser": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, - "@webassemblyjs/helper-fsm": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz", - "integrity": "sha512-HCS6KN3wgxUihGBW7WFzEC/o8Eyvk0d56uazusnxXthDPnkWiMv+kGi9xXswL2cvfYfeK5yiM17z2K5BVlwypw==", - "dev": true - }, - "@webassemblyjs/helper-module-context": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz", - "integrity": "sha512-e8/6GbY7OjLM+6OsN7f2krC2qYVNaSr0B0oe4lWdmq5sL++8dYDD1TFbD1TdAdWMRTYNr/Qq7ovXWzia2EbSjw==", + "@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", "dev": true, "requires": { - "mamacro": "^0.0.3" + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + }, + "dependencies": { + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + } } }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz", - "integrity": "sha512-PzYFCb7RjjSdAOljyvLWVqd6adAOabJW+8yRT+NWhXuf1nNZWH+igFZCUK9k7Cx7CsBbzIfXjJc7u56zZgFj9Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz", - "integrity": "sha512-3GS628ppDPSuwcYlQ7cDCGr4W2n9c4hLzvnRKeuz+lGsJSmc/ADVoYpm1ts2vlB1tGHkjtQMni+yu8mHoMlKlA==", + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6" + "@babel/types": "^7.0.0" } }, - "@webassemblyjs/ieee754": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz", - "integrity": "sha512-V4cIp0ruyw+hawUHwQLn6o2mFEw4t50tk530oKsYXQhEzKR+xNGDxs/SFFuyTO7X3NzEu4usA3w5jzhl2RYyzQ==", + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", "dev": true, "requires": { - "@xtuc/ieee754": "^1.2.0" + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "@webassemblyjs/leb128": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.7.6.tgz", - "integrity": "sha512-ojdlG8WpM394lBow4ncTGJoIVZ4aAtNOWHhfAM7m7zprmkVcKK+2kK5YJ9Bmj6/ketTtOn7wGSHCtMt+LzqgYQ==", + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", "dev": true, "requires": { - "@xtuc/long": "4.2.1" + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" } }, - "@webassemblyjs/utf8": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.7.6.tgz", - "integrity": "sha512-oId+tLxQ+AeDC34ELRYNSqJRaScB0TClUU6KQfpB8rNT6oelYlz8axsPhf6yPTg7PBJ/Z5WcXmUYiHEWgbbHJw==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz", - "integrity": "sha512-pTNjLO3o41v/Vz9VFLl+I3YLImpCSpodFW77pNoH4agn5I6GgSxXHXtvWDTvYJFty0jSeXZWLEmbaSIRUDlekg==", + "@babel/helper-define-map": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", + "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/helper-wasm-section": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6", - "@webassemblyjs/wasm-opt": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6", - "@webassemblyjs/wast-printer": "1.7.6" + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" } }, - "@webassemblyjs/wasm-gen": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz", - "integrity": "sha512-mQvFJVumtmRKEUXMohwn8nSrtjJJl6oXwF3FotC5t6e2hlKMh8sIaW03Sck2MDzw9xPogZD7tdP5kjPlbH9EcQ==", + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/ieee754": "1.7.6", - "@webassemblyjs/leb128": "1.7.6", - "@webassemblyjs/utf8": "1.7.6" + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "@webassemblyjs/wasm-opt": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz", - "integrity": "sha512-go44K90fSIsDwRgtHhX14VtbdDPdK2sZQtZqUcMRvTojdozj5tLI0VVJAzLCfz51NOkFXezPeVTAYFqrZ6rI8Q==", + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-buffer": "1.7.6", - "@webassemblyjs/wasm-gen": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6" + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "@webassemblyjs/wasm-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz", - "integrity": "sha512-t1T6TfwNY85pDA/HWPA8kB9xA4sp9ajlRg5W7EKikqrynTyFo+/qDzIpvdkOkOGjlS6d4n4SX59SPuIayR22Yg==", + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-api-error": "1.7.6", - "@webassemblyjs/helper-wasm-bytecode": "1.7.6", - "@webassemblyjs/ieee754": "1.7.6", - "@webassemblyjs/leb128": "1.7.6", - "@webassemblyjs/utf8": "1.7.6" + "@babel/types": "^7.0.0" } }, - "@webassemblyjs/wast-parser": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz", - "integrity": "sha512-1MaWTErN0ziOsNUlLdvwS+NS1QWuI/kgJaAGAMHX8+fMJFgOJDmN/xsG4h/A1Gtf/tz5VyXQciaqHZqp2q0vfg==", + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/floating-point-hex-parser": "1.7.6", - "@webassemblyjs/helper-api-error": "1.7.6", - "@webassemblyjs/helper-code-frame": "1.7.6", - "@webassemblyjs/helper-fsm": "1.7.6", - "@xtuc/long": "4.2.1", - "mamacro": "^0.0.3" + "@babel/types": "^7.4.4" } }, - "@webassemblyjs/wast-printer": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz", - "integrity": "sha512-vHdHSK1tOetvDcl1IV1OdDeGNe/NDDQ+KzuZHMtqTVP1xO/tZ/IKNpj5BaGk1OYFdsDWQqb31PIwdEyPntOWRQ==", + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/wast-parser": "1.7.6", - "@xtuc/long": "4.2.1" + "@babel/types": "^7.0.0" } }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.1.tgz", - "integrity": "sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g==", - "dev": true + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } }, - "JSONStream": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.3.tgz", - "integrity": "sha512-3Sp6WZZ/lXl+nTDoGpGWHEpTnnC6X5fnkolYZR6nwIfzbxxvA8utPWe1gCt7i0m9uVGsSz2IS8K8mJ7HmlduMg==", + "@babel/helper-module-transforms": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", + "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", "dev": true, "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" } }, - "abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", "dev": true, - "optional": true + "requires": { + "@babel/types": "^7.0.0" + } }, - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", "dev": true }, - "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", + "@babel/helper-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", + "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", "dev": true, "requires": { - "acorn": "^5.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - } + "lodash": "^4.17.11" } }, - "acorn-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", - "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", "dev": true, - "optional": true, "requires": { - "acorn": "^2.1.0" - }, - "dependencies": { - "acorn": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", - "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", - "dev": true, - "optional": true - } + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" } }, - "acorn-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz", - "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==", + "@babel/helper-replace-supers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", + "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", "dev": true, "requires": { - "acorn": "^5.4.1", - "xtend": "^4.0.1" - }, - "dependencies": { - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", - "dev": true - } + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" } }, - "addressparser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", - "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", "dev": true, - "optional": true - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", - "dev": true + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } }, - "agent-base": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", - "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", "dev": true, "requires": { - "es6-promisify": "^5.0.0" + "@babel/types": "^7.4.4" } }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", "dev": true, "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" } }, - "ajv-keywords": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", - "dev": true - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "@babel/helpers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", + "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", "dev": true, "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "dependencies": { - "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" - } - } + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" } }, - "amqplib": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.2.tgz", - "integrity": "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA==", + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, - "optional": true, "requires": { - "bitsyntax": "~0.0.4", - "bluebird": "^3.4.6", - "buffer-more-ints": "0.0.2", - "readable-stream": "1.x >=1.1.9", - "safe-buffer": "^5.0.1" + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" }, "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "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, - "optional": true + "requires": { + "color-convert": "^1.9.0" + } }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" } } } }, - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "@babel/parser": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.4.tgz", + "integrity": "sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", "dev": true, "requires": { - "ansi-wrap": "^0.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" } }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", "dev": true, "requires": { - "ansi-wrap": "0.1.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" } }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz", + "integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", + "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", "dev": true, "requires": { - "micromatch": "^2.1.5", - "normalize-path": "^2.0.0" + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" }, "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", "dev": true, "requires": { - "arr-flatten": "^1.0.1" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" } }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", "dev": true }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", "dev": true, "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" + "jsesc": "~0.5.0" } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + } + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", + "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz", + "integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.11" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", + "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.4", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + }, + "dependencies": { + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + } + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", + "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", + "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", "dev": true, "requires": { - "is-posix-bracket": "^0.1.0" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" } }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", "dev": true, "requires": { - "is-extglob": "^1.0.0" + "jsesc": "~0.5.0" } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + } + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", + "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", + "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", + "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", + "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.4.tgz", + "integrity": "sha512-Ki+Y9nXBlKfhD+LXaRS7v95TtTGYRAf9Y1rTDiE75zf8YQz4GDaWRXosMfJBXxnk88mGFjWdCRIeqDbon7spYA==", + "dev": true, + "requires": { + "regexp-tree": "^0.1.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", + "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.4.tgz", + "integrity": "sha512-Zz3w+pX1SI0KMIiqshFZkwnVGUhDZzpX2vtPzfJBKQQq8WsP/Xy9DNdELWivxcKOCX/Pywge4SiEaPaLtoDT4g==", + "dev": true, + "requires": { + "regenerator-transform": "^0.13.4" + }, + "dependencies": { + "regenerator-transform": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.4.tgz", + "integrity": "sha512-T0QMBjK3J0MtxjPmdIMXm72Wvj2Abb0Bd4HADdfijwMdoIsyQZ6fWC7kDFhk2YinBBEMZDL7Y7wh0J1sGx3S4A==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + } + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.4.4.tgz", + "integrity": "sha512-aMVojEjPszvau3NRg+TIH14ynZLvPewH4xhlCW1w6A3rkxTS1m4uwzRclYR9oS+rl/dr+kT+pzbfHuAWP/lc7Q==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", + "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "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=", + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", "dev": true, "requires": { - "is-extglob": "^1.0.0" + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" } }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + } + } + } + }, + "@babel/preset-env": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.4.tgz", + "integrity": "sha512-FU1H+ACWqZZqfw1x2G1tgtSSYSfxJLkpaUQL37CenULFARDo+h4xJoVHzRoHbK+85ViLciuI7ME4WTIhFRBBlw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.4.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.4.4", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.4.4", + "@babel/plugin-transform-classes": "^7.4.4", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.4.4", + "@babel/plugin-transform-modules-systemjs": "^7.4.4", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.4", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.4", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "browserslist": "^4.5.2", + "core-js-compat": "^3.0.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + }, + "dependencies": { + "browserslist": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.0.tgz", + "integrity": "sha512-Jk0YFwXBuMOOol8n6FhgkDzn3mY9PYLYGk29zybF05SbRTsMgPqmTNeQQhOghCxq5oFqAXE3u4sYddr4C0uRhg==", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "caniuse-lite": "^1.0.30000967", + "electron-to-chromium": "^1.3.133", + "node-releases": "^1.1.19" } }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "caniuse-lite": { + "version": "1.0.30000969", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000969.tgz", + "integrity": "sha512-Kus0yxkoAJgVc0bax7S4gLSlFifCa7MnSZL9p9VuS/HIKEL4seaqh28KIQAAO50cD/rJ5CiJkJFapkdDAlhFxQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.135", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.135.tgz", + "integrity": "sha512-xXLNstRdVsisPF3pL3H9TVZo2XkMILfqtD6RiWIUmDK2sFX1Bjwqmd8LBp0Kuo2FgKO63JXPoEVGm8WyYdwP0Q==", + "dev": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } + } + }, + "@babel/register": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.4.4.tgz", + "integrity": "sha512-sn51H88GRa00+ZoMqCVgOphmswG4b7mhf9VOB0LUBAieykq2GnRFerlN+JQkO/ntT7wz4jaHNSRPg9IdMPEUkA==", + "dev": true, + "requires": { + "core-js": "^3.0.0", + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.11", + "mkdirp": "^0.5.1", + "pirates": "^4.0.0", + "source-map-support": "^0.5.9" + }, + "dependencies": { + "core-js": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.0.tgz", + "integrity": "sha512-EyF8cMvUWRDWRLmC3+i50D1DqK4aFZWb/6PDPP2QfX2r0zXkgR2V9wt7jX7TRM0Qdj/3f6+JQkqfCaGkSj92iQ==", + "dev": true + } + } + }, + "@babel/runtime": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.4.tgz", + "integrity": "sha512-w0+uT71b6Yi7i5SE0co4NioIpSYS6lLiXvCzWzGSKvpK5vdQtCbICHMj+gbAKAOtxiV6HsVh/MBdaF9EQ6faSg==", + "requires": { + "regenerator-runtime": "^0.13.2" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz", + "integrity": "sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==" + } + } + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.4.tgz", + "integrity": "sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "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" + "ms": "^2.1.1" } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + }, + "dependencies": { + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true } } }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "archive-type": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-3.2.0.tgz", - "integrity": "sha1-nNnABpV+vpX62tW9YJiUKoE3N/Y=", + "@samverschueren/stream-to-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz", + "integrity": "sha512-MI4Xx6LHs4Webyvi6EbspgyAb4D2Q2VtnCQ1blOJcoLS6mVa8lNN2rkIy1CVxfTUpoyIbCTkXES1rLXztFD1lg==", "dev": true, "requires": { - "file-type": "^3.1.0" + "any-observable": "^0.3.0" } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "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 - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "@types/node": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.1.3.tgz", + "integrity": "sha512-GiCx7dRvta0hbxXoJFAUxz+CKX6bZSCKjM5slq2vPp/5zwK01T4ibYZkGr6EN4F2QmxDQR76/ZHg6q+7iFWCWw==", "dev": true }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", - "dev": true + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", "dev": true }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", "dev": true }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", "dev": true }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", "dev": true }, - "asn1.js": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", - "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", "dev": true, "requires": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" } }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", "dev": true, "requires": { - "util": "0.10.3" + "@xtuc/ieee754": "^1.2.0" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", "dev": true }, - "ast-types": { - "version": "0.11.5", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz", - "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==", + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", "dev": true, - "optional": true + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } }, - "astw": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz", - "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=", + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", "dev": true, "requires": { - "acorn": "^4.0.3" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" } }, - "async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", - "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", "dev": true, "requires": { - "lodash": "^4.17.10" + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" } }, - "async-done": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", - "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==", + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^1.0.7", - "stream-exhaust": "^1.0.1" - }, - "dependencies": { - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - } + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" } }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", - "dev": true - }, - "async-limiter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", - "dev": true + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } }, - "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha1-7vAUoxRa5Hehy8AM0eVSM23Ot5A=", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, - "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", - "dev": true, - "optional": true - }, - "axios": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", - "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "dev": true, - "optional": true, "requires": { - "follow-redirects": "1.0.0" - }, - "dependencies": { - "follow-redirects": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", - "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", - "dev": true, - "optional": true, - "requires": { - "debug": "^2.2.0" - } - } + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "abab": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" - } + "optional": true }, - "babel-core": { - "version": "6.26.3", - "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz", - "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==", - "dev": true, - "requires": { - "babel-code-frame": "^6.26.0", - "babel-generator": "^6.26.0", - "babel-helpers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-register": "^6.26.0", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "convert-source-map": "^1.5.1", - "debug": "^2.6.9", - "json5": "^0.5.1", - "lodash": "^4.17.4", - "minimatch": "^3.0.4", - "path-is-absolute": "^1.0.1", - "private": "^0.1.8", - "slash": "^1.0.0", - "source-map": "^0.5.7" - } + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true }, - "babel-generator": { - "version": "6.26.1", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", - "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", "dev": true, "requires": { - "babel-messages": "^6.23.0", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "detect-indent": "^4.0.0", - "jsesc": "^1.3.0", - "lodash": "^4.17.4", - "source-map": "^0.5.7", - "trim-right": "^1.0.1" + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + } } }, - "babel-helper-builder-binary-assignment-operator-visitor": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", - "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", - "dev": true, - "requires": { - "babel-helper-explode-assignable-expression": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "acorn": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz", + "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==", + "dev": true + }, + "acorn-dynamic-import": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==", + "dev": true }, - "babel-helper-call-delegate": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", - "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "acorn-globals": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz", + "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=", "dev": true, + "optional": true, "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "acorn": "^2.1.0" + }, + "dependencies": { + "acorn": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz", + "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc=", + "dev": true, + "optional": true + } } }, - "babel-helper-define-map": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", - "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "acorn-jsx": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", + "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "dev": true + }, + "acorn-node": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.6.2.tgz", + "integrity": "sha512-rIhNEZuNI8ibQcL7ANm/mGyPukIaZsRNX9psFNQURyJW0nu6k8wjSDld20z6v2mDBWqX13pIEnk9gGZJHIlEXg==", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "acorn": "^6.0.2", + "acorn-dynamic-import": "^4.0.0", + "acorn-walk": "^6.1.0", + "xtend": "^4.0.1" } }, - "babel-helper-explode-assignable-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", - "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "acorn-walk": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", + "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, - "babel-helper-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", - "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha1-Y3S03V1HGP884npnGjscrQdxMqk=", "dev": true, "requires": { - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "ansi-wrap": "^0.1.0" } }, - "babel-helper-get-function-arity": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", - "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "ansi-wrap": "0.1.0" } }, - "babel-helper-hoist-variables": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", - "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "ansi-wrap": "0.1.0" } }, - "babel-helper-optimise-call-expression": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", - "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "ansi-wrap": "0.1.0" } }, - "babel-helper-regex": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", - "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" } }, - "babel-helper-remap-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", - "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", "dev": true, "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "buffer-equal": "^1.0.0" } }, - "babel-helper-replace-supers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", - "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=", + "dev": true + }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", "dev": true, "requires": { - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "file-type": "^4.2.0" } }, - "babel-helpers": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", - "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "sprintf-js": "~1.0.2" } }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "make-iterator": "^1.0.0" } }, - "babel-plugin-check-es2015-constants": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", - "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", + "dev": true + }, + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "make-iterator": "^1.0.0" } }, - "babel-plugin-syntax-async-functions": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", - "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "babel-plugin-syntax-exponentiation-operator": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", - "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", "dev": true }, - "babel-plugin-syntax-trailing-function-commas": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", - "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", "dev": true }, - "babel-plugin-transform-async-to-generator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", - "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", - "dev": true, - "requires": { - "babel-helper-remap-async-to-generator": "^6.24.1", - "babel-plugin-syntax-async-functions": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true }, - "babel-plugin-transform-es2015-arrow-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", - "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "define-properties": "^1.1.2", + "es-abstract": "^1.7.0" } }, - "babel-plugin-transform-es2015-block-scoped-functions": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", - "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "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 + } } }, - "babel-plugin-transform-es2015-block-scoping": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", - "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", "dev": true, "requires": { - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "lodash": "^4.17.4" + "is-number": "^4.0.0" + }, + "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 + } } }, - "babel-plugin-transform-es2015-classes": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", - "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", - "dev": true, - "requires": { - "babel-helper-define-map": "^6.24.1", - "babel-helper-function-name": "^6.24.1", - "babel-helper-optimise-call-expression": "^6.24.1", - "babel-helper-replace-supers": "^6.24.1", - "babel-messages": "^6.23.0", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" - } + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true }, - "babel-plugin-transform-es2015-computed-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", - "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true }, - "babel-plugin-transform-es2015-destructuring": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", - "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", + "dev": true }, - "babel-plugin-transform-es2015-duplicate-keys": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", - "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } } }, - "babel-plugin-transform-es2015-for-of": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", - "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "array-uniq": "^1.0.1" } }, - "babel-plugin-transform-es2015-function-name": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", - "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", - "dev": true, - "requires": { - "babel-helper-function-name": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true }, - "babel-plugin-transform-es2015-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", - "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha1-ucK/WAXx5kqt7tbfOiv6+1pz9aA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" } }, - "babel-plugin-transform-es2015-modules-amd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", - "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", "dev": true, "requires": { - "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } } }, - "babel-plugin-transform-es2015-modules-commonjs": { - "version": "6.26.2", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", - "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", - "dev": true, - "requires": { - "babel-plugin-transform-strict-mode": "^6.24.1", - "babel-runtime": "^6.26.0", - "babel-template": "^6.26.0", - "babel-types": "^6.26.0" - } + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true }, - "babel-plugin-transform-es2015-modules-systemjs": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", - "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", - "dev": true, - "requires": { - "babel-helper-hoist-variables": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true }, - "babel-plugin-transform-es2015-modules-umd": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", - "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", - "dev": true, - "requires": { - "babel-plugin-transform-es2015-modules-amd": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1" - } + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true }, - "babel-plugin-transform-es2015-object-super": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", - "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", - "dev": true, - "requires": { - "babel-helper-replace-supers": "^6.24.1", - "babel-runtime": "^6.22.0" - } + "async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.0.0.tgz", + "integrity": "sha512-LNZ6JSpKraIia6VZKKbKxmX6nWIdfsG7WqrOvKpCuDjH7BnGyQRFMTSXEe8to2WF/rqoAKgZvj+L5nnxe0suAg==", + "dev": true }, - "babel-plugin-transform-es2015-parameters": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", - "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "async-done": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", + "integrity": "sha1-FLe3Nme4ZMjwK1slP8nG7dt3fz4=", "dev": true, "requires": { - "babel-helper-call-delegate": "^6.24.1", - "babel-helper-get-function-arity": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-template": "^6.24.1", - "babel-traverse": "^6.24.1", - "babel-types": "^6.24.1" + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^1.0.7", + "stream-exhaust": "^1.0.1" + }, + "dependencies": { + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + } } }, - "babel-plugin-transform-es2015-shorthand-properties": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", - "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true }, - "babel-plugin-transform-es2015-spread": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", - "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "async-limiter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", + "integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=", + "dev": true }, - "babel-plugin-transform-es2015-sticky-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", - "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", "dev": true, "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" + "async-done": "^1.2.2" } }, - "babel-plugin-transform-es2015-template-literals": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", - "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, - "babel-plugin-transform-es2015-typeof-symbol": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", - "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", - "dev": true, - "requires": { - "babel-runtime": "^6.22.0" - } + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true }, - "babel-plugin-transform-es2015-unicode-regex": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", - "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", - "dev": true, - "requires": { - "babel-helper-regex": "^6.24.1", - "babel-runtime": "^6.22.0", - "regexpu-core": "^2.0.0" - } + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, - "babel-plugin-transform-exponentiation-operator": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", - "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "aws4": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", "dev": true, - "requires": { - "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", - "babel-plugin-syntax-exponentiation-operator": "^6.8.0", - "babel-runtime": "^6.22.0" - } + "optional": true }, - "babel-plugin-transform-regenerator": { + "babel-code-frame": { "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", - "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { - "regenerator-transform": "^0.10.0" + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" } }, - "babel-plugin-transform-runtime": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz", - "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=", + "babel-eslint": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz", + "integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==", "dev": true, "requires": { - "babel-runtime": "^6.22.0" + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.0.0", + "@babel/traverse": "^7.0.0", + "@babel/types": "^7.0.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "^1.0.0" } }, - "babel-plugin-transform-strict-mode": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", - "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha1-GERAjTuPDTWkBOp6wYDwh6YBvZA=", "dev": true, "requires": { - "babel-runtime": "^6.22.0", - "babel-types": "^6.24.1" - } - }, - "babel-preset-env": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", - "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", - "dev": true, - "requires": { - "babel-plugin-check-es2015-constants": "^6.22.0", - "babel-plugin-syntax-trailing-function-commas": "^6.22.0", - "babel-plugin-transform-async-to-generator": "^6.22.0", - "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", - "babel-plugin-transform-es2015-block-scoping": "^6.23.0", - "babel-plugin-transform-es2015-classes": "^6.23.0", - "babel-plugin-transform-es2015-computed-properties": "^6.22.0", - "babel-plugin-transform-es2015-destructuring": "^6.23.0", - "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", - "babel-plugin-transform-es2015-for-of": "^6.23.0", - "babel-plugin-transform-es2015-function-name": "^6.22.0", - "babel-plugin-transform-es2015-literals": "^6.22.0", - "babel-plugin-transform-es2015-modules-amd": "^6.22.0", - "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", - "babel-plugin-transform-es2015-modules-umd": "^6.23.0", - "babel-plugin-transform-es2015-object-super": "^6.22.0", - "babel-plugin-transform-es2015-parameters": "^6.23.0", - "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", - "babel-plugin-transform-es2015-spread": "^6.22.0", - "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", - "babel-plugin-transform-es2015-template-literals": "^6.22.0", - "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", - "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", - "babel-plugin-transform-exponentiation-operator": "^6.22.0", - "babel-plugin-transform-regenerator": "^6.22.0", - "browserslist": "^3.2.6", - "invariant": "^2.2.2", - "semver": "^5.3.0" + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "detect-indent": "^4.0.0", + "jsesc": "^1.3.0", + "lodash": "^4.17.4", + "source-map": "^0.5.7", + "trim-right": "^1.0.1" } }, - "babel-register": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", - "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { - "babel-core": "^6.26.0", - "babel-runtime": "^6.26.0", - "core-js": "^2.5.0", - "home-or-tmp": "^2.0.0", - "lodash": "^4.17.4", - "mkdirp": "^0.5.1", - "source-map-support": "^0.4.15" + "babel-runtime": "^6.22.0" } }, "babel-runtime": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, "requires": { "core-js": "^2.4.0", "regenerator-runtime": "^0.11.0" } }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "dev": true, - "requires": { - "babel-runtime": "^6.26.0", - "babel-traverse": "^6.26.0", - "babel-types": "^6.26.0", - "babylon": "^6.18.0", - "lodash": "^4.17.4" - } - }, "babel-traverse": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", @@ -1377,21 +1934,34 @@ } }, "babelify": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", - "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", - "dev": true, - "requires": { - "babel-core": "^6.0.14", - "object-assign": "^4.0.0" - } + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-10.0.0.tgz", + "integrity": "sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==", + "dev": true }, "babylon": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=", "dev": true }, + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -1407,7 +1977,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -1431,7 +2001,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1440,7 +2010,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -1449,7 +2019,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -1468,7 +2038,7 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "integrity": "sha1-yrHmEY8FEJXli1KBrqjBzSK/wOM=", "dev": true }, "base64id": { @@ -1503,37 +2073,27 @@ } }, "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true }, "binary-extensions": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", "dev": true }, "binaryextensions": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-1.0.1.tgz", - "integrity": "sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.2.tgz", + "integrity": "sha512-xVNN69YGDghOqCCtA6FI7avYrr02mTJjOgB0/f1VPD3pJC8QEvjTKWc4epDx8AqxxA75NI0QpVM2gPJXUbE4Tg==", "dev": true }, - "bitsyntax": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", - "integrity": "sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI=", - "dev": true, - "optional": true, - "requires": { - "buffer-more-ints": "0.0.2" - } - }, "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "dev": true, "requires": { "readable-stream": "^2.3.5", @@ -1541,39 +2101,47 @@ } }, "blob": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", "dev": true }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", + "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==", "dev": true }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=", "dev": true }, "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "dev": true, "requires": { - "bytes": "3.0.0", + "bytes": "3.1.0", "content-type": "~1.0.4", "debug": "2.6.9", "depd": "~1.1.2", - "http-errors": "~1.6.3", - "iconv-lite": "0.4.23", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "on-finished": "~2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "~1.6.16" + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + } } }, "boolbase": { @@ -1582,19 +2150,16 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, - "boom": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", - "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", - "dev": true, - "requires": { - "hoek": "2.x.x" - } + "boolify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/boolify/-/boolify-1.0.1.tgz", + "integrity": "sha1-tcCeF8rNET0Rt7s+04TMASmU2Gs=", + "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==", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -1604,7 +2169,7 @@ "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", "dev": true, "requires": { "arr-flatten": "^1.1.0", @@ -1639,7 +2204,7 @@ "browser-pack": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", - "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "integrity": "sha1-w0uhDQuc4WK1ryJ8cTHJLC7NV3Q=", "dev": true, "requires": { "JSONStream": "^1.0.3", @@ -1651,9 +2216,9 @@ } }, "browser-resolve": { - "version": "1.11.2", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz", - "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=", + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", "dev": true, "requires": { "resolve": "1.1.7" @@ -1668,36 +2233,37 @@ } }, "browserify": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/browserify/-/browserify-13.3.0.tgz", - "integrity": "sha1-tanJAgJD8McORnW+yCI7xifkFc4=", + "version": "16.2.3", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-16.2.3.tgz", + "integrity": "sha512-zQt/Gd1+W+IY+h/xX2NYMW4orQWhqSwyV+xsblycTtpOuB27h1fZhhNQuipJ4t79ohw4P4mMem0jp/ZkISQtjQ==", "dev": true, "requires": { "JSONStream": "^1.0.3", "assert": "^1.4.0", "browser-pack": "^6.0.1", "browser-resolve": "^1.11.0", - "browserify-zlib": "~0.1.2", - "buffer": "^4.1.0", + "browserify-zlib": "~0.2.0", + "buffer": "^5.0.2", "cached-path-relative": "^1.0.0", - "concat-stream": "~1.5.1", + "concat-stream": "^1.6.0", "console-browserify": "^1.1.0", "constants-browserify": "~1.0.0", "crypto-browserify": "^3.0.0", "defined": "^1.0.0", "deps-sort": "^2.0.0", - "domain-browser": "~1.1.0", + "domain-browser": "^1.2.0", "duplexer2": "~0.1.2", - "events": "~1.1.0", + "events": "^2.0.0", "glob": "^7.1.0", "has": "^1.0.0", "htmlescape": "^1.1.0", - "https-browserify": "~0.0.0", + "https-browserify": "^1.0.0", "inherits": "~2.0.1", "insert-module-globals": "^7.0.0", "labeled-stream-splicer": "^2.0.0", - "module-deps": "^4.0.8", - "os-browserify": "~0.1.1", + "mkdirp": "^0.5.0", + "module-deps": "^6.0.0", + "os-browserify": "~0.3.0", "parents": "^1.0.1", "path-browserify": "~0.0.0", "process": "~0.11.0", @@ -1710,15 +2276,15 @@ "shell-quote": "^1.6.1", "stream-browserify": "^2.0.0", "stream-http": "^2.0.0", - "string_decoder": "~0.10.0", + "string_decoder": "^1.1.1", "subarg": "^1.0.0", "syntax-error": "^1.1.1", "through2": "^2.0.0", "timers-browserify": "^1.0.1", - "tty-browserify": "~0.0.0", + "tty-browserify": "0.0.1", "url": "~0.11.0", "util": "~0.10.1", - "vm-browserify": "~0.0.1", + "vm-browserify": "^1.0.0", "xtend": "^4.0.0" }, "dependencies": { @@ -1727,13 +2293,22 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true + }, + "string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } } } }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "integrity": "sha1-Mmc0ZC9APavDADIJhTu3CtQo70g=", "dev": true, "requires": { "buffer-xor": "^1.0.3", @@ -1747,7 +2322,7 @@ "browserify-cipher": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", - "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "integrity": "sha1-jWR0wbhwv9q807z8wZNKEOlPFfA=", "dev": true, "requires": { "browserify-aes": "^1.0.4", @@ -1756,14 +2331,15 @@ } }, "browserify-des": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", - "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "browserify-rsa": { @@ -1802,49 +2378,38 @@ } }, "browserify-zlib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", - "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", - "dev": true, - "requires": { - "pako": "~0.2.0" - } - }, - "browserslist": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", - "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30000844", - "electron-to-chromium": "^1.3.47" + "pako": "~1.0.5" } }, "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "dev": true, "requires": { "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "ieee754": "^1.1.4" } }, "buffer-alloc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", - "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "dev": true, "requires": { - "buffer-alloc-unsafe": "^0.1.0", - "buffer-fill": "^0.1.0" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, "buffer-alloc-unsafe": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz", - "integrity": "sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", "dev": true }, "buffer-crc32": { @@ -1853,60 +2418,29 @@ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", "dev": true }, - "buffer-fill": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-0.1.1.tgz", - "integrity": "sha512-YgBMBzdRLEfgxJIGu2wrvI2E03tMCFU1p7d1KhB4BOoMN0VxmTFjSyN5JtKt9z8Z9JajMHruI6SE25W96wNv7Q==", - "dev": true - }, - "buffer-from": { + "buffer-equal": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", - "dev": true - }, - "buffer-more-ints": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", - "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", "dev": true }, - "buffer-shims": { + "buffer-fill": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", - "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", "dev": true }, - "buffer-to-vinyl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-to-vinyl/-/buffer-to-vinyl-1.1.0.tgz", - "integrity": "sha1-APFfruOreh3aLN5tkSG//dB7ImI=", - "dev": true, - "requires": { - "file-type": "^3.1.0", - "readable-stream": "^2.0.2", - "uuid": "^2.0.1", - "vinyl": "^1.0.0" - }, - "dependencies": { - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", - "dev": true - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "dev": true }, "buffer-xor": { "version": "1.0.3", @@ -1914,37 +2448,6 @@ "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", "dev": true }, - "buildmail": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", - "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", - "dev": true, - "optional": true, - "requires": { - "addressparser": "1.0.1", - "libbase64": "0.1.0", - "libmime": "3.0.0", - "libqp": "1.1.0", - "nodemailer-fetch": "1.6.0", - "nodemailer-shared": "1.1.0", - "punycode": "1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true, - "optional": true - } - } - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", @@ -1952,48 +2455,66 @@ "dev": true }, "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", "dev": true }, "cacache": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", - "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", - "dev": true, - "requires": { - "bluebird": "^3.5.1", - "chownr": "^1.0.1", - "glob": "^7.1.2", - "graceful-fs": "^4.1.11", - "lru-cache": "^4.1.1", - "mississippi": "^2.0.0", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-11.3.2.tgz", + "integrity": "sha512-E0zP4EPGDOaT2chM08Als91eYnf8Z+eH1awwwVsngUmgppfM5jjJ8l3z5vO5p5w/I3LsiXawb1sW0VY65pQABg==", + "dev": true, + "requires": { + "bluebird": "^3.5.3", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", "mkdirp": "^0.5.1", "move-concurrently": "^1.0.1", "promise-inflight": "^1.0.1", "rimraf": "^2.6.2", - "ssri": "^5.2.4", - "unique-filename": "^1.1.0", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", "y18n": "^4.0.0" }, "dependencies": { + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" + "yallist": "^3.0.2" } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true } } }, "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -2008,55 +2529,80 @@ } }, "cached-path-relative": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", - "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.2.tgz", + "integrity": "sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg==", "dev": true }, + "caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "requires": { + "callsites": "^2.0.0" + }, + "dependencies": { + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + } + } + }, + "caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "requires": { + "caller-callsite": "^2.0.0" + } + }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", "dev": true }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", "dev": true }, "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz", + "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=", "dev": true, "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "^4.1.0", + "map-obj": "^2.0.0", + "quick-lru": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } } }, - "caniuse-lite": { - "version": "1.0.30000846", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000846.tgz", - "integrity": "sha512-qxUOHr5mTaadWH1ap0ueivHd8x42Bnemcn+JutVr7GWmm2bU4zoBhjuv5QdXgALQnnT626lOQros7cCDf8PwCg==", - "dev": true - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", @@ -2070,6 +2616,12 @@ "supports-color": "^2.0.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, "cheerio": { "version": "1.0.0-rc.2", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", @@ -2085,67 +2637,58 @@ } }, "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", + "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", "dev": true, "requires": { - "anymatch": "^1.3.0", - "async-each": "^1.0.0", - "fsevents": "^1.0.0", - "glob-parent": "^2.0.0", - "inherits": "^2.0.1", + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", "is-binary-path": "^1.0.0", - "is-glob": "^2.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0" + "readdirp": "^2.2.1", + "upath": "^1.1.1" }, "dependencies": { - "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" - } - }, - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "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" - } } } }, "chownr": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", - "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "integrity": "sha1-VHJri4//TfBTxCGH6AH7RBLfFJQ=", "dev": true }, "chrome-trace-event": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.0.tgz", - "integrity": "sha512-xDbVgyfDTT2piup/h8dK/y4QZfJRSa73bw1WZ8b4XM1o7fsFubUVGYcE+1ANtOzJJELGpYoG2961z0Z6OAld9A==", + "integrity": "sha1-Rakb0sIMlBHwljtarrmhuV4JzEg=", "dev": true, "requires": { "tslib": "^1.9.0" } }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -2153,15 +2696,15 @@ } }, "circular-json": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.5.tgz", - "integrity": "sha512-13YaR6kiz0kBNmIVM87Io8Hp7bWOo4r61vkEANy8iH9R9bc6avud/1FT0SBpqR1RpIQADOh/Q+yHZDA1iL6ysA==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", "dev": true }, "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -2181,22 +2724,95 @@ } } }, - "cliui": { + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-spinners": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.1.0.tgz", + "integrity": "sha512-8B00fJOEh1HPrx4fo5eW16XmE1PcL1tGpGrxy63CXGP9nHdPBN63X75hA1zhvQuhVztJWLqV58Roj2qlNM7cAA==", + "dev": true + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", "dev": true, "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" }, "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } } } }, @@ -2206,18 +2822,52 @@ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", "dev": true }, + "cloneable-readable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", + "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -2229,12 +2879,12 @@ } }, "color-convert": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", - "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-name": "^1.1.1" + "color-name": "1.1.3" } }, "color-logger": { @@ -2252,7 +2902,7 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", "dev": true }, "colors": { @@ -2261,15 +2911,6 @@ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, - "combine-lists": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", - "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", - "dev": true, - "requires": { - "lodash": "^4.5.0" - } - }, "combine-source-map": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", @@ -2308,6 +2949,12 @@ "graceful-readlink": ">= 1.0.0" } }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -2321,9 +2968,9 @@ "dev": true }, "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", "dev": true }, "component-inherit": { @@ -2339,47 +2986,26 @@ "dev": true }, "concat-stream": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", - "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "inherits": "~2.0.1", - "readable-stream": "~2.0.0", - "typedarray": "~0.0.5" - }, - "dependencies": { - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" - } - } + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" } }, "connect": { - "version": "3.6.6", - "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", - "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "requires": { "debug": "2.6.9", - "finalhandler": "1.1.0", - "parseurl": "~1.3.2", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", "utils-merge": "1.0.1" } }, @@ -2398,17 +3024,26 @@ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", "dev": true }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=", "dev": true }, "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } }, "cookie": { "version": "0.3.1", @@ -2419,7 +3054,7 @@ "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=", "dev": true, "requires": { "aproba": "^1.1.1", @@ -2436,10 +3071,63 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "dev": true, + "requires": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "dev": true + }, + "core-js-compat": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.1.0.tgz", + "integrity": "sha512-v8M7YAMacMOJ4T4Z9QSud3dFYASMDvK9d2RWBHRSJlO4nGboLQVtFdbDmgzxfM7XrvcvO56L0sHcqGjuk/4wTQ==", + "dev": true, + "requires": { + "browserslist": "^4.6.0", + "core-js-pure": "3.1.0", + "semver": "^6.0.0" + }, + "dependencies": { + "browserslist": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.0.tgz", + "integrity": "sha512-Jk0YFwXBuMOOol8n6FhgkDzn3mY9PYLYGk29zybF05SbRTsMgPqmTNeQQhOghCxq5oFqAXE3u4sYddr4C0uRhg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000967", + "electron-to-chromium": "^1.3.133", + "node-releases": "^1.1.19" + } + }, + "caniuse-lite": { + "version": "1.0.30000969", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000969.tgz", + "integrity": "sha512-Kus0yxkoAJgVc0bax7S4gLSlFifCa7MnSZL9p9VuS/HIKEL4seaqh28KIQAAO50cD/rJ5CiJkJFapkdDAlhFxQ==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.3.135", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.135.tgz", + "integrity": "sha512-xXLNstRdVsisPF3pL3H9TVZo2XkMILfqtD6RiWIUmDK2sFX1Bjwqmd8LBp0Kuo2FgKO63JXPoEVGm8WyYdwP0Q==", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.1.0.tgz", + "integrity": "sha512-9NxJBUp8p35vrBbEhQl+FvKbYY68fELWld0asAXMnfWl9xRrN472mw/n+ZvmnG0fYh4U7agPcJZ7iqcJW5R9Rg==", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -2447,10 +3135,50 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "requires": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "dependencies": { + "import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "requires": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "create-ecdh": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", - "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "integrity": "sha1-yREbbzMEXEaX8UR4f5JUzcd8Rf8=", "dev": true, "requires": { "bn.js": "^4.1.0", @@ -2460,7 +3188,7 @@ "create-hash": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "integrity": "sha1-iJB4rxGmN1a8+1m9IhmWvjqe8ZY=", "dev": true, "requires": { "cipher-base": "^1.0.1", @@ -2473,7 +3201,7 @@ "create-hmac": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "integrity": "sha1-aRcMeLOrlXFHsriwRXLkfq0iQ/8=", "dev": true, "requires": { "cipher-base": "^1.0.3", @@ -2484,20 +3212,31 @@ "sha.js": "^2.4.8" } }, - "cryptiles": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", - "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "optional": true, "requires": { - "boom": "2.x.x" + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, "crypto-browserify": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", - "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "integrity": "sha1-OWz58xN/A+S45TLFj2mCVOAPgOw=", "dev": true, "requires": { "browserify-cipher": "^1.0.0", @@ -2547,15 +3286,6 @@ "cssom": "0.3.x" } }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "dev": true, - "requires": { - "array-find-index": "^1.0.1" - } - }, "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -2568,6 +3298,27 @@ "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", "dev": true }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "dargs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", + "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", + "dev": true + }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -2577,17 +3328,16 @@ "assert-plus": "^1.0.0" } }, - "data-uri-to-buffer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", - "dev": true, - "optional": true + "date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true }, "date-format": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.0.0.tgz", + "integrity": "sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA==", "dev": true }, "date-now": { @@ -2602,16 +3352,10 @@ "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", "dev": true }, - "deap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deap/-/deap-1.0.1.tgz", - "integrity": "sha512-k75KYNZMvwAwes2xIPry/QTffXIchjD8QfABvvfTr80P85jv5ZcKqcoDo+vMe71nNnVnXYe8MA28weyqcf/DKw==", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -2630,479 +3374,165 @@ "dev": true }, "decompress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/decompress/-/decompress-3.0.0.tgz", - "integrity": "sha1-rx3VDQbjv8QyRh033hGzjA2ZG+0=", - "dev": true, - "requires": { - "buffer-to-vinyl": "^1.0.0", - "concat-stream": "^1.4.6", - "decompress-tar": "^3.0.0", - "decompress-tarbz2": "^3.0.0", - "decompress-targz": "^3.0.0", - "decompress-unzip": "^3.0.0", - "stream-combiner2": "^1.1.1", - "vinyl-assign": "^1.0.1", - "vinyl-fs": "^2.2.0" - }, - "dependencies": { - "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" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-stream": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", - "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "glob": "^5.0.3", - "glob-parent": "^3.0.0", - "micromatch": "^2.3.7", - "ordered-read-streams": "^0.3.0", - "through2": "^0.6.0", - "to-absolute-glob": "^0.1.1", - "unique-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, - "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" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.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" - } - }, - "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" - } - }, - "ordered-read-streams": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", - "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", - "dev": true, - "requires": { - "is-stream": "^1.0.1", - "readable-stream": "^2.0.1" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "unique-stream": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", - "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", - "dev": true, - "requires": { - "json-stable-stringify": "^1.0.0", - "through2-filter": "^2.0.0" - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-fs": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", - "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", - "dev": true, - "requires": { - "duplexify": "^3.2.0", - "glob-stream": "^5.3.2", - "graceful-fs": "^4.0.0", - "gulp-sourcemaps": "1.6.0", - "is-valid-glob": "^0.3.0", - "lazystream": "^1.0.0", - "lodash.isequal": "^4.0.0", - "merge-stream": "^1.0.0", - "mkdirp": "^0.5.0", - "object-assign": "^4.0.0", - "readable-stream": "^2.0.4", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^1.0.0", - "through2": "^2.0.0", - "through2-filter": "^2.0.0", - "vali-date": "^1.0.0", - "vinyl": "^1.0.0" - } - } - } - }, - "decompress-tar": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-3.1.0.tgz", - "integrity": "sha1-IXx4n5uURQ76rcXF5TeXj8MzxGY=", - "dev": true, - "requires": { - "is-tar": "^1.0.0", - "object-assign": "^2.0.0", - "strip-dirs": "^1.0.0", - "tar-stream": "^1.1.1", - "through2": "^0.6.1", - "vinyl": "^0.4.3" - }, - "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "dev": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, - "decompress-tarbz2": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-3.1.0.tgz", - "integrity": "sha1-iyOTVoE1X58YnYclag+L3ZbZZm0=", + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", "dev": true, "requires": { - "is-bzip2": "^1.0.0", - "object-assign": "^2.0.0", - "seek-bzip": "^1.0.3", - "strip-dirs": "^1.0.0", - "tar-stream": "^1.1.1", - "through2": "^0.6.1", - "vinyl": "^0.4.3" + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" }, "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } } } }, "decompress-targz": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-3.1.0.tgz", - "integrity": "sha1-ssE9+YFmJomRtxXWRH9kLpaW9aA=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, "requires": { - "is-gzip": "^1.0.0", - "object-assign": "^2.0.0", - "strip-dirs": "^1.0.0", - "tar-stream": "^1.1.1", - "through2": "^0.6.1", - "vinyl": "^0.4.3" + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" }, "dependencies": { - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "object-assign": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", - "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } } } }, "decompress-unzip": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-3.4.0.tgz", - "integrity": "sha1-YUdbQVIGa74/7hL51inRX+ZHjus=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, "requires": { - "is-zip": "^1.0.0", - "read-all-stream": "^3.0.0", - "stat-mode": "^0.2.0", - "strip-dirs": "^1.0.0", - "through2": "^2.0.0", - "vinyl": "^1.0.0", - "yauzl": "^2.2.1" + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" }, "dependencies": { - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", "dev": true, - "optional": true + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true }, "defaults": { "version": "1.0.3", @@ -3113,10 +3543,19 @@ "clone": "^1.0.2" } }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -3126,7 +3565,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3135,7 +3574,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -3144,7 +3583,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -3160,16 +3599,26 @@ "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", "dev": true }, - "degenerator": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", - "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", "dev": true, - "optional": true, "requires": { - "ast-types": "0.x.x", - "escodegen": "1.x.x", - "esprima": "3.x.x" + "globby": "^6.1.0", + "is-path-cwd": "^1.0.0", + "is-path-in-cwd": "^1.0.0", + "p-map": "^1.1.1", + "pify": "^3.0.0", + "rimraf": "^2.2.8" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } } }, "delayed-stream": { @@ -3184,12 +3633,6 @@ "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", "dev": true }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true - }, "deps-sort": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz", @@ -3228,21 +3671,14 @@ } }, "detective": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", - "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", "dev": true, "requires": { - "acorn": "^5.2.1", - "defined": "^1.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", - "dev": true - } + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" } }, "di": { @@ -3254,7 +3690,7 @@ "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", - "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "integrity": "sha1-QOjumPVaIUlgcUaSHGPhrl89KHU=", "dev": true, "requires": { "bn.js": "^4.1.0", @@ -3262,6 +3698,21 @@ "randombytes": "^2.0.0" } }, + "dlv": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.2.tgz", + "integrity": "sha512-xxD4VSH67GbRvSGUrckvha94RD7hjgOH7rqGxiytLpkaeMvixOHFZTGFK6EkIm3T761OVHT8ABHmGkq9gXgu6Q==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", @@ -3293,9 +3744,9 @@ } }, "domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, "domelementtype": { @@ -3307,7 +3758,7 @@ "domhandler": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "integrity": "sha1-iAUJfpM9ZehVRvcm1g9euItE+AM=", "dev": true, "requires": { "domelementtype": "1" @@ -3323,13 +3774,6 @@ "domelementtype": "1" } }, - "double-ended-queue": { - "version": "2.1.0-0", - "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", - "dev": true, - "optional": true - }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -3340,26 +3784,25 @@ } }, "duplexify": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", "dev": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", "readable-stream": "^2.0.0", "stream-shift": "^1.0.0" - }, - "dependencies": { - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - } + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" } }, "ecc-jsbn": { @@ -3378,22 +3821,28 @@ "integrity": "sha1-60Cq+9Bnpup27/+rBke81VCbN7I=", "dev": true }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", "dev": true }, - "electron-to-chromium": { - "version": "1.3.48", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz", - "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA=", + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", "dev": true }, "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", "dev": true, "requires": { "bn.js": "^4.4.0", @@ -3405,6 +3854,12 @@ "minimalistic-crypto-utils": "^1.0.0" } }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", @@ -3418,29 +3873,92 @@ "dev": true }, "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", "dev": true, "requires": { - "once": "~1.3.0" + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" }, "dependencies": { - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "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": { - "wrappy": "1" + "ms": "2.0.0" + } + } + } + }, + "engine.io-client": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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" } } } }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, "enhanced-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", - "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "integrity": "sha1-Qcfgv9/nSsH/4eV61qXGyfN0Kn8=", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -3460,37 +3978,91 @@ "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", "dev": true }, - "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", + "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-keys": "^1.0.12" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "dev": true, "requires": { - "prr": "~1.0.1" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" } }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "es5-ext": { + "version": "0.10.50", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", + "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", "dev": true, "requires": { - "is-arrayish": "^0.2.1" + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" } }, - "es6-promise": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", - "dev": true + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", "dev": true, "requires": { - "es6-promise": "^4.0.3" + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" } }, "escape-html": { @@ -3522,7 +4094,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true, "optional": true } @@ -3531,7 +4103,7 @@ "esdoc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/esdoc/-/esdoc-1.1.0.tgz", - "integrity": "sha512-vsUcp52XJkOWg9m1vDYplGZN2iDzvmjDL5M/Mp8qkoDG3p2s0yIQCIjKR5wfPBaM3eV14a6zhQNYiNTCVzPnxA==", + "integrity": "sha1-B9QOv3kXZM1TeSnCkRHiCoV2JPM=", "dev": true, "requires": { "babel-generator": "6.26.1", @@ -3550,7 +4122,7 @@ "fs-extra": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", - "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", + "integrity": "sha1-QU0BEM3QZwVzTQVWUsVBEmDDGr0=", "dev": true, "requires": { "graceful-fs": "^4.1.2", @@ -3569,7 +4141,7 @@ "esdoc-brand-plugin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/esdoc-brand-plugin/-/esdoc-brand-plugin-1.0.1.tgz", - "integrity": "sha512-Yv9j3M7qk5PSLmSeD6MbPsfIsEf8K43EdH8qZpE/GZwnJCRVmDPrZJ1cLDj/fPu6P35YqgcEaJK4E2NL/CKA7g==", + "integrity": "sha1-fA4a6Q6EwwstM2nTpkSfncn41RE=", "dev": true, "requires": { "cheerio": "0.22.0" @@ -3614,12 +4186,34 @@ "dev": true, "requires": { "fs-extra": "1.0.0" + }, + "dependencies": { + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + } } }, "esdoc-importpath-plugin": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/esdoc-importpath-plugin/-/esdoc-importpath-plugin-1.0.2.tgz", - "integrity": "sha512-o9/EIk8YyufjzDBrTZu7/6he2No515b51Nnd8QGzXvdTM+rekQjZ7wxVjcqTUQ68bbYLFKqaxZBNltYUbD5aUQ==", + "integrity": "sha1-UpzPLIQCNSYNAalQJKVzHvYnR3U=", "dev": true }, "esdoc-integrate-manual-plugin": { @@ -3637,13 +4231,13 @@ "esdoc-lint-plugin": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/esdoc-lint-plugin/-/esdoc-lint-plugin-1.0.2.tgz", - "integrity": "sha512-24AYqD2WbZI9We02I7/6dzAa7yUliRTFUaJCZAcYJMQicJT5gUrNFVaI8XmWEN/mhF3szIn1uZBNWeLul4CmNw==", + "integrity": "sha1-SWKTDG3Fsl2Az27/Gw88JGCQd/c=", "dev": true }, "esdoc-publish-html-plugin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/esdoc-publish-html-plugin/-/esdoc-publish-html-plugin-1.1.2.tgz", - "integrity": "sha512-hG1fZmTcEp3P/Hv/qKiMdG1qSp8MjnVZMMkxL5P5ry7I2sX0HQ4P9lt2lms+90Lt0r340HHhSuVx107UL7dphg==", + "integrity": "sha1-veznvHoKPkGZM1AyUtt6Z3KHnas=", "dev": true, "requires": { "babel-generator": "6.11.4", @@ -3655,129 +4249,494 @@ "taffydb": "2.7.2" }, "dependencies": { - "babel-generator": { - "version": "6.11.4", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.4.tgz", - "integrity": "sha1-FPaTOrsgxiZm0n47e59bncBxKpo=", + "babel-generator": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.4.tgz", + "integrity": "sha1-FPaTOrsgxiZm0n47e59bncBxKpo=", + "dev": true, + "requires": { + "babel-messages": "^6.8.0", + "babel-runtime": "^6.9.0", + "babel-types": "^6.10.2", + "detect-indent": "^3.0.1", + "lodash": "^4.2.0", + "source-map": "^0.5.0" + } + }, + "cheerio": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "dev": true, + "requires": { + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" + } + }, + "detect-indent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", + "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "minimist": "^1.1.0", + "repeating": "^1.1.0" + } + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0" + } + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "repeating": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", + "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "taffydb": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.2.tgz", + "integrity": "sha1-e/gQalwaSCUbPjvAoOFzJIn9Dcg=", + "dev": true + } + } + }, + "esdoc-standard-plugin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esdoc-standard-plugin/-/esdoc-standard-plugin-1.0.0.tgz", + "integrity": "sha1-ZhIBysfvhokkkCRG/awVJyU8XU0=", + "dev": true, + "requires": { + "esdoc-accessor-plugin": "^1.0.0", + "esdoc-brand-plugin": "^1.0.0", + "esdoc-coverage-plugin": "^1.0.0", + "esdoc-external-ecmascript-plugin": "^1.0.0", + "esdoc-integrate-manual-plugin": "^1.0.0", + "esdoc-integrate-test-plugin": "^1.0.0", + "esdoc-lint-plugin": "^1.0.0", + "esdoc-publish-html-plugin": "^1.0.0", + "esdoc-type-inference-plugin": "^1.0.0", + "esdoc-undocumented-identifier-plugin": "^1.0.0", + "esdoc-unexported-identifier-plugin": "^1.0.0" + } + }, + "esdoc-type-inference-plugin": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/esdoc-type-inference-plugin/-/esdoc-type-inference-plugin-1.0.2.tgz", + "integrity": "sha1-kW4/dW3h2B2cDb4cAI6Nr9Miz68=", + "dev": true + }, + "esdoc-undocumented-identifier-plugin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esdoc-undocumented-identifier-plugin/-/esdoc-undocumented-identifier-plugin-1.0.0.tgz", + "integrity": "sha1-guBdNxwy0ShxFA8dXIHsmf2cwsg=", + "dev": true + }, + "esdoc-unexported-identifier-plugin": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esdoc-unexported-identifier-plugin/-/esdoc-unexported-identifier-plugin-1.0.0.tgz", + "integrity": "sha1-H5h0xqfCvr+a05fDzrdcnGnaurE=", + "dev": true + }, + "eslint": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", + "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.9.1", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^4.0.3", + "eslint-utils": "^1.3.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^5.0.1", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.7.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^6.2.2", + "js-yaml": "^3.13.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^5.5.1", + "strip-ansi": "^4.0.0", + "strip-json-comments": "^2.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "eslint-config-standard": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz", + "integrity": "sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.5.0" + } + }, + "eslint-module-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz", + "integrity": "sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==", + "dev": true, + "requires": { + "debug": "^2.6.8", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "babel-messages": "^6.8.0", - "babel-runtime": "^6.9.0", - "babel-types": "^6.10.2", - "detect-indent": "^3.0.1", - "lodash": "^4.2.0", - "source-map": "^0.5.0" + "locate-path": "^2.0.0" } }, - "cheerio": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", - "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "css-select": "~1.2.0", - "dom-serializer": "~0.1.0", - "entities": "~1.1.1", - "htmlparser2": "^3.9.1", - "lodash.assignin": "^4.0.9", - "lodash.bind": "^4.1.4", - "lodash.defaults": "^4.0.1", - "lodash.filter": "^4.4.0", - "lodash.flatten": "^4.2.0", - "lodash.foreach": "^4.3.0", - "lodash.map": "^4.4.0", - "lodash.merge": "^4.4.0", - "lodash.pick": "^4.2.1", - "lodash.reduce": "^4.4.0", - "lodash.reject": "^4.4.0", - "lodash.some": "^4.4.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" } }, - "detect-indent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz", - "integrity": "sha1-ncXl3bzu+DJXZLlFGwK8bVQIT3U=", + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "get-stdin": "^4.0.1", - "minimist": "^1.1.0", - "repeating": "^1.1.0" + "p-try": "^1.0.0" } }, - "repeating": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", - "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "is-finite": "^1.0.0" + "p-limit": "^1.1.0" } }, - "taffydb": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.2.tgz", - "integrity": "sha1-e/gQalwaSCUbPjvAoOFzJIn9Dcg=", + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } } } }, - "esdoc-standard-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-standard-plugin/-/esdoc-standard-plugin-1.0.0.tgz", - "integrity": "sha1-ZhIBysfvhokkkCRG/awVJyU8XU0=", + "eslint-plugin-es": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-1.4.0.tgz", + "integrity": "sha512-XfFmgFdIUDgvaRAlaXUkxrRg5JSADoRC8IkKLc/cISeR3yHVMefFHQZpcyXXEUUPHfy5DwviBcrfqlyqEwlQVw==", "dev": true, "requires": { - "esdoc-accessor-plugin": "^1.0.0", - "esdoc-brand-plugin": "^1.0.0", - "esdoc-coverage-plugin": "^1.0.0", - "esdoc-external-ecmascript-plugin": "^1.0.0", - "esdoc-integrate-manual-plugin": "^1.0.0", - "esdoc-integrate-test-plugin": "^1.0.0", - "esdoc-lint-plugin": "^1.0.0", - "esdoc-publish-html-plugin": "^1.0.0", - "esdoc-type-inference-plugin": "^1.0.0", - "esdoc-undocumented-identifier-plugin": "^1.0.0", - "esdoc-unexported-identifier-plugin": "^1.0.0" + "eslint-utils": "^1.3.0", + "regexpp": "^2.0.1" } }, - "esdoc-type-inference-plugin": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/esdoc-type-inference-plugin/-/esdoc-type-inference-plugin-1.0.2.tgz", - "integrity": "sha512-tMIcEHNe1uhUGA7lT1UTWc9hs2dzthnTgmqXpmeUhurk7fL2tinvoH+IVvG/sLROzwOGZQS9zW/F9KWnpMzLIQ==", + "eslint-plugin-import": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz", + "integrity": "sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g==", + "dev": true, + "requires": { + "array-includes": "^3.0.3", + "contains-path": "^0.1.0", + "debug": "^2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "^0.3.2", + "eslint-module-utils": "^2.4.0", + "has": "^1.0.3", + "lodash": "^4.17.11", + "minimatch": "^3.0.4", + "read-pkg-up": "^2.0.0", + "resolve": "^1.10.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "isarray": "^1.0.0" + } + } + } + }, + "eslint-plugin-jasmine": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.10.1.tgz", + "integrity": "sha1-VzO3CedR9LxA4x4cFpib0s377Jc=", "dev": true }, - "esdoc-undocumented-identifier-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-undocumented-identifier-plugin/-/esdoc-undocumented-identifier-plugin-1.0.0.tgz", - "integrity": "sha1-guBdNxwy0ShxFA8dXIHsmf2cwsg=", + "eslint-plugin-node": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-9.0.1.tgz", + "integrity": "sha512-fljT5Uyy3lkJzuqhxrYanLSsvaILs9I7CmQ31atTtZ0DoIzRbbvInBh4cQ1CrthFHInHYBQxfPmPt6KLHXNXdw==", + "dev": true, + "requires": { + "eslint-plugin-es": "^1.4.0", + "eslint-utils": "^1.3.1", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.1.tgz", + "integrity": "sha512-DWjnQIFLenVrwyRCKZT+7a7/U4Cqgar4WG8V++K3hw+lrW1hc/SIwdiGmtxKCVACmHULTuGeBbHJmbwW7/sAvA==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.1.1.tgz", + "integrity": "sha512-faAHw7uzlNPy7b45J1guyjazw28M+7gJokKUjC5JSFoYfUEyy6Gw/i7YQvmv2Yk00sUjWcmzXQLpU1Ki/C2IZQ==", "dev": true }, - "esdoc-unexported-identifier-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esdoc-unexported-identifier-plugin/-/esdoc-unexported-identifier-plugin-1.0.0.tgz", - "integrity": "sha1-H5h0xqfCvr+a05fDzrdcnGnaurE=", + "eslint-plugin-standard": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.0.tgz", + "integrity": "sha512-OwxJkR6TQiYMmt1EsNRMe5qG3GsbjlcOhbGUBY4LtavF9DsLaTcoR+j2Tdjqi23oUwKNUqX7qcn5fPStafMdlA==", "dev": true }, "eslint-scope": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz", - "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" } }, + "eslint-utils": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz", + "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", + "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-jsx": "^5.0.0", + "eslint-visitor-keys": "^1.0.0" + } + }, "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true + "dev": true, + "optional": true + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "dev": true, + "requires": { + "estraverse": "^4.0.0" + } }, "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -3796,86 +4755,60 @@ "dev": true }, "eventemitter3": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", "dev": true }, "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", "dev": true }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=", "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" } }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-braces": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", - "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { - "array-slice": "^0.2.3", - "array-unique": "^0.2.1", - "braces": "^0.1.2" + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" }, "dependencies": { - "array-slice": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", - "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 - }, - "braces": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", - "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { - "expand-range": "^0.1.0" + "pump": "^3.0.0" } }, - "expand-range": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", - "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { - "is-number": "^0.1.1", - "repeat-string": "^0.2.2" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } - }, - "is-number": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", - "dev": true - }, - "repeat-string": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", - "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", - "dev": true } } }, @@ -3926,7 +4859,7 @@ "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==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { "is-number": "^2.1.0", @@ -3993,7 +4926,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -4001,10 +4934,32 @@ } } }, + "external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "dependencies": { + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + } + } + }, "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "dev": true, "requires": { "array-unique": "^0.3.2", @@ -4038,7 +4993,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -4047,7 +5002,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -4056,7 +5011,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -4087,7 +5042,7 @@ "acorn": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "integrity": "sha1-Z6ojG/iBKXS4UjWpZ3Hra9B+onk=", "dev": true }, "isarray": { @@ -4105,13 +5060,14 @@ } }, "fancy-log": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", - "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", "dev": true, "requires": { "ansi-gray": "^0.1.1", "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", "time-stamp": "^1.0.0" } }, @@ -4131,30 +5087,46 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true, - "optional": true + "dev": true }, "fd-slicer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", - "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", "dev": true, "requires": { "pend": "~1.2.0" } }, - "file-type": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", - "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", "dev": true }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", "dev": true, - "optional": true + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", + "dev": true }, "filename-regex": { "version": "2.0.1", @@ -4186,71 +5158,62 @@ } }, "finalhandler": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", - "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.1", + "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "on-finished": "~2.3.0", - "parseurl": "~1.3.2", - "statuses": "~1.3.1", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", "unpipe": "~1.0.0" - }, - "dependencies": { - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", - "dev": true - } } }, "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", "dev": true, "requires": { "commondir": "^1.0.1", - "make-dir": "^1.0.0", - "pkg-dir": "^2.0.0" + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" } }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "find-parent-dir": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", + "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", "dev": true }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^3.0.0" } }, "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", "dev": true, "requires": { "detect-file": "^1.0.0", - "is-glob": "^3.1.0", + "is-glob": "^4.0.0", "micromatch": "^3.0.4", "resolve-dir": "^1.0.1" } }, "fined": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz", - "integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", "dev": true, "requires": { "expand-tilde": "^2.0.2", @@ -4261,44 +5224,76 @@ } }, "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", + "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", + "dev": true, + "requires": { + "readable-stream": "^2.0.2" + } }, "flagged-respawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.0.tgz", - "integrity": "sha1-Tnmumy6zi/hrO7Vr8+ClaqX8q9c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.0.tgz", + "integrity": "sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg==", "dev": true }, "flush-write-stream": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", - "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", "dev": true, "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" } }, + "fn-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-2.0.1.tgz", + "integrity": "sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc=", + "dev": true + }, "follow-redirects": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.0.tgz", - "integrity": "sha512-fdrt472/9qQ6Kgjvb935ig6vJCuofpBUD14f9Vb+SLlm7xIe4Qva5gey8EKtv8lp7ahE1wilg3xL1znpVGtZIA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", + "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", "dev": true, "requires": { - "debug": "^3.1.0" + "debug": "^3.2.6" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, @@ -4371,29 +5366,28 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", "dev": true }, "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.0.1.tgz", + "integrity": "sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "jsonfile": "^2.1.0", - "klaw": "^1.0.0" - }, - "dependencies": { - "jsonfile": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", - "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.6" - } - } + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" } }, "fs-write-stream-atomic": { @@ -4415,40 +5409,36 @@ "dev": true }, "fsevents": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz", - "integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", "dev": true, "optional": true, "requires": { - "nan": "^2.9.2", - "node-pre-gyp": "^0.10.0" + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" }, "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "bundled": true, "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "bundled": true, "dev": true }, "aproba": { "version": "1.2.0", - "resolved": false, - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "bundled": true, "dev": true, "optional": true }, "are-we-there-yet": { - "version": "1.1.4", - "resolved": false, - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "version": "1.1.5", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4458,14 +5448,12 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "bundled": true, "dev": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "bundled": true, "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -4473,72 +5461,62 @@ } }, "chownr": { - "version": "1.0.1", - "resolved": false, - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "version": "1.1.1", + "bundled": true, "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "bundled": true, "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": false, - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "bundled": true, "dev": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "bundled": true, "dev": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "bundled": true, "dev": true, "optional": true }, "debug": { - "version": "2.6.9", - "resolved": false, - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "bundled": true, "dev": true, "optional": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "deep-extend": { - "version": "0.5.1", - "resolved": false, - "integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==", + "version": "0.6.0", + "bundled": true, "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "bundled": true, "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bundled": true, "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, - "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4547,15 +5525,13 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "bundled": true, "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4570,9 +5546,8 @@ } }, "glob": { - "version": "7.1.2", - "resolved": false, - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4586,25 +5561,22 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "bundled": true, "dev": true, "optional": true }, "iconv-lite": { - "version": "0.4.21", - "resolved": false, - "integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==", + "version": "0.4.24", + "bundled": true, "dev": true, "optional": true, "requires": { - "safer-buffer": "^2.1.0" + "safer-buffer": ">= 2.1.2 < 3" } }, "ignore-walk": { "version": "3.0.1", - "resolved": false, - "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4613,8 +5585,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4624,21 +5595,18 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "bundled": true, "dev": true }, "ini": { "version": "1.3.5", - "resolved": false, - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "bundled": true, "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "bundled": true, "dev": true, "requires": { "number-is-nan": "^1.0.0" @@ -4646,15 +5614,13 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "bundled": true, "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "bundled": true, "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -4662,24 +5628,21 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "bundled": true, "dev": true }, "minipass": { - "version": "2.2.4", - "resolved": false, - "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", + "version": "2.3.5", + "bundled": true, "dev": true, "requires": { - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.0" } }, "minizlib": { - "version": "1.1.0", - "resolved": false, - "integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==", + "version": "1.2.1", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4688,46 +5651,42 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "bundled": true, "dev": true, "requires": { "minimist": "0.0.8" } }, "ms": { - "version": "2.0.0", - "resolved": false, - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.1", + "bundled": true, "dev": true, "optional": true }, "needle": { - "version": "2.2.0", - "resolved": false, - "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", + "version": "2.3.0", + "bundled": true, "dev": true, "optional": true, "requires": { - "debug": "^2.1.2", + "debug": "^4.1.0", "iconv-lite": "^0.4.4", "sax": "^1.2.4" } }, "node-pre-gyp": { - "version": "0.10.0", - "resolved": false, - "integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==", + "version": "0.12.0", + "bundled": true, "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", "mkdirp": "^0.5.1", - "needle": "^2.2.0", + "needle": "^2.2.1", "nopt": "^4.0.1", "npm-packlist": "^1.1.6", "npmlog": "^4.0.2", - "rc": "^1.1.7", + "rc": "^1.2.7", "rimraf": "^2.6.1", "semver": "^5.3.0", "tar": "^4" @@ -4735,8 +5694,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4745,16 +5703,14 @@ } }, "npm-bundled": { - "version": "1.0.3", - "resolved": false, - "integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==", + "version": "1.0.6", + "bundled": true, "dev": true, "optional": true }, "npm-packlist": { - "version": "1.1.10", - "resolved": false, - "integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==", + "version": "1.4.1", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4764,8 +5720,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4777,21 +5732,18 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "bundled": true, "dev": true }, "object-assign": { "version": "4.1.1", - "resolved": false, - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "bundled": true, "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "bundled": true, "dev": true, "requires": { "wrappy": "1" @@ -4799,22 +5751,19 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "bundled": true, "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "bundled": true, "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4824,26 +5773,23 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "bundled": true, "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "bundled": true, "dev": true, "optional": true }, "rc": { - "version": "1.2.7", - "resolved": false, - "integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==", + "version": "1.2.8", + "bundled": true, "dev": true, "optional": true, "requires": { - "deep-extend": "^0.5.1", + "deep-extend": "^0.6.0", "ini": "~1.3.0", "minimist": "^1.2.0", "strip-json-comments": "~2.0.1" @@ -4851,8 +5797,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": false, - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "bundled": true, "dev": true, "optional": true } @@ -4860,8 +5805,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4875,60 +5819,52 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": false, - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "bundled": true, "dev": true, "optional": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "safe-buffer": { - "version": "5.1.1", - "resolved": false, - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "version": "5.1.2", + "bundled": true, "dev": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "bundled": true, "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "bundled": true, "dev": true, "optional": true }, "semver": { - "version": "5.5.0", - "resolved": false, - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "5.7.0", + "bundled": true, "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "bundled": true, "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "bundled": true, "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "bundled": true, "dev": true, "requires": { "code-point-at": "^1.0.0", @@ -4938,8 +5874,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "bundled": true, "dev": true, "optional": true, "requires": { @@ -4948,8 +5883,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "bundled": true, "dev": true, "requires": { "ansi-regex": "^2.0.0" @@ -4957,122 +5891,92 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "bundled": true, "dev": true, "optional": true }, "tar": { - "version": "4.4.1", - "resolved": false, - "integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==", + "version": "4.4.8", + "bundled": true, "dev": true, "optional": true, "requires": { - "chownr": "^1.0.1", + "chownr": "^1.1.1", "fs-minipass": "^1.2.5", - "minipass": "^2.2.4", - "minizlib": "^1.1.0", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.1", + "safe-buffer": "^5.1.2", "yallist": "^3.0.2" } }, "util-deprecate": { "version": "1.0.2", - "resolved": false, - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "bundled": true, "dev": true, "optional": true }, "wide-align": { - "version": "1.1.2", - "resolved": false, - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "version": "1.1.3", + "bundled": true, "dev": true, "optional": true, "requires": { - "string-width": "^1.0.2" + "string-width": "^1.0.2 || 2" } }, "wrappy": { "version": "1.0.2", - "resolved": false, - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "bundled": true, "dev": true }, "yallist": { - "version": "3.0.2", - "resolved": false, - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", + "version": "3.0.3", + "bundled": true, "dev": true } } }, - "ftp": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", - "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", - "dev": true, - "optional": true, - "requires": { - "readable-stream": "1.1.x", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - } - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "g-status": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/g-status/-/g-status-2.0.2.tgz", + "integrity": "sha512-kQoE9qH+T1AHKgSSD0Hkv98bobE90ILQcXAF4wvGgsr7uFqNvwmh8j+Lq3l0RVt3E3HjSbv2B9biEGcEtpHLCA==", "dev": true, "requires": { - "globule": "~0.1.0" + "arrify": "^1.0.1", + "matcher": "^1.0.0", + "simple-git": "^1.85.0" } }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true, - "optional": true - }, - "generate-object-property": { + "get-assigned-identifiers": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "optional": true, - "requires": { - "is-property": "^1.0.0" - } + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", + "dev": true + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-own-enumerable-property-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz", + "integrity": "sha512-CIJYJC4GGF06TakLg8z4GQKvDsx9EMspVxOYih7LerEL/WosUnFIww45CGfxfeKHqlg3twgUrYRT1O3WQqjGCg==", + "dev": true }, "get-stdin": { "version": "4.0.1", @@ -5080,19 +5984,14 @@ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, - "get-uri": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", - "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==", + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", "dev": true, - "optional": true, "requires": { - "data-uri-to-buffer": "1", - "debug": "2", - "extend": "3", - "file-uri-to-path": "1", - "ftp": "~0.3.10", - "readable-stream": "2" + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" } }, "get-value": { @@ -5111,9 +6010,9 @@ } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -5168,95 +6067,55 @@ "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" }, "dependencies": { - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" + "is-extglob": "^2.1.0" } } } }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", "dev": true, "requires": { - "gaze": "^0.5.1" + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" } }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "glob-watcher": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", + "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", "dev": true, "requires": { - "find-index": "^0.1.1" + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "object.defaults": "^1.1.0" } }, "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -5280,58 +6139,27 @@ "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=", "dev": true }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", "dev": true, "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } } } }, @@ -5357,46 +6185,63 @@ "dev": true }, "gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", "dev": true, "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" }, "dependencies": { - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "dev": true + "gulp-cli": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", + "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.1.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.0.1", + "yargs": "^7.1.0" + } } } }, "gulp-babel": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-6.1.3.tgz", - "integrity": "sha512-tm15R3rt4gO59WXCuqrwf4QXJM9VIJC+0J2NPYSC6xZn+cZRD5y5RPGAiHaDxCJq7Rz5BDljlrk3cEjWADF+wQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz", + "integrity": "sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ==", "dev": true, "requires": { - "babel-core": "^6.23.1", - "object-assign": "^4.0.1", "plugin-error": "^1.0.1", - "replace-ext": "0.0.1", + "replace-ext": "^1.0.0", "through2": "^2.0.0", "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + } } }, "gulp-batch": { @@ -5410,15 +6255,50 @@ } }, "gulp-decompress": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-1.2.0.tgz", - "integrity": "sha1-jutlpeAV+O2FMsr+KEVJYGJvDcc=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/gulp-decompress/-/gulp-decompress-2.0.2.tgz", + "integrity": "sha512-S0ORQYTqksiKMWClGJtjtIgevrTVUbu7KguP74xxXvIiEINS4v7QjjZ8su8hGYPOJ2zW0WGVysgoct4HzINNqQ==", "dev": true, "requires": { - "archive-type": "^3.0.0", - "decompress": "^3.0.0", - "gulp-util": "^3.0.1", - "readable-stream": "^2.0.2" + "archive-type": "^4.0.0", + "decompress": "^4.0.0", + "plugin-error": "^1.0.1", + "readable-stream": "^2.0.2", + "vinyl": "^2.1.0" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + } } }, "gulp-download": { @@ -5578,160 +6458,37 @@ } }, "gulp-file": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/gulp-file/-/gulp-file-0.3.0.tgz", - "integrity": "sha1-6MTXY/Em+zMy/EFuPR70btZ9jQ0=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/gulp-file/-/gulp-file-0.4.0.tgz", + "integrity": "sha1-RRNWoqxQicbbkaBEQlKgVDZXAGs=", "dev": true, "requires": { - "gulp-util": "^2.2.14", - "through2": "^0.4.1" + "through2": "^0.4.1", + "vinyl": "^2.1.0" }, "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", "dev": true }, - "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", "dev": true }, - "chalk": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", - "dev": true, - "requires": { - "ansi-styles": "^1.1.0", - "escape-string-regexp": "^1.0.0", - "has-ansi": "^0.1.0", - "strip-ansi": "^0.3.0", - "supports-color": "^0.2.0" - } - }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - } - }, - "gulp-util": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz", - "integrity": "sha1-1xRuVyiRC9jwR6awseVJvCLb1kw=", - "dev": true, - "requires": { - "chalk": "^0.5.0", - "dateformat": "^1.0.7-1.2.3", - "lodash._reinterpolate": "^2.4.1", - "lodash.template": "^2.4.1", - "minimist": "^0.2.0", - "multipipe": "^0.1.0", - "through2": "^0.5.0", - "vinyl": "^0.2.1" - }, - "dependencies": { - "through2": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz", - "integrity": "sha1-390BLrnHAOIyP9M084rGIqs3Lac=", - "dev": true, - "requires": { - "readable-stream": "~1.0.17", - "xtend": "~3.0.0" - } - } - } - }, - "has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", - "dev": true, - "requires": { - "ansi-regex": "^0.2.0" - } - }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "lodash._reinterpolate": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz", - "integrity": "sha1-TxInqlqHEfxjL1sHofRgequLMiI=", - "dev": true - }, - "lodash.defaults": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz", - "integrity": "sha1-p+iIXwXmiFEUS24SqPNngCa8TFQ=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "lodash.escape": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz", - "integrity": "sha1-LOEsXghNsKV92l5dHu659dF1o7Q=", - "dev": true, - "requires": { - "lodash._escapehtmlchar": "~2.4.1", - "lodash._reunescapedhtml": "~2.4.1", - "lodash.keys": "~2.4.1" - } - }, - "lodash.keys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", - "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - }, - "lodash.template": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz", - "integrity": "sha1-nmEQB+32KRKal0qzxIuBez4c8g0=", - "dev": true, - "requires": { - "lodash._escapestringchar": "~2.4.1", - "lodash._reinterpolate": "~2.4.1", - "lodash.defaults": "~2.4.1", - "lodash.escape": "~2.4.1", - "lodash.keys": "~2.4.1", - "lodash.templatesettings": "~2.4.1", - "lodash.values": "~2.4.1" - } - }, - "lodash.templatesettings": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz", - "integrity": "sha1-6nbHXRHrhtTb6JqDiTu4YZKaxpk=", - "dev": true, - "requires": { - "lodash._reinterpolate": "~2.4.1", - "lodash.escape": "~2.4.1" - } - }, - "minimist": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz", - "integrity": "sha1-Tf/lJdriuGTGbC4jxicdev3s784=", + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", "dev": true }, "readable-stream": { @@ -5746,19 +6503,10 @@ "string_decoder": "~0.10.x" } }, - "strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", - "dev": true, - "requires": { - "ansi-regex": "^0.2.1" - } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, "through2": { @@ -5769,367 +6517,156 @@ "requires": { "readable-stream": "~1.0.17", "xtend": "~2.1.1" - }, - "dependencies": { - "xtend": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", - "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", - "dev": true, - "requires": { - "object-keys": "~0.4.0" - } - } } }, "vinyl": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz", - "integrity": "sha1-vKk4IJWC7FpJrVOKAPofEl5RMlI=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone-stats": "~0.0.1" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } }, "xtend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", - "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "~0.4.0" + } } } }, "gulp-install": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/gulp-install/-/gulp-install-0.6.0.tgz", - "integrity": "sha1-EVQfEfxfehnhjLPvjq255kuOVKo=", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gulp-install/-/gulp-install-1.1.0.tgz", + "integrity": "sha1-k4a0bLRmm0cle2rfTj6i6DySiho=", "dev": true, "requires": { - "gulp-util": "^3.0.4", - "through2": "^2.0.0", - "which": "^1.0.9" + "dargs": "^5.1.0", + "gulp-util": "^3.0.7", + "lodash.groupby": "^4.6.0", + "p-queue": "^1.0.0", + "through2": "^2.0.3", + "which": "^1.2.14" } }, "gulp-jasmine": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/gulp-jasmine/-/gulp-jasmine-2.4.2.tgz", - "integrity": "sha1-Wn9H4nNww2GawKKkQr45lnFAnbM=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/gulp-jasmine/-/gulp-jasmine-4.0.0.tgz", + "integrity": "sha512-0UqY2fA6RCdUDJDsVym3zXYSWmt0AV7YY/6PAeKb+oGTKEgS7zZOH5w/4gcSKs+2FXiWrucQwLDvtEKIDbpF4A==", "dev": true, "requires": { - "arrify": "^1.0.0", - "gulp-util": "^3.0.0", - "jasmine": "^2.3.0", - "jasmine-terminal-reporter": "^1.0.0", - "through2": "^2.0.0" + "arrify": "^1.0.1", + "jasmine": "^3.1.0", + "jasmine-terminal-reporter": "^1.0.3", + "plugin-error": "^1.0.1", + "through2": "^2.0.3" } }, "gulp-replace": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-0.5.4.tgz", - "integrity": "sha1-aaZ5FLvRPFYr/xT1BKQDeWqg2qk=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz", + "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==", "dev": true, "requires": { - "istextorbinary": "1.0.2", + "istextorbinary": "2.2.1", "readable-stream": "^2.0.1", "replacestream": "^4.0.0" } }, - "gulp-sourcemaps": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz", - "integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=", - "dev": true, - "requires": { - "convert-source-map": "^1.1.1", - "graceful-fs": "^4.1.2", - "strip-bom": "^2.0.0", - "through2": "^2.0.0", - "vinyl": "^1.0.0" - }, - "dependencies": { - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } - }, - "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - } - } - }, "gulp-typescript": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-3.2.4.tgz", - "integrity": "sha512-bZosNvbUGzFA4bjjWoUPyjU5vfgJSzlYKkU0Jutbsrj+td8yvtqxethhqfzB9MwyamaUODIuidj5gIytZ523Bw==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.1.tgz", + "integrity": "sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ==", "dev": true, "requires": { - "gulp-util": "~3.0.7", - "source-map": "~0.5.3", - "through2": "~2.0.1", - "vinyl-fs": "~2.4.3" + "ansi-colors": "^3.0.5", + "plugin-error": "^1.0.1", + "source-map": "^0.7.3", + "through2": "^3.0.0", + "vinyl": "^2.1.0", + "vinyl-fs": "^3.0.3" }, "dependencies": { - "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" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", "dev": true }, - "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" - } - }, - "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" - } - }, - "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" - } - }, - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-stream": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz", - "integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "glob": "^5.0.3", - "glob-parent": "^3.0.0", - "micromatch": "^2.3.7", - "ordered-read-streams": "^0.3.0", - "through2": "^0.6.0", - "to-absolute-glob": "^0.1.1", - "unique-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true }, - "is-extglob": { + "clone-stats": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", "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" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "dev": true, - "requires": { - "jsonify": "~0.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" - } - }, - "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" - } - }, - "ordered-read-streams": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz", - "integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=", - "dev": true, - "requires": { - "is-stream": "^1.0.1", - "readable-stream": "^2.0.1" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true }, - "unique-stream": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz", - "integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=", + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", "dev": true, "requires": { - "json-stable-stringify": "^1.0.0", - "through2-filter": "^2.0.0" + "readable-stream": "2 || 3" } }, "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-fs": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz", - "integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "duplexify": "^3.2.0", - "glob-stream": "^5.3.2", - "graceful-fs": "^4.0.0", - "gulp-sourcemaps": "1.6.0", - "is-valid-glob": "^0.3.0", - "lazystream": "^1.0.0", - "lodash.isequal": "^4.0.0", - "merge-stream": "^1.0.0", - "mkdirp": "^0.5.0", - "object-assign": "^4.0.0", - "readable-stream": "^2.0.4", - "strip-bom": "^2.0.0", - "strip-bom-stream": "^1.0.0", - "through2": "^2.0.0", - "through2-filter": "^2.0.0", - "vali-date": "^1.0.0", - "vinyl": "^1.0.0" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } } } }, "gulp-uglify": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-1.5.4.tgz", - "integrity": "sha1-UkeI2HZm0J+dDCH7IXf5ADmmWMk=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz", + "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==", "dev": true, "requires": { - "deap": "^1.0.0", - "fancy-log": "^1.0.0", - "gulp-util": "^3.0.0", - "isobject": "^2.0.0", + "array-each": "^1.0.1", + "extend-shallow": "^3.0.2", + "gulplog": "^1.0.0", + "has-gulplog": "^0.1.0", + "isobject": "^3.0.1", + "make-error-cause": "^1.1.1", + "safe-buffer": "^5.1.2", "through2": "^2.0.0", - "uglify-js": "2.6.4", - "uglify-save-license": "^0.4.1", + "uglify-js": "^3.0.5", "vinyl-sourcemaps-apply": "^0.2.0" - }, - "dependencies": { - "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" - } - } } }, "gulp-util": { @@ -6167,32 +6704,165 @@ } }, "gulp-watch": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-4.3.11.tgz", - "integrity": "sha1-Fi/FY96fx3DpH5p845VVE6mhGMA=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-5.0.1.tgz", + "integrity": "sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog==", "dev": true, "requires": { + "ansi-colors": "1.1.0", "anymatch": "^1.3.0", - "chokidar": "^1.6.1", + "chokidar": "^2.0.0", + "fancy-log": "1.3.2", "glob-parent": "^3.0.1", - "gulp-util": "^3.0.7", "object-assign": "^4.1.0", "path-is-absolute": "^1.0.1", + "plugin-error": "1.0.1", "readable-stream": "^2.2.2", "slash": "^1.0.0", - "vinyl": "^1.2.0", + "vinyl": "^2.1.0", "vinyl-file": "^2.0.0" }, "dependencies": { + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.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" + } + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "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" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "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" + } + }, + "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" + } + }, + "fancy-log": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz", + "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "time-stamp": "^1.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } } } @@ -6224,12 +6894,12 @@ } }, "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "^1.0.2" + "function-bind": "^1.1.1" } }, "has-ansi": { @@ -6244,7 +6914,7 @@ "has-binary2": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=", "dev": true, "requires": { "isarray": "2.0.1" @@ -6279,6 +6949,12 @@ "sparkles": "^1.0.0" } }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, "has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -6322,38 +6998,20 @@ } }, "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "dev": true, "requires": { "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "hawk": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", - "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", - "dev": true, - "optional": true, - "requires": { - "boom": "2.x.x", - "cryptiles": "2.x.x", - "hoek": "2.x.x", - "sntp": "1.x.x" + "minimalistic-assert": "^1.0.1" } }, - "hipchat-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", - "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", - "dev": true, - "optional": true, - "requires": { - "lodash": "^4.0.0", - "request": "^2.0.0" - } + "hat": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/hat/-/hat-0.0.3.tgz", + "integrity": "sha1-uwFKnmSzeIrtgAWRdBPU/z1QLYo=", + "dev": true }, "hmac-drbg": { "version": "1.0.1", @@ -6366,35 +7024,19 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "hoek": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", - "dev": true - }, - "home-or-tmp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", - "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.1" - } - }, "homedir-polyfill": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", - "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", "dev": true, "requires": { "parse-passwd": "^1.0.0" } }, "hosted-git-info": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", - "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "htmlescape": { @@ -6418,21 +7060,22 @@ } }, "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" } }, "http-proxy": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=", "dev": true, "requires": { "eventemitter3": "^3.0.0", @@ -6440,27 +7083,6 @@ "requires-port": "^1.0.0" } }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "dev": true, - "requires": { - "agent-base": "4", - "debug": "3.1.0" - }, - "dependencies": { - "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" - } - } - } - }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -6472,54 +7094,72 @@ "sshpk": "^1.7.0" } }, - "httpntlm": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", - "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", - "dev": true, - "requires": { - "httpreq": ">=0.4.22", - "underscore": "~1.7.0" - }, - "dependencies": { - "underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", - "dev": true - } - } - }, - "httpreq": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", - "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", - "dev": true - }, "https-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", - "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", "dev": true }, - "https-proxy-agent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", - "dev": true, - "requires": { - "agent-base": "^4.1.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "husky": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-2.3.0.tgz", + "integrity": "sha512-A/ZQSEILoq+mQM3yC3RIBSaw1bYXdkKnyyKVSUiJl+iBjVZc5LQEXdGY1ZjrDxC4IzfRPiJ0IqzEQGCN5TQa/A==", + "dev": true, + "requires": { + "cosmiconfig": "^5.2.0", + "execa": "^1.0.0", + "find-up": "^3.0.0", + "get-stdin": "^7.0.0", + "is-ci": "^2.0.0", + "pkg-dir": "^4.1.0", + "please-upgrade-node": "^3.1.1", + "read-pkg": "^5.1.1", + "run-node": "^1.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "ms": "2.0.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "pkg-dir": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.1.0.tgz", + "integrity": "sha512-55k9QN4saZ8q518lE6EFgYiu95u3BWkSajCifhdQjvLvmr8IpnRbhI+UGpWJQfa0KzDguHeeWT1ccO1PmkOi3A==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "read-pkg": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.1.1.tgz", + "integrity": "sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^4.0.0", + "type-fest": "^0.4.1" } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true } } }, @@ -6604,18 +7244,18 @@ } }, "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" } }, "ieee754": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", "dev": true }, "iferr": { @@ -6624,6 +7264,22 @@ "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", "dev": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.0.0.tgz", + "integrity": "sha512-pOnA9tfM3Uwics+SaBLCNyZZZbK+4PTu0OPZtLlMIrv17EdBoC15S9Kn8ckJ9TZTyKb3ywNE5y1yeDxxGA7nTQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -6645,13 +7301,6 @@ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", "dev": true }, - "inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "dev": true, - "optional": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6671,7 +7320,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", "dev": true }, "inline-source-map": { @@ -6683,62 +7332,116 @@ "source-map": "~0.5.3" } }, + "inquirer": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz", + "integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.11", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "insert-module-globals": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.1.0.tgz", - "integrity": "sha512-LbYZdybvKjbbcKLp03lB323Cgc8f0iL0Rjh8U6JZ7K1gZSf7MxQH191iCNUcLX4qIQ6/yWe4Q4ZsQ+opcReNFg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.0.tgz", + "integrity": "sha512-VE6NlW+WGn2/AeOMd496AHFYmE7eLKkUY6Ty31k4og5vmA3Fjuwe9v6ifH6Xx/Hz27QvdoMoviw1/pqWRB09Sw==", "dev": true, "requires": { "JSONStream": "^1.0.3", + "acorn-node": "^1.5.2", "combine-source-map": "^0.8.0", "concat-stream": "^1.6.1", "is-buffer": "^1.1.0", - "lexical-scope": "^1.2.0", "path-is-absolute": "^1.0.1", "process": "~0.11.0", "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", "xtend": "^4.0.0" - }, - "dependencies": { - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - } } }, "interpret": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", "dev": true }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", "dev": true, "requires": { "loose-envify": "^1.0.0" } }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -6783,24 +7486,24 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", "dev": true }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", "dev": true, "requires": { - "builtin-modules": "^1.0.0" + "ci-info": "^2.0.0" } }, - "is-bzip2": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-bzip2/-/is-bzip2-1.0.0.tgz", - "integrity": "sha1-XuWOqlounIDiFAe+3yOuWsCRs/w=", - "dev": true - }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -6821,10 +7524,16 @@ } } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -6835,11 +7544,17 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", "dev": true } } }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", @@ -6876,46 +7591,31 @@ "number-is-nan": "^1.0.0" } }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "^2.1.0" + "is-extglob": "^2.1.1" } }, - "is-gzip": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", - "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=", + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", "dev": true }, - "is-my-ip-valid": { + "is-negated-glob": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", - "dev": true, - "optional": true - }, - "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", - "dev": true, - "optional": true, - "requires": { - "generate-function": "^2.0.0", - "generate-object-property": "^1.1.0", - "is-my-ip-valid": "^1.0.0", - "jsonpointer": "^4.0.0", - "xtend": "^4.0.0" - } - }, - "is-natural-number": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-2.1.1.tgz", - "integrity": "sha1-fUxXKDd+84bD4ZSpkRv1fG3DNec=", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", "dev": true }, "is-number": { @@ -6938,27 +7638,49 @@ } } }, - "is-odd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", - "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", "dev": true, "requires": { - "is-number": "^4.0.0" - }, - "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 - } + "symbol-observable": "^1.1.0" + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "dev": true, + "requires": { + "is-path-inside": "^1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" } }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -6976,33 +7698,56 @@ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "dev": true, - "optional": true + "requires": { + "has": "^1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true }, "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", "dev": true, "requires": { "is-unc-path": "^1.0.0" } }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, - "is-tar": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-tar/-/is-tar-1.0.0.tgz", - "integrity": "sha1-L2suF5LB9bs2UZrKqdZcDSb+hT0=", - "dev": true + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } }, "is-typedarray": { "version": "1.0.0", @@ -7013,7 +7758,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -7026,21 +7771,21 @@ "dev": true }, "is-valid-glob": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-0.3.0.tgz", - "integrity": "sha1-1LVcafUYhvm2XHDWwmItN+KfSP4=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", "dev": true }, "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", "dev": true }, - "is-zip": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-zip/-/is-zip-1.0.0.tgz", - "integrity": "sha1-R7Co/004p2QxzP2ZqOFaTIa6IyU=", + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true }, "isarray": { @@ -7050,10 +7795,13 @@ "dev": true }, "isbinaryfile": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", - "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", - "dev": true + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } }, "isexe": { "version": "2.0.0", @@ -7074,49 +7822,53 @@ "dev": true }, "istextorbinary": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-1.0.2.tgz", - "integrity": "sha1-rOGTVNGpoBc+/rEITOD4ewrX3s8=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", + "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", "dev": true, "requires": { - "binaryextensions": "~1.0.0", - "textextensions": "~1.0.0" + "binaryextensions": "2", + "editions": "^1.3.3", + "textextensions": "2" } }, "jasmine": { - "version": "2.99.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.99.0.tgz", - "integrity": "sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.4.0.tgz", + "integrity": "sha512-sR9b4n+fnBFDEd7VS2el2DeHgKcPiMVn44rtKFumq9q7P/t8WrxsVIZPob4UDdgcDNCwyDqwxCt4k9TDRmjPoQ==", "dev": true, "requires": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.99.0" + "glob": "^7.1.3", + "jasmine-core": "~3.4.0" } }, "jasmine-console-reporter": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jasmine-console-reporter/-/jasmine-console-reporter-2.0.1.tgz", - "integrity": "sha512-Q9pQ18NI+Oz9+kRmvcmM8oDTgiIoAESMRpO/DsyCOwIqktc7onsev6vKLmf3h+UP3AuX7xBB6xlREoV4jMOlzw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine-console-reporter/-/jasmine-console-reporter-3.1.0.tgz", + "integrity": "sha512-fNP6XlgkIyNvfr6JVMJudZL9qWNY2K7l934Ojj4k8J09/QXf4xYf2Mc7MUgcsDhqIb2zTkLd2LsBJWFvJz41/w==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "chalk": "^2.1.0" + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "ci-info": "^1.4.0", + "node-emoji": "^1.8.1", + "ora": "^3.0.0", + "perfy": "^1.1.5" }, "dependencies": { "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==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "^1.9.0" } }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -7124,10 +7876,16 @@ "supports-color": "^5.3.0" } }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { "has-flag": "^3.0.0" @@ -7136,9 +7894,9 @@ } }, "jasmine-core": { - "version": "2.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", - "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.4.0.tgz", + "integrity": "sha512-HU/YxV4i6GcmiH4duATwAbJQMlE0MsDIR5XmSVxURxKHn3aGAdbY1/ZJFmVRbKtnLwIxxMJD7gYaPsypcbYimg==", "dev": true }, "jasmine-terminal-reporter": { @@ -7151,12 +7909,42 @@ "pluralize": "^1.2.1" } }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=", + "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 }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -7213,7 +8001,7 @@ "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "integrity": "sha1-u4Z8+zRQ5pEHwTHRxRS6s9yLyqk=", "dev": true }, "json-schema": { @@ -7237,6 +8025,12 @@ "jsonify": "~0.0.0" } }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -7244,10 +8038,13 @@ "dev": true }, "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } }, "jsonfile": { "version": "4.0.0", @@ -7270,13 +8067,6 @@ "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", "dev": true }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true, - "optional": true - }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -7289,314 +8079,82 @@ "verror": "1.10.0" } }, + "just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, "karma": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.5.tgz", - "integrity": "sha1-NxDHoucbHEOTE/KDhG2I4E5PkYw=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz", + "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==", "dev": true, "requires": { "bluebird": "^3.3.0", "body-parser": "^1.16.1", - "chokidar": "^2.0.3", - "colors": "^1.1.0", - "combine-lists": "^1.0.0", - "connect": "^3.6.0", - "core-js": "^2.2.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.0", - "expand-braces": "^0.1.1", - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "http-proxy": "^1.13.0", - "isbinaryfile": "^3.0.0", - "lodash": "^4.17.4", - "log4js": "^2.5.3", - "mime": "^1.3.4", - "minimatch": "^3.0.2", - "optimist": "^0.6.1", - "qjobs": "^1.1.4", - "range-parser": "^1.2.0", - "rimraf": "^2.6.0", - "safe-buffer": "^5.0.1", - "socket.io": "2.0.4", - "source-map": "^0.6.1", - "tmp": "0.0.33", - "useragent": "2.2.1" - }, - "dependencies": { - "accepts": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", - "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", - "dev": true, - "requires": { - "mime-types": "~2.1.18", - "negotiator": "0.6.1" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", - "dev": true - }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha1-NW/04rDo5D4yLRijckYLvPOszSY=", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" - } - }, - "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" - } - }, - "engine.io": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", - "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "base64id": "1.0.0", - "cookie": "0.3.1", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.0", - "uws": "~9.14.0", - "ws": "~3.3.1" - } - }, - "engine.io-client": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", - "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~3.1.0", - "engine.io-parser": "~2.1.1", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~3.3.1", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" - } - }, - "engine.io-parser": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", - "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", - "dev": true, - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.4", - "has-binary2": "~1.0.2" - } - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", - "dev": true - }, - "log4js": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.11.0.tgz", - "integrity": "sha1-vzkC7/ZcaSPZzpz70ttUFg40AFo=", - "dev": true, - "requires": { - "amqplib": "^0.5.2", - "axios": "^0.15.3", - "circular-json": "^0.5.4", - "date-format": "^1.2.0", - "debug": "^3.1.0", - "hipchat-notifier": "^1.1.0", - "loggly": "^1.1.0", - "mailgun-js": "^0.18.0", - "nodemailer": "^2.5.0", - "redis": "^2.7.1", - "semver": "^5.5.0", - "slack-node": "~0.2.0", - "streamroller": "0.7.0" - } - }, - "lru-cache": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", - "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", - "dev": true - }, - "socket.io": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", - "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", - "dev": true, - "requires": { - "debug": "~2.6.6", - "engine.io": "~3.1.0", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.0.4", - "socket.io-parser": "~3.1.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "socket.io-adapter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", - "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", - "dev": true - }, - "socket.io-client": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", - "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", - "dev": true, - "requires": { - "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~2.6.4", - "engine.io-client": "~3.1.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "socket.io-parser": "~3.1.1", - "to-array": "0.1.4" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "socket.io-parser": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", - "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", - "dev": true, - "requires": { - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "has-binary2": "~1.0.2", - "isarray": "2.0.1" - } - }, + "braces": "^2.3.2", + "chokidar": "^2.0.3", + "colors": "^1.1.0", + "connect": "^3.6.0", + "core-js": "^2.2.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^3.0.0", + "lodash": "^4.17.11", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "optimist": "^0.6.1", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "safe-buffer": "^5.0.1", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "useragent": "2.3.0" + }, + "dependencies": { "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { "os-tmpdir": "~1.0.2" } - }, - "ultron": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", - "dev": true - }, - "useragent": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", - "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", - "dev": true, - "requires": { - "lru-cache": "2.2.x", - "tmp": "0.0.x" - } - }, - "ws": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", - "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0", - "safe-buffer": "~5.1.0", - "ultron": "~1.1.0" - } - }, - "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", - "dev": true } } }, + "karma-browserify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/karma-browserify/-/karma-browserify-6.0.0.tgz", + "integrity": "sha512-G3dGjoy1/6P8I6qTp799fbcAxs4P+1JcyEKUzy9g1/xMakqf9FFPwW2T9iEtCbWoH5WIKD3z+YwGL5ysBhzrsg==", + "dev": true, + "requires": { + "convert-source-map": "^1.1.3", + "hat": "^0.0.3", + "js-string-escape": "^1.0.0", + "lodash": "^4.17.10", + "minimatch": "^3.0.0", + "os-shim": "^0.1.3" + } + }, "karma-chrome-launcher": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz", - "integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==", + "integrity": "sha1-zxudBxNswY/iOTJ9JGVMPbw2is8=", "dev": true, "requires": { "fs-access": "^1.0.0", @@ -7606,7 +8164,7 @@ "karma-edge-launcher": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/karma-edge-launcher/-/karma-edge-launcher-0.4.2.tgz", - "integrity": "sha512-YAJZb1fmRcxNhMIWYsjLuxwODBjh2cSHgTW/jkVmdpGguJjLbs9ZgIK/tEJsMQcBLUkO+yO4LBbqYxqgGW2HIw==", + "integrity": "sha1-PZUpsJsTyQnF887uEtAOf5qYmz0=", "dev": true, "requires": { "edge-launcher": "1.2.2" @@ -7615,7 +8173,7 @@ "karma-firefox-launcher": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.1.0.tgz", - "integrity": "sha512-LbZ5/XlIXLeQ3cqnCbYLn+rOVhuMIK9aZwlP6eOLGzWdo1UVp7t6CN3DP4SafiRLjexKwHeKHDm0c38Mtd3VxA==", + "integrity": "sha1-LEcDBFLwRTHrfRPU/HZpYwu5Mzk=", "dev": true }, "karma-ie-launcher": { @@ -7628,10 +8186,22 @@ } }, "karma-jasmine": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.2.tgz", - "integrity": "sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM=", - "dev": true + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-2.0.1.tgz", + "integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==", + "dev": true, + "requires": { + "jasmine-core": "^3.3" + } + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } }, "karma-spec-reporter": { "version": "0.0.32", @@ -7645,7 +8215,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, "klaw": { @@ -7660,7 +8230,7 @@ "labeled-stream-splicer": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.1.tgz", - "integrity": "sha512-MC94mHZRvJ3LfykJlTUipBqenZz1pacOZEMhhQ8dMGcDHs0SBE5GbsavUXV7YtP3icBW17W0Zy1I0lfASmo9Pg==", + "integrity": "sha1-nP+jL9meFhL9HYao25YkFtUpKSY=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -7671,16 +8241,20 @@ "isarray": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.4.tgz", - "integrity": "sha512-GMxXOiUirWg1xTKRipM0Ek07rX+ubx4nNVElTJdNLYmNO/2YrDkgJGw9CljXn+r4EWiDQg/8lsRdHyg2PJuUaA==", + "integrity": "sha1-OOe8uw87obeTPIa6GJTd/DeBu7c=", "dev": true } } }, - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "dev": true + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } }, "lazystream": { "version": "1.0.0", @@ -7691,136 +8265,320 @@ "readable-stream": "^2.0.5" } }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "requires": { + "flush-write-stream": "^1.0.2" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", "dev": true, - "optional": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" } }, - "lexical-scope": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz", - "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=", + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", "dev": true, "requires": { - "astw": "^2.0.0" + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" } }, - "libbase64": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", - "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", - "dev": true + "lint-staged": { + "version": "8.1.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.7.tgz", + "integrity": "sha512-egT0goFhIFoOGk6rasPngTFh2qDqxZddM0PwI58oi66RxCDcn5uDwxmiasWIF0qGnchHSYVJ8HPRD5LrFo7TKA==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "commander": "^2.14.1", + "cosmiconfig": "^5.2.0", + "debug": "^3.1.0", + "dedent": "^0.7.0", + "del": "^3.0.0", + "execa": "^1.0.0", + "find-parent-dir": "^0.3.0", + "g-status": "^2.0.2", + "is-glob": "^4.0.0", + "is-windows": "^1.0.2", + "listr": "^0.14.2", + "listr-update-renderer": "^0.5.0", + "lodash": "^4.17.11", + "log-symbols": "^2.2.0", + "micromatch": "^3.1.8", + "npm-which": "^3.0.1", + "p-map": "^1.1.1", + "path-is-inside": "^1.0.2", + "pify": "^3.0.0", + "please-upgrade-node": "^3.0.2", + "staged-git-files": "1.1.2", + "string-argv": "^0.0.2", + "stringify-object": "^3.2.2", + "yup": "^0.27.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } }, - "libmime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", - "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", + "listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", "dev": true, "requires": { - "iconv-lite": "0.4.15", - "libbase64": "0.1.0", - "libqp": "1.1.0" + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" }, "dependencies": { - "iconv-lite": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", "dev": true } } }, - "libqp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", - "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", "dev": true }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", "dev": true, "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "^1.0.0" + } + } + } + }, + "listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "requires": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "dependencies": { + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "strip-bom": "^3.0.0" }, "dependencies": { - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "requires": { - "is-utf8": "^0.2.0" - } + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true } } }, "loader-runner": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", "dev": true }, "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", "dev": true, "requires": { - "big.js": "^3.1.3", + "big.js": "^5.2.2", "emojis-list": "^2.0.0", - "json5": "^0.5.0" + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "^2.0.0", + "p-locate": "^3.0.0", "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, "lodash._basecopy": { @@ -7841,51 +8599,18 @@ "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", "dev": true }, - "lodash._escapehtmlchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz", - "integrity": "sha1-32fDu2t+jh6DGrSL+geVuSr+iZ0=", - "dev": true, - "requires": { - "lodash._htmlescapes": "~2.4.1" - } - }, - "lodash._escapestringchar": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz", - "integrity": "sha1-7P4iYYoq3lC/7qQ5N+Ud9m8O23I=", - "dev": true - }, "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", "dev": true }, - "lodash._htmlescapes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz", - "integrity": "sha1-MtFL8IRLbeb4tioFG09nwii2JMs=", - "dev": true - }, "lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", "dev": true }, - "lodash._isnative": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz", - "integrity": "sha1-PqZAS3hKe+g2x7V1gOHN95sUgyw=", - "dev": true - }, - "lodash._objecttypes": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz", - "integrity": "sha1-fAt/admKH3ZSn4kLDNsbTf7BHBE=", - "dev": true - }, "lodash._reescape": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", @@ -7904,44 +8629,12 @@ "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", "dev": true }, - "lodash._reunescapedhtml": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz", - "integrity": "sha1-dHxPxAED6zu4oJduVx96JlnpO6c=", - "dev": true, - "requires": { - "lodash._htmlescapes": "~2.4.1", - "lodash.keys": "~2.4.1" - }, - "dependencies": { - "lodash.keys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", - "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - } - } - }, "lodash._root": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", "dev": true }, - "lodash._shimkeys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz", - "integrity": "sha1-bpzJZm/wgfC1psl4uD4kLmlJ0gM=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" - } - }, "lodash.assignin": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", @@ -7950,14 +8643,8 @@ }, "lodash.bind": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", - "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", - "dev": true - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=", "dev": true }, "lodash.defaults": { @@ -7993,6 +8680,12 @@ "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=", "dev": true }, + "lodash.groupby": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", + "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E=", + "dev": true + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", @@ -8005,21 +8698,6 @@ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", "dev": true }, - "lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=", - "dev": true - }, - "lodash.isobject": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz", - "integrity": "sha1-Wi5H/mmVPx7mMafrof5k0tBlWPU=", - "dev": true, - "requires": { - "lodash._objecttypes": "~2.4.1" - } - }, "lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", @@ -8046,7 +8724,7 @@ "lodash.merge": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ=", "dev": true }, "lodash.pick": { @@ -8106,193 +8784,146 @@ "lodash.escape": "^3.0.0" } }, - "lodash.values": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz", - "integrity": "sha1-q/UUQ2s8twUAFieXjLzzCxKA7qQ=", - "dev": true, - "requires": { - "lodash.keys": "~2.4.1" - }, - "dependencies": { - "lodash.keys": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz", - "integrity": "sha1-SN6kbfj/djKxDXBrissmWR4rNyc=", - "dev": true, - "requires": { - "lodash._isnative": "~2.4.1", - "lodash._shimkeys": "~2.4.1", - "lodash.isobject": "~2.4.1" - } - } - } + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", + "dev": true }, - "loggly": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", - "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", + "lodash.unescape": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz", + "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", "dev": true, - "optional": true, "requires": { - "json-stringify-safe": "5.0.x", - "request": "2.75.x", - "timespan": "2.3.x" + "chalk": "^2.0.1" }, "dependencies": { - "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", - "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", - "dev": true, - "optional": true - }, - "bl": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", - "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "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, - "optional": true, "requires": { - "readable-stream": "~2.0.5" + "color-convert": "^1.9.0" } }, - "caseless": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", - "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", - "dev": true, - "optional": true - }, - "commander": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz", - "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==", - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", - "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "optional": true, "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.5", - "mime-types": "^2.1.11" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" } }, - "har-validator": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", - "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "optional": true, "requires": { - "chalk": "^1.1.1", - "commander": "^2.9.0", - "is-my-json-valid": "^2.12.4", - "pinkie-promise": "^2.0.0" + "has-flag": "^3.0.0" } + } + } + }, + "log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha1-iDKP19HOeTiykoN0bwsbwSayRwg=", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true }, - "http-signature": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", - "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, - "optional": true, "requires": { - "assert-plus": "^0.2.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "ansi-regex": "^3.0.0" } }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", - "dev": true, - "optional": true - }, - "qs": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", - "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", - "dev": true, - "optional": true - }, - "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha1-KIoE2H7aXChuBg3+jxNc6NAH+Lo=", "dev": true, - "optional": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "~1.0.0", - "process-nextick-args": "~1.0.6", - "string_decoder": "~0.10.x", - "util-deprecate": "~1.0.1" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" } - }, - "request": { - "version": "2.75.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", - "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + } + } + }, + "log4js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.2.0.tgz", + "integrity": "sha512-1dJ2ORJcdqbzxvzKM2ceqPBh4O6bbICJpB4dvSEUoMcb14s8MqQ/54zNPqekuN5yjGtxO3GUDTvZfQOQhwdqnA==", + "dev": true, + "requires": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.2", + "streamroller": "^1.0.5" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, - "optional": true, "requires": { - "aws-sign2": "~0.6.0", - "aws4": "^1.2.1", - "bl": "~1.1.2", - "caseless": "~0.11.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.0", - "forever-agent": "~0.6.1", - "form-data": "~2.0.0", - "har-validator": "~2.0.6", - "hawk": "~3.1.3", - "http-signature": "~1.1.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.7", - "node-uuid": "~1.4.7", - "oauth-sign": "~0.8.1", - "qs": "~6.2.0", - "stringstream": "~0.0.4", - "tough-cookie": "~2.3.0", - "tunnel-agent": "~0.4.1" + "ms": "^2.1.1" } }, - "tunnel-agent": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", - "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", - "dev": true, - "optional": true + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, - "lolex": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", + "loglevel": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", + "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=", "dev": true }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha1-akAhj9x64V/HbD0PPmdsRlOIYD4=", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + } + }, + "lolex": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-4.0.1.tgz", + "integrity": "sha512-UHuOBZ5jjsKuzbB/gRNNW8Vg8f00Emgskdq2kvZxgBJCS0aqquAuXai/SkWORlKeZEiNQWZjFZOqIUcH9LqKCw==", "dev": true }, "loose-envify": { @@ -8304,93 +8935,71 @@ "js-tokens": "^3.0.0" } }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "dev": true, - "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" - } - }, "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "mailcomposer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", - "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, - "optional": true, "requires": { - "buildmail": "4.0.1", - "libmime": "3.0.0" + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" } }, - "mailgun-js": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.18.1.tgz", - "integrity": "sha512-lvuMP14u24HS2uBsJEnzSyPMxzU2b99tQsIx1o6QNjqxjk8b3WvR+vq5oG1mjqz/IBYo+5gF+uSoDS0RkMVHmg==", + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, - "optional": true, "requires": { - "async": "~2.6.0", - "debug": "~3.1.0", - "form-data": "~2.3.0", - "inflection": "~1.12.0", - "is-stream": "^1.1.0", - "path-proxy": "~1.0.0", - "promisify-call": "^2.0.2", - "proxy-agent": "~3.0.0", - "tsscmp": "~1.0.0" + "pify": "^4.0.1", + "semver": "^5.6.0" }, "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true } } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "make-error": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", + "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "dev": true + }, + "make-error-cause": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz", + "integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=", "dev": true, "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } + "make-error": "^1.2.0" } }, "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", "dev": true, "requires": { "kind-of": "^6.0.2" } }, + "make-plural": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz", + "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, "mamacro": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", - "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "integrity": "sha1-rSyVdhl8nxq/MI0Hh4Zb2XWj8+Q=", "dev": true }, "map-cache": { @@ -8400,9 +9009,9 @@ "dev": true }, "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz", + "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=", "dev": true }, "map-visit": { @@ -8417,23 +9026,68 @@ "marked": { "version": "0.3.19", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", - "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", + "integrity": "sha1-XUf3CcTJ/Dwha21GEnKA9As515A=", "dev": true }, + "matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "matcher": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-1.1.1.tgz", + "integrity": "sha512-+BmqxWIubKTRKNWx/ahnCkk3mG8m7OturVlqq6HiojGJTd5hVYbgZm6WzcYPCoB+KBT4Vd6R7WSRG2OADNaCjg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.4" + } + }, "math-random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", "dev": true }, "md5.js": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", - "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "dev": true, "requires": { "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "media-typer": { @@ -8442,6 +9096,15 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -8452,37 +9115,45 @@ "readable-stream": "^2.0.1" } }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "messageformat": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/messageformat/-/messageformat-1.1.1.tgz", + "integrity": "sha512-Q0uXcDtF5pEZsVSyhzDOGgZZK6ykN79VY9CwU3Nv0gsqx62BjdJW0MT+63UkHQ4exe3HE33ZlxR2/YwoJarRTg==", "dev": true, "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "glob": "~7.0.6", + "make-plural": "^4.1.1", + "messageformat-parser": "^1.1.0", + "nopt": "~3.0.6", + "reserved-words": "^0.1.2" + }, + "dependencies": { + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } } }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } + "messageformat-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-1.1.0.tgz", + "integrity": "sha512-Hwem6G3MsKDLS1FtBRGIs8T50P1Q00r3srS6QJePCFbad9fq0nYxwf3rnU2BreApRGhmpKMV7oZI06Sy1c9TPA==", + "dev": true }, "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -8503,7 +9174,7 @@ "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", - "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "integrity": "sha1-8IA1HIZbDcViqEYpZtqlNUPHik0=", "dev": true, "requires": { "bn.js": "^4.0.0", @@ -8511,9 +9182,9 @@ } }, "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.3.tgz", + "integrity": "sha512-QgrPRJfE+riq5TPZMcHZOtm8c6K/yYrMbKIoRfapfiGLxS8OTeIfRhUGW5LU7MlRa52KOAGCfUNruqLrIBvWZw==", "dev": true }, "mime-db": { @@ -8531,10 +9202,16 @@ "mime-db": "~1.33.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "integrity": "sha1-LhlN4ERibUoQ5/f7wAznPoPk1cc=", "dev": true }, "minimalistic-crypto-utils": { @@ -8546,7 +9223,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -8559,9 +9236,9 @@ "dev": true }, "mississippi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", - "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "dev": true, "requires": { "concat-stream": "^1.5.0", @@ -8570,19 +9247,20 @@ "flush-write-stream": "^1.0.0", "from2": "^2.1.0", "parallel-transform": "^1.1.0", - "pump": "^2.0.1", + "pump": "^3.0.0", "pumpify": "^1.3.3", "stream-each": "^1.1.0", "through2": "^2.0.0" }, "dependencies": { - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { - "once": "^1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -8590,7 +9268,7 @@ "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { "for-in": "^1.0.2", @@ -8600,7 +9278,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -8626,22 +9304,22 @@ } }, "module-deps": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", - "integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.0.tgz", + "integrity": "sha512-hKPmO06so6bL/ZvqVNVqdTVO8UAYsi3tQWlCa+z9KuWhoN4KDQtb5hcqQQv58qYiDE21wIvnttZEPiDgEbpwbA==", "dev": true, "requires": { "JSONStream": "^1.0.3", "browser-resolve": "^1.7.0", "cached-path-relative": "^1.0.0", - "concat-stream": "~1.5.0", + "concat-stream": "~1.6.0", "defined": "^1.0.0", - "detective": "^4.0.0", + "detective": "^5.0.2", "duplexer2": "^0.1.2", "inherits": "^2.0.1", "parents": "^1.0.0", "readable-stream": "^2.0.2", - "resolve": "^1.1.3", + "resolve": "^1.4.0", "stream-combiner2": "^1.1.1", "subarg": "^1.0.0", "through2": "^2.0.0", @@ -8707,22 +9385,34 @@ } }, "mustache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz", - "integrity": "sha1-QCj3d4sXcIpImTCm5SrDvKDaQdA=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.0.1.tgz", + "integrity": "sha512-jFI/4UVRsRYdUbuDTKT7KzfOp7FiD5WzYmmwNwXyUVypC0xjoTL78Fqc0jHUPIvvGD+6DQSPHIt1NE7D1ArsqA==", + "dev": true + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, "nan": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", - "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", "dev": true, "optional": true }, "nanomatch": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", - "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -8730,7 +9420,6 @@ "define-property": "^2.0.2", "extend-shallow": "^3.0.2", "fragment-cache": "^0.2.1", - "is-odd": "^2.0.0", "is-windows": "^1.0.2", "kind-of": "^6.0.2", "object.pick": "^1.3.0", @@ -8739,35 +9428,49 @@ "to-regex": "^3.0.1" } }, - "natives": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.4.tgz", - "integrity": "sha512-Q29yeg9aFKwhLVdkTAejM/HvYG0Y1Am1+HUkFQGn5k2j8GS+v60TVmZh6nujpEAj/qql+wGUrlryO8bF+b1jEg==", + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", "dev": true }, "neo-async": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.2.tgz", - "integrity": "sha512-vdqTKI9GBIYcAEbFAcpKPErKINfPF5zIuz3/niBfq8WUZjpT2tytLlFVrBgWdOtqI4uaA/Rb6No0hux39XXDuw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", "dev": true }, - "netmask": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", - "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", "dev": true, - "optional": true + "requires": { + "lodash.toarray": "^4.4.0" + } }, "node-libs-browser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", - "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.0.tgz", + "integrity": "sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==", "dev": true, "requires": { "assert": "^1.1.1", @@ -8777,7 +9480,7 @@ "constants-browserify": "^1.0.0", "crypto-browserify": "^3.11.0", "domain-browser": "^1.1.1", - "events": "^1.0.0", + "events": "^3.0.0", "https-browserify": "^1.0.0", "os-browserify": "^0.3.0", "path-browserify": "0.0.0", @@ -8791,35 +9494,31 @@ "timers-browserify": "^2.0.4", "tty-browserify": "0.0.0", "url": "^0.11.0", - "util": "^0.10.3", + "util": "^0.11.0", "vm-browserify": "0.0.4" }, "dependencies": { - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "buffer": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "dev": true, "requires": { - "pako": "~1.0.5" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" } }, - "https-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", - "dev": true - }, - "os-browserify": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", "dev": true }, - "pako": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "path-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, "punycode": { @@ -8829,9 +9528,9 @@ "dev": true }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8840,7 +9539,7 @@ "timers-browserify": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", - "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "integrity": "sha1-HSjj0qrfHVpZlsTp+VYBzQU0gK4=", "dev": true, "requires": { "setimmediate": "^1.0.4" @@ -8851,120 +9550,132 @@ "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, + "requires": { + "indexof": "0.0.1" + } } } }, - "node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", - "dev": true, - "optional": true + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true }, - "nodemailer": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", - "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", + "node-releases": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.19.tgz", + "integrity": "sha512-SH/B4WwovHbulIALsQllAVwqZZD1kPmKCqrhGfR29dXjLAVZMHvBjD3S6nL9D/J9QkmZ1R92/0wCMDKXUUvyyA==", "dev": true, - "optional": true, "requires": { - "libmime": "3.0.0", - "mailcomposer": "4.0.1", - "nodemailer-direct-transport": "3.3.2", - "nodemailer-shared": "1.1.0", - "nodemailer-smtp-pool": "2.8.2", - "nodemailer-smtp-transport": "2.7.2", - "socks": "1.1.9" + "semver": "^5.3.0" }, "dependencies": { - "socks": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", - "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", - "dev": true, - "optional": true, - "requires": { - "ip": "^1.1.2", - "smart-buffer": "^1.0.4" - } + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true } } }, - "nodemailer-direct-transport": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", - "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, - "optional": true, "requires": { - "nodemailer-shared": "1.1.0", - "smtp-connection": "2.12.0" + "abbrev": "1" } }, - "nodemailer-fetch": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", - "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", - "dev": true - }, - "nodemailer-shared": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", - "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { - "nodemailer-fetch": "1.6.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, - "nodemailer-smtp-pool": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", - "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", + "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, - "optional": true, "requires": { - "nodemailer-shared": "1.1.0", - "nodemailer-wellknown": "0.1.10", - "smtp-connection": "2.12.0" + "remove-trailing-separator": "^1.0.1" } }, - "nodemailer-smtp-transport": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", - "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", + "now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", "dev": true, - "optional": true, "requires": { - "nodemailer-shared": "1.1.0", - "nodemailer-wellknown": "0.1.10", - "smtp-connection": "2.12.0" + "once": "^1.3.2" } }, - "nodemailer-wellknown": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", - "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", - "dev": true + "npm-path": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.4.tgz", + "integrity": "sha512-IFsj0R9C7ZdR5cP+ET342q77uSRdtWOlWpih5eC+lu29tIDbNEgDbzgVJ5UFvYHWhxDZ5TFkJafFioO0pPQjCw==", + "dev": true, + "requires": { + "which": "^1.2.10" + } }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "is-builtin-module": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "path-key": "^2.0.0" } }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "npm-which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", + "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", "dev": true, "requires": { - "remove-trailing-separator": "^1.0.1" + "commander": "^2.9.0", + "npm-path": "^2.0.2", + "which": "^1.2.10" + }, + "dependencies": { + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + } } }, "nth-check": { @@ -8991,7 +9702,7 @@ "nwmatcher": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "integrity": "sha1-IoVjHzSpXw0Dlc2QDJbtObWPNG4=", "dev": true, "optional": true }, @@ -9046,9 +9757,9 @@ } }, "object-keys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", - "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, "object-visit": { @@ -9060,6 +9771,18 @@ "isobject": "^3.0.0" } }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, "object.defaults": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", @@ -9112,6 +9835,16 @@ "isobject": "^3.0.1" } }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -9130,6 +9863,15 @@ "wrappy": "1" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + } + }, "optimist": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", @@ -9159,7 +9901,6 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", "dev": true, - "optional": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -9169,33 +9910,94 @@ "wordwrap": "~1.0.0" } }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "ora": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", + "integrity": "sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==", "dev": true, "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-spinners": "^2.0.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^5.2.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } }, "os-browserify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", - "integrity": "sha1-ScoCk+CxlZCl9d4Qx/JlphfY/lQ=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", "dev": true }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", "dev": true }, "os-tmpdir": { @@ -9204,88 +10006,52 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "dev": true, "requires": { - "p-try": "^1.0.0" + "p-try": "^2.0.0" } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "^1.1.0" + "p-limit": "^2.0.0" } }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, - "pac-proxy-agent": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz", - "integrity": "sha512-cDNAN1Ehjbf5EHkNY5qnRhGPUCp6SnpyVof5fRzN800QV1Y2OkzbH9rmjZkbBRa8igof903yOnjIl6z0SlAhxA==", - "dev": true, - "optional": true, - "requires": { - "agent-base": "^4.2.0", - "debug": "^3.1.0", - "get-uri": "^2.0.0", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.1", - "pac-resolver": "^3.0.0", - "raw-body": "^2.2.0", - "socks-proxy-agent": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "socks-proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", - "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", - "dev": true, - "optional": true, - "requires": { - "agent-base": "^4.1.0", - "socks": "^1.1.10" - } - } - } + "p-queue": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-1.2.0.tgz", + "integrity": "sha1-Y5y4sHJwwVtx16ZEao4wQU88ltE=", + "dev": true }, - "pac-resolver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", - "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", - "dev": true, - "optional": true, - "requires": { - "co": "^4.6.0", - "degenerator": "^1.0.4", - "ip": "^1.1.5", - "netmask": "^1.0.6", - "thunkify": "^2.1.2" - } + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true }, "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", "dev": true }, "parallel-transform": { @@ -9299,6 +10065,15 @@ "readable-stream": "^2.1.5" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parents": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", @@ -9309,16 +10084,17 @@ } }, "parse-asn1": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", - "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.4.tgz", + "integrity": "sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==", "dev": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", "create-hash": "^1.1.0", "evp_bytestokey": "^1.0.0", - "pbkdf2": "^3.0.3" + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" } }, "parse-filepath": { @@ -9370,6 +10146,12 @@ "error-ex": "^1.2.0" } }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", @@ -9379,7 +10161,7 @@ "parse5": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", - "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "integrity": "sha1-BC95L/3TaFFVHPTp4Gazh0q0W1w=", "dev": true, "requires": { "@types/node": "*" @@ -9404,9 +10186,9 @@ } }, "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true }, "pascalcase": { @@ -9416,9 +10198,9 @@ "dev": true }, "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", "dev": true }, "path-dirname": { @@ -9428,13 +10210,10 @@ "dev": true }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", @@ -9442,36 +10221,29 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, - "path-platform": { - "version": "0.11.15", - "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", - "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, - "path-proxy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", - "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", - "dev": true, - "optional": true, - "requires": { - "inflection": "~1.3.0" - }, - "dependencies": { - "inflection": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", - "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", - "dev": true, - "optional": true - } - } + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "dev": true }, "path-root": { "version": "0.1.1", @@ -9489,20 +10261,26 @@ "dev": true }, "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "pify": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, "pbkdf2": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", - "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", "dev": true, "requires": { "create-hash": "^1.1.2", @@ -9524,10 +10302,16 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "perfy": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/perfy/-/perfy-1.1.5.tgz", + "integrity": "sha512-/ieVBpMaPTJf83YTUl2TImsSwMEJ23qGP2w27pE6aX+NrB/ZRGqOnQZpl7J719yFwd+ebDiHguPNFeMSamyK7w==", + "dev": true + }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "pinkie": { @@ -9545,15 +10329,608 @@ "pinkie": "^2.0.0" } }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "please-upgrade-node": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz", + "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==", + "dev": true, + "requires": { + "semver-compare": "^1.0.0" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha1-dwFr2JGdCsN3/c3QMiMolTyleBw=", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "prettier": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.1.tgz", + "integrity": "sha512-TzGRNvuUSmPgwivDqkZ9tM/qTGW9hqDKWOE9YHiyQdixlKbv7kvEqsmDPrcHJTKwthU774TQwZXVtaQ/mMsvjg==", + "dev": true + }, + "prettier-eslint": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-8.8.2.tgz", + "integrity": "sha512-2UzApPuxi2yRoyMlXMazgR6UcH9DKJhNgCviIwY3ixZ9THWSSrUww5vkiZ3C48WvpFl1M1y/oU63deSy1puWEA==", "dev": true, "requires": { - "find-up": "^2.1.0" + "babel-runtime": "^6.26.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^4.0.0", + "indent-string": "^3.2.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^1.7.0", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^2.5.1", + "typescript-eslint-parser": "^16.0.0", + "vue-eslint-parser": "^2.0.2" + }, + "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "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" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + } + } + }, + "prettier-eslint-cli": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/prettier-eslint-cli/-/prettier-eslint-cli-4.7.1.tgz", + "integrity": "sha512-hQbsGaEVz97oBBcKdsJ46khv0kOGkMyWrXzcFOXW6X8UuetZ/j0yDJkNJgUTVc6PVFbbzBXk+qgd5vos9qzXPQ==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "babel-runtime": "^6.23.0", + "boolify": "^1.0.0", + "camelcase-keys": "^4.1.0", + "chalk": "2.3.0", + "common-tags": "^1.4.0", + "eslint": "^4.5.0", + "find-up": "^2.1.0", + "get-stdin": "^5.0.1", + "glob": "^7.1.1", + "ignore": "^3.2.7", + "indent-string": "^3.1.0", + "lodash.memoize": "^4.1.2", + "loglevel-colored-level-prefix": "^1.0.0", + "messageformat": "^1.0.2", + "prettier-eslint": "^8.5.0", + "rxjs": "^5.3.0", + "yargs": "10.0.3" }, "dependencies": { + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "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" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.1.0", + "escape-string-regexp": "^1.0.5", + "supports-color": "^4.0.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "dev": true, + "requires": { + "ajv": "^5.3.0", + "babel-code-frame": "^6.22.0", + "chalk": "^2.1.0", + "concat-stream": "^1.6.0", + "cross-spawn": "^5.1.0", + "debug": "^3.1.0", + "doctrine": "^2.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.4", + "esquery": "^1.0.0", + "esutils": "^2.0.2", + "file-entry-cache": "^2.0.0", + "functional-red-black-tree": "^1.0.1", + "glob": "^7.1.2", + "globals": "^11.0.1", + "ignore": "^3.3.3", + "imurmurhash": "^0.1.4", + "inquirer": "^3.0.6", + "is-resolvable": "^1.0.0", + "js-yaml": "^3.9.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.2", + "path-is-inside": "^1.0.2", + "pluralize": "^7.0.0", + "progress": "^2.0.0", + "regexpp": "^1.0.1", + "require-uncached": "^1.0.3", + "semver": "^5.3.0", + "strip-ansi": "^4.0.0", + "strip-json-comments": "~2.0.1", + "table": "4.0.2", + "text-table": "~0.2.0" + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "^1.2.1", + "object-assign": "^4.0.1" + } + }, "find-up": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", @@ -9562,45 +10939,290 @@ "requires": { "locate-path": "^2.0.0" } + }, + "flat-cache": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", + "dev": true, + "requires": { + "circular-json": "^0.3.1", + "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", + "write": "^0.2.1" + } + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", + "dev": true + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.4", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx-lite": "^4.0.8", + "rx-lite-aggregates": "^4.0.8", + "string-width": "^2.1.0", + "strip-ansi": "^4.0.0", + "through": "^2.3.6" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "^0.7.0", + "lcid": "^1.0.0", + "mem": "^1.1.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "rxjs": { + "version": "5.5.12", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", + "integrity": "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + } + }, + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "^2.0.0" + } + }, + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "^5.2.3", + "ajv-keywords": "^2.1.0", + "chalk": "^2.1.0", + "lodash": "^4.17.4", + "slice-ansi": "1.0.0", + "string-width": "^2.1.1" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "yargs": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz", + "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", + "dev": true, + "requires": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^8.0.0" + } + }, + "yargs-parser": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + } } } }, - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", "dev": true, "requires": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + }, + "dependencies": { + "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" + } + } } }, - "pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", - "dev": true - }, "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", @@ -9610,7 +11232,7 @@ "private": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", - "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "integrity": "sha1-I4Hts2ifelPWUxkAYPz4ItLzaP8=", "dev": true }, "process": { @@ -9622,7 +11244,13 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "promise-inflight": { @@ -9631,62 +11259,11 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, - "promisify-call": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", - "integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=", - "dev": true, - "optional": true, - "requires": { - "with-callback": "^1.0.2" - } - }, - "proxy-agent": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.1.tgz", - "integrity": "sha512-mAZexaz9ZxQhYPWfAjzlrloEjW+JHiBFryE4AJXFDTnaXfmH/FKqC1swTRKuEPbHWz02flQNXFOyDUF7zfEG6A==", - "dev": true, - "optional": true, - "requires": { - "agent-base": "^4.2.0", - "debug": "^3.1.0", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.1", - "lru-cache": "^4.1.2", - "pac-proxy-agent": "^2.0.1", - "proxy-from-env": "^1.0.0", - "socks-proxy-agent": "^4.0.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "dev": true, - "optional": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - } - } - }, - "proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", - "dev": true, - "optional": true + "property-expr": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-1.5.1.tgz", + "integrity": "sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g==", + "dev": true }, "prr": { "version": "1.0.1", @@ -9707,43 +11284,33 @@ "dev": true }, "public-encrypt": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", - "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", "dev": true, "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", "create-hash": "^1.1.0", "parse-asn1": "^5.0.0", - "randombytes": "^2.0.1" + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "pump": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - }, - "dependencies": { - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - } + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha1-Ejma3W5M91Jtlzy8i1zi4pCLOQk=", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "pumpify": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "integrity": "sha1-NlE74karJ1cLGjdKXOJ4v9dDcM4=", "dev": true, "requires": { "duplexify": "^3.6.0", @@ -9754,18 +11321,18 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" }, "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=", "dev": true }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", "dev": true }, "querystring": { @@ -9780,10 +11347,16 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, + "quick-lru": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", + "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=", + "dev": true + }, "randomatic": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", - "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", "dev": true, "requires": { "is-number": "^4.0.0", @@ -9794,15 +11367,15 @@ "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==", + "integrity": "sha1-ACbjf1RU1z41bf5lZGmYZ8an8P8=", "dev": true } } }, "randombytes": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", - "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, "requires": { "safe-buffer": "^5.1.0" @@ -9811,7 +11384,7 @@ "randomfill": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", - "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "integrity": "sha1-ySGW/IarQr6YPxvzF3giSTHWFFg=", "dev": true, "requires": { "randombytes": "^2.0.5", @@ -9819,33 +11392,23 @@ } }, "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true }, "raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "dev": true, "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" } }, - "read-all-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", - "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0", - "readable-stream": "^2.0.0" - } - }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -9856,30 +11419,75 @@ } }, "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "^1.0.0", + "load-json-file": "^2.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "path-type": "^2.0.0" } }, "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } } }, "readable-stream": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -9894,7 +11502,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -9903,15 +11511,14 @@ } }, "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "minimatch": "^3.0.2", - "readable-stream": "^2.0.2", - "set-immediate-shim": "^1.0.1" + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" } }, "rechoir": { @@ -9923,68 +11530,31 @@ "resolve": "^1.1.6" } }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "dev": true, - "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" - } - }, - "redis": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", - "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", - "dev": true, - "optional": true, - "requires": { - "double-ended-queue": "^2.1.0-0", - "redis-commands": "^1.2.0", - "redis-parser": "^2.6.0" - } - }, - "redis-commands": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.5.tgz", - "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==", - "dev": true, - "optional": true - }, - "redis-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", - "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", - "dev": true, - "optional": true - }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", - "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "integrity": "sha1-SoVuxLVuQHfFV1icroXnpMiGmhE=", "dev": true }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regenerator-transform": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", - "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", "dev": true, "requires": { - "babel-runtime": "^6.18.0", - "babel-types": "^6.19.0", - "private": "^0.1.6" + "regenerate": "^1.4.0" } }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha1-vgWtf5v30i4Fb5cmzuUBf78Z4uk=", + "dev": true + }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", "dev": true, "requires": { "is-equal-shallow": "^0.1.3" @@ -9993,45 +11563,44 @@ "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" } }, - "regexpu-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", - "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "regexp-tree": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.8.tgz", + "integrity": "sha512-9ASu7tuCKzdFa2YKfJmnmlilFrIJ8HFfE6MCs4aDLUw4gTBAaNwTTx/gw8Qo97fsV+UTVQXTmz9sHByeC8sKZg==", + "dev": true + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", "dev": true, "requires": { - "regenerate": "^1.2.1", - "regjsgen": "^0.2.0", - "regjsparser": "^0.1.4" + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" } }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", - "dev": true - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", "dev": true, "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" } }, "remove-trailing-separator": { @@ -10041,9 +11610,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", "dev": true }, "repeat-string": { @@ -10067,10 +11636,21 @@ "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", "dev": true }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, "replacestream": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz", - "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==", + "integrity": "sha1-PuV5gJK+Nksc2xSEMISSyz3/LzY=", "dev": true, "requires": { "escape-string-regexp": "^1.0.3", @@ -10107,17 +11687,55 @@ "uuid": "^3.1.0" } }, - "requestretry": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", - "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", "dev": true, - "optional": true, "requires": { - "extend": "^3.0.0", - "lodash": "^4.15.0", - "request": "^2.74.0", - "when": "^3.7.7" + "caller-path": "^0.1.0", + "resolve-from": "^1.0.0" + }, + "dependencies": { + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "^0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + } } }, "requires-port": { @@ -10126,13 +11744,19 @@ "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "reserved-words": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/reserved-words/-/reserved-words-0.1.2.tgz", + "integrity": "sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE=", + "dev": true + }, "resolve": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz", - "integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", + "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", "dev": true, "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "resolve-dir": { @@ -10145,46 +11769,83 @@ "global-modules": "^1.0.0" } }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "requires": { + "value-or-function": "^3.0.0" + } + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "requires": { - "align-text": "^0.1.1" - } + "rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "integrity": "sha1-ocGm9iR1FXe6XQeRTLyShQWFiQw=", "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" } }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "^2.1.0" + } + }, + "run-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", + "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", + "dev": true + }, "run-queue": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", @@ -10195,19 +11856,96 @@ } }, "run-sequence": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-1.2.2.tgz", - "integrity": "sha1-UJWgvr6YczsBQL0I3YDsAw3azes=", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-2.2.1.tgz", + "integrity": "sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "fancy-log": "^1.3.2", + "plugin-error": "^0.1.2" + }, + "dependencies": { + "arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + } + }, + "arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true + }, + "array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true + }, + "extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "requires": { + "kind-of": "^1.1.0" + } + }, + "kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true + }, + "plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "requires": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + } + } + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "*" + } + }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", + "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", "dev": true, "requires": { - "chalk": "*", - "gulp-util": "*" + "tslib": "^1.9.0" } }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", "dev": true }, "safe-regex": { @@ -10222,30 +11960,31 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", "dev": true }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", "dev": true, "optional": true }, "schema-utils": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz", - "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", "dev": true, "requires": { "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" }, "dependencies": { "ajv": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", - "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -10254,6 +11993,12 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", + "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "dev": true + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -10278,33 +12023,42 @@ } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", "dev": true }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", "dev": true }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "requires": { + "sver-compat": "^1.5.0" + } + }, "serialize-javascript": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.7.0.tgz", + "integrity": "sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==", "dev": true }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -10331,15 +12085,15 @@ "dev": true }, "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", "dev": true }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "integrity": "sha1-N6XPC4HsvGlD3hCbopYNGyZYSuc=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -10356,6 +12110,21 @@ "sha.js": "~2.4.4" } }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, "shell-quote": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", @@ -10368,26 +12137,42 @@ "jsonify": "~0.0.0" } }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, - "slack-node": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", - "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", + "simple-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", + "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=", + "dev": true + }, + "simple-git": { + "version": "1.113.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.113.0.tgz", + "integrity": "sha512-i9WVsrK2u0G/cASI9nh7voxOk9mhanWY9eGtWBDSYql6m49Yk5/Fan6uZsDr/xmzv8n+eQ8ahKCoEr8cvU3h+g==", "dev": true, - "optional": true, "requires": { - "requestretry": "^1.2.2" + "debug": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } } }, "slash": { @@ -10396,27 +12181,32 @@ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", "dev": true }, - "smart-buffer": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", - "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", - "dev": true, - "optional": true - }, - "smtp-connection": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", - "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", "dev": true, "requires": { - "httpntlm": "1.6.1", - "nodemailer-shared": "1.1.0" + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "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" + } + } } }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", "dev": true, "requires": { "base": "^0.11.1", @@ -10452,7 +12242,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { "define-property": "^1.0.0", @@ -10472,7 +12262,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10481,7 +12271,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -10490,7 +12280,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -10503,7 +12293,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -10520,62 +12310,114 @@ } } }, - "sntp": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", - "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", "dev": true, - "optional": true, "requires": { - "hoek": "2.x.x" + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + }, + "dependencies": { + "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" + } + } } }, - "socks": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", - "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", + "socket.io-adapter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true + }, + "socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", "dev": true, - "optional": true, "requires": { - "ip": "^1.1.4", - "smart-buffer": "^1.0.13" + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "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" + } + } } }, - "socks-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", - "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", + "socket.io-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", "dev": true, - "optional": true, "requires": { - "agent-base": "~4.2.0", - "socks": "~2.2.0" + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" }, "dependencies": { - "smart-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.1.tgz", - "integrity": "sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg==", - "dev": true, - "optional": true + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, - "socks": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.1.tgz", - "integrity": "sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w==", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, - "optional": true, "requires": { - "ip": "^1.1.5", - "smart-buffer": "^4.0.1" + "ms": "2.0.0" } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true } } }, "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", "dev": true }, "source-map": { @@ -10587,7 +12429,7 @@ "source-map-resolve": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "integrity": "sha1-cuLMNAlVQ+Q7LGKyxMENSpBU8lk=", "dev": true, "requires": { "atob": "^2.1.1", @@ -10598,12 +12440,21 @@ } }, "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", "dev": true, "requires": { - "source-map": "^0.5.6" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } } }, "source-map-url": { @@ -10615,13 +12466,13 @@ "sparkles": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "integrity": "sha1-AI22XtzmxQ7sDF4ijhlFBh3QQ3w=", "dev": true }, "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -10629,15 +12480,15 @@ } }, "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -10645,20 +12496,26 @@ } }, "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", + "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", "dev": true }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { "extend-shallow": "^3.0.0" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "sshpk": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", @@ -10676,18 +12533,24 @@ } }, "ssri": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", - "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "dev": true, "requires": { - "safe-buffer": "^5.1.1" + "figgy-pudding": "^3.5.1" } }, - "stat-mode": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-0.2.2.tgz", - "integrity": "sha1-5sgLYjEj19gM8TLOU480YokHJQI=", + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "staged-git-files": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/staged-git-files/-/staged-git-files-1.1.2.tgz", + "integrity": "sha512-0Eyrk6uXW6tg9PYkhi/V/J4zHp33aNyi2hOCmhFLqLTIhbgqWn5jlSzI+IU0VqrZq6+DbHcabQl/WP6P3BG0QA==", "dev": true }, "static-extend": { @@ -10750,9 +12613,9 @@ } }, "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", "dev": true, "requires": { "inherits": "~2.0.1", @@ -10769,43 +12632,26 @@ "readable-stream": "^2.0.2" } }, - "stream-consume": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", - "dev": true - }, "stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", - "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "integrity": "sha1-6+J6DDibBPvMIzZClS4Qcxr6m64=", "dev": true, "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" - }, - "dependencies": { - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - } } }, "stream-exhaust": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "integrity": "sha1-rNrI2lnvK8HheiwMz2wyDRIOVV0=", "dev": true }, "stream-http": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", - "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", "dev": true, "requires": { "builtin-status-codes": "^3.0.0", @@ -10832,24 +12678,84 @@ } }, "streamroller": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.5.tgz", + "integrity": "sha512-iGVaMcyF5PcUY0cPbW3xFQUXnr9O4RZXNBBjhuLZgrjLO4XCLLGfx4T2sGqygSeylUjwgWRsnNbT9aV0Zb8AYw==", "dev": true, "requires": { - "date-format": "^1.2.0", - "debug": "^3.1.0", - "mkdirp": "^0.5.1", - "readable-stream": "^2.3.0" + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.11" }, "dependencies": { + "async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", + "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + }, + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "string-argv": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.0.2.tgz", + "integrity": "sha1-2sMECGkMIfPDYwo/86BYd73L1zY=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" } } } @@ -10860,12 +12766,16 @@ "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", "dev": true }, - "stringstream": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", - "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "stringify-object": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz", + "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==", "dev": true, - "optional": true + "requires": { + "get-own-enumerable-property-symbols": "^3.0.0", + "is-obj": "^1.0.1", + "is-regexp": "^1.0.0" + } }, "strip-ansi": { "version": "3.0.1", @@ -10877,22 +12787,18 @@ } }, "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true }, "strip-bom-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz", - "integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", + "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", "dev": true, "requires": { - "first-chunk-stream": "^1.0.0", + "first-chunk-stream": "^2.0.0", "strip-bom": "^2.0.0" }, "dependencies": { @@ -10908,44 +12814,25 @@ } }, "strip-dirs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz", - "integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "dev": true, "requires": { - "chalk": "^1.0.0", - "get-stdin": "^4.0.1", - "is-absolute": "^0.1.5", - "is-natural-number": "^2.0.0", - "minimist": "^1.1.0", - "sum-up": "^1.0.1" - }, - "dependencies": { - "is-absolute": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", - "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=", - "dev": true, - "requires": { - "is-relative": "^0.1.0" - } - }, - "is-relative": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", - "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=", - "dev": true - } + "is-natural-number": "^4.0.1" } }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1" - } + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true }, "subarg": { "version": "1.0.0", @@ -10956,21 +12843,28 @@ "minimist": "^1.1.0" } }, - "sum-up": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sum-up/-/sum-up-1.0.3.tgz", - "integrity": "sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4=", - "dev": true, - "requires": { - "chalk": "^1.0.0" - } - }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true + }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", @@ -10978,15 +12872,85 @@ "dev": true, "optional": true }, + "synchronous-promise": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.7.tgz", + "integrity": "sha512-16GbgwTmFMYFyQMLvtQjvNWh30dsFe1cAW5Fg1wm5+dg84L9Pe36mftsIRU95/W2YsISxsz/xq4VB23sqpgb/A==", + "dev": true + }, "syntax-error": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", - "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "integrity": "sha1-LZ1P9cBkrLcRWUo+O5UFStUdkHw=", "dev": true, "requires": { "acorn-node": "^1.2.0" } }, + "table": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/table/-/table-5.3.3.tgz", + "integrity": "sha512-3wUNCgdWX6PNpOe3amTTPWPuF6VGvgzjKCaO1snFj0z7Y3mUPWf5+zDtxUVGispJkDECPmR29wbzh6bVMOHbcw==", + "dev": true, + "requires": { + "ajv": "^6.9.1", + "lodash": "^4.17.11", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ajv": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, "taffydb": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.7.3.tgz", @@ -10994,46 +12958,91 @@ "dev": true }, "tapable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.0.tgz", - "integrity": "sha512-IlqtmLVaZA2qab8epUXbVWRn3aB1imbDMJtjB3nu4X0NqPkcY/JH9ZtCBWKHWPxs8Svi9tyo8w2dBoi07qZbBA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true }, "tar-stream": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.1.tgz", - "integrity": "sha512-IFLM5wp3QrJODQFPm6/to3LJZrONdBY/otxcvDIQzu217zKye6yVR3hhi9lAjrC2Z+m/j5oDxMPb1qcd8cIvpA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "dev": true, "requires": { "bl": "^1.0.0", - "buffer-alloc": "^1.1.0", + "buffer-alloc": "^1.2.0", "end-of-stream": "^1.0.0", "fs-constants": "^1.0.0", "readable-stream": "^2.3.0", - "to-buffer": "^1.1.0", + "to-buffer": "^1.1.1", "xtend": "^4.0.0" + } + }, + "terser": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz", + "integrity": "sha512-/FQzzPJmCpjAH9Xvk2paiWrFq+5M6aVOf+2KRbwhByISDX/EujxsK+BAvrhb6H+2rtrLCHK9N01wO014vrIwVQ==", + "dev": true, + "requires": { + "commander": "^2.19.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.10" }, "dependencies": { - "end-of-stream": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.4.tgz", + "integrity": "sha512-64IiILNQlACWZLzFlpzNaG0bpQ4ytaB7fwOsbpsdIV70AfLUmIGGeuKL0YV2WmtcrURjE2aOvHD4/lrFV3Rg+Q==", + "dev": true, + "requires": { + "cacache": "^11.3.2", + "find-cache-dir": "^2.0.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "source-map": "^0.6.1", + "terser": "^3.17.0", + "webpack-sources": "^1.3.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true } } }, "text-encoding": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", - "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=" + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.7.0.tgz", + "integrity": "sha512-oJQ3f1hrOnbRLOcwKz0Liq2IcrvDeZRHXhd9RgLrsT+DjWY/nty1Hi7v3dtkaEYbPYe0mUoOfzRrMwfXXwgPUA==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true }, "textextensions": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz", - "integrity": "sha1-ZUhjk+4fK7A5pgy7oFsLaL2VAdI=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.4.0.tgz", + "integrity": "sha512-qftQXnX1DzpSV8EddtHIT0eDDEiBF8ywhFYR2lI9xrGtxqKN+CvLXhACeCIGbCpQfxxERbrkZEFb8cZcDKbVZA==", "dev": true }, "throttleit": { @@ -11059,31 +13068,15 @@ } }, "through2-filter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz", - "integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", "dev": true, "requires": { "through2": "~2.0.0", "xtend": "~4.0.0" } }, - "thunkify": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", - "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", - "dev": true, - "optional": true - }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0" - } - }, "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", @@ -11099,40 +13092,23 @@ "process": "~0.11.0" } }, - "timespan": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", - "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", - "dev": true, - "optional": true - }, "tmp": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", - "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz", + "integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==", "dev": true, "requires": { - "os-tmpdir": "~1.0.1" + "rimraf": "^2.6.3" } }, "to-absolute-glob": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz", - "integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", "dev": true, "requires": { - "extend-shallow": "^2.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" } }, "to-array": { @@ -11150,7 +13126,7 @@ "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", "dev": true }, "to-fast-properties": { @@ -11182,7 +13158,7 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { "define-property": "^2.0.2", @@ -11201,6 +13177,27 @@ "repeat-string": "^1.6.1" } }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "requires": { + "through2": "^2.0.3" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=", + "dev": true + }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", @@ -11225,12 +13222,6 @@ "dev": true, "optional": true }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", - "dev": true - }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -11240,20 +13231,13 @@ "tslib": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "integrity": "sha1-1+TdeSRdhUKMTX5IIqeZF5VMooY=", "dev": true }, - "tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", - "dev": true, - "optional": true - }, "tty-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", - "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "integrity": "sha1-PwUlHuF5BN/QZ3VGZw25ZRaCuBE=", "dev": true }, "tunnel-agent": { @@ -11281,14 +13265,37 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", + "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "dev": true + }, "type-is": { - "version": "1.6.16", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", - "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "requires": { "media-typer": "0.3.0", - "mime-types": "~2.1.18" + "mime-types": "~2.1.24" + }, + "dependencies": { + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "requires": { + "mime-db": "1.40.0" + } + } } }, "typedarray": { @@ -11298,63 +13305,43 @@ "dev": true }, "typescript": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.3.tgz", - "integrity": "sha512-K7g15Bb6Ra4lKf7Iq2l/I5/En+hLIHmxWZGq3D4DIRNFxMNV6j2SHSvDOqs2tGd4UvD/fJvrwopzQXjLrT7Itw==", + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", "dev": true }, - "uglify-js": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz", - "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=", + "typescript-eslint-parser": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/typescript-eslint-parser/-/typescript-eslint-parser-16.0.1.tgz", + "integrity": "sha512-IKawLTu4A2xN3aN/cPLxvZ0bhxZHILGDKTZWvWNJ3sLNhJ3PjfMEDQmR2VMpdRPrmWOadgWXRwjLBzSA8AGsaQ==", "dev": true, "requires": { - "async": "~0.2.6", - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "lodash.unescape": "4.0.1", + "semver": "5.5.0" }, "dependencies": { - "async": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", - "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", "dev": true } } }, - "uglify-save-license": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz", - "integrity": "sha1-lXJsF8xv0XHDYX479NjYKqjEzOE=", - "dev": true - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true - }, - "uglifyjs-webpack-plugin": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz", - "integrity": "sha512-ovHIch0AMlxjD/97j9AYovZxG5wnHOPkL7T1GKochBADp/Zwc44pEWNqpKl1Loupp1WhFg7SlYmHZRUfdAacgw==", + "uglify-js": { + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.14.tgz", + "integrity": "sha512-dgyjIw8KFK6AyVl5vm2tEqPewv5TKGEiiVFLI1LbF+oHua/Njd8tZk3lIbF1AWU1rNdEg7scaceADb4zqCcWXg==", "dev": true, "requires": { - "cacache": "^10.0.4", - "find-cache-dir": "^1.0.0", - "schema-utils": "^0.4.5", - "serialize-javascript": "^1.4.0", - "source-map": "^0.6.1", - "uglify-es": "^3.3.4", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" + "commander": "~2.20.0", + "source-map": "~0.6.1" }, "dependencies": { "commander": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", "dev": true }, "source-map": { @@ -11362,31 +13349,101 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true - }, - "uglify-es": { - "version": "3.3.9", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", - "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", - "dev": true, - "requires": { - "commander": "~2.13.0", - "source-map": "~0.6.1" - } } } }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, "umd": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", - "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", + "integrity": "sha1-qp/mU8QrkJdnhInAEACstp8LJs8=", "dev": true }, + "unbzip2-stream": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz", + "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", "dev": true }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "dev": true, + "requires": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "undertaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -11423,28 +13480,32 @@ } }, "unique-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", - "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "dev": true, "requires": { "unique-slug": "^2.0.0" } }, "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.1.tgz", + "integrity": "sha512-n9cU6+gITaVu7VGj1Z8feKMmfAjEAQGhwD9fE3zvpRRa0wEIx8ODYkVGfSc94M2OX00tUFV8wH3zYbm1I8mxFg==", "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } }, "universalify": { "version": "0.1.1", @@ -11499,15 +13560,15 @@ } }, "upath": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", - "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", + "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", "dev": true }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", "requires": { "punycode": "^2.1.0" } @@ -11537,37 +13598,41 @@ } }, "use": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", - "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "dev": true }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "useragent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz", + "integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==", "dev": true, "requires": { - "inherits": "2.0.1" + "lru-cache": "4.1.x", + "tmp": "0.0.x" }, "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", - "dev": true + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } } } }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -11587,38 +13652,31 @@ "dev": true, "optional": true }, - "uws": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", - "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", - "dev": true, - "optional": true - }, "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", "dev": true, "requires": { - "user-home": "^1.1.1" + "homedir-polyfill": "^1.0.1" } }, - "vali-date": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/vali-date/-/vali-date-1.0.0.tgz", - "integrity": "sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY=", - "dev": true - }, "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -11641,16 +13699,6 @@ "replace-ext": "0.0.1" } }, - "vinyl-assign": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/vinyl-assign/-/vinyl-assign-1.2.1.tgz", - "integrity": "sha1-TRmIkbVRWRHXcajNnFSApGoHSkU=", - "dev": true, - "requires": { - "object-assign": "^4.0.1", - "readable-stream": "^2.0.0" - } - }, "vinyl-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.1.tgz", @@ -11675,14 +13723,11 @@ "vinyl": "^1.1.0" }, "dependencies": { - "first-chunk-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", - "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true }, "strip-bom": { "version": "2.0.0", @@ -11693,124 +13738,167 @@ "is-utf8": "^0.2.0" } }, - "strip-bom-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz", - "integrity": "sha1-+H217yYT9paKpUWr/h7HKLaoKco=", + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "first-chunk-stream": "^2.0.0", - "strip-bom": "^2.0.0" + "clone": "^1.0.0", + "clone-stats": "^0.0.1", + "replace-ext": "0.0.1" } + } + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "dependencies": { + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true }, "vinyl": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", - "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } } } }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", + "vinyl-source-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz", + "integrity": "sha1-84pa+53R6Ttl1VBGmsYYKsT1S44=", "dev": true, "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" + "through2": "^2.0.3", + "vinyl": "^2.1.0" }, "dependencies": { "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", "dev": true }, - "graceful-fs": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", - "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", - "dev": true, - "requires": { - "natives": "^1.1.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", "dev": true }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true }, "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } } } }, - "vinyl-source-stream": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz", - "integrity": "sha1-YrU6E1YQqJbpjKlr7jqH8Aio54A=", + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", "dev": true, "requires": { - "through2": "^2.0.3", - "vinyl": "^0.4.3" + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" }, "dependencies": { "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", "dev": true, "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" } } } @@ -11825,13 +13913,10 @@ } }, "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz", + "integrity": "sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==", + "dev": true }, "void-elements": { "version": "2.0.1", @@ -11839,59 +13924,90 @@ "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "dev": true }, - "watchpack": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", - "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "vue-eslint-parser": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz", + "integrity": "sha512-ZezcU71Owm84xVF6gfurBQUGg8WQ+WZGxgDEQu1IHFBZNx7BFZg3L1yHxrCBNNwbwFtE1GuvfJKMtb6Xuwc/Bw==", "dev": true, "requires": { - "chokidar": "^2.0.2", - "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "debug": "^3.1.0", + "eslint-scope": "^3.7.1", + "eslint-visitor-keys": "^1.0.0", + "espree": "^3.5.2", + "esquery": "^1.0.0", + "lodash": "^4.17.4" }, "dependencies": { - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" + "acorn": "^3.0.4" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } } }, - "chokidar": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", - "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.0", - "braces": "^2.3.0", - "fsevents": "^1.2.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.1", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "lodash.debounce": "^4.0.8", - "normalize-path": "^2.1.1", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.0.0", - "upath": "^1.0.5" + "ms": "^2.1.1" } }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { - "is-extglob": "^2.1.1" + "acorn": "^5.5.0", + "acorn-jsx": "^3.0.0" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true } } }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha1-S8EsLr6KonenHx0/FNaFx7RGzQA=", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, "webidl-conversions": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz", @@ -11900,17 +14016,17 @@ "optional": true }, "webpack": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.19.1.tgz", - "integrity": "sha512-j7Q/5QqZRqIFXJvC0E59ipLV5Hf6lAnS3ezC3I4HMUybwEDikQBVad5d+IpPtmaQPQArvgUZLXIN6lWijHBn4g==", + "version": "4.32.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.32.0.tgz", + "integrity": "sha512-ofFq9jjAn4HRzlmkcZZrjijbRZcqDw+mM9KrjKd0r6lS0qxyZ7jzICzhphGafXL62dGdjP7TgMK9mZeMLUgZgw==", "dev": true, "requires": { - "@webassemblyjs/ast": "1.7.6", - "@webassemblyjs/helper-module-context": "1.7.6", - "@webassemblyjs/wasm-edit": "1.7.6", - "@webassemblyjs/wasm-parser": "1.7.6", - "acorn": "^5.6.2", - "acorn-dynamic-import": "^3.0.0", + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.0.5", + "acorn-dynamic-import": "^4.0.0", "ajv": "^6.1.0", "ajv-keywords": "^3.1.0", "chrome-trace-event": "^1.0.0", @@ -11924,23 +14040,17 @@ "mkdirp": "~0.5.0", "neo-async": "^2.5.0", "node-libs-browser": "^2.0.0", - "schema-utils": "^0.4.4", + "schema-utils": "^1.0.0", "tapable": "^1.1.0", - "uglifyjs-webpack-plugin": "^1.2.4", + "terser-webpack-plugin": "^1.1.0", "watchpack": "^1.5.0", - "webpack-sources": "^1.2.0" + "webpack-sources": "^1.3.0" }, "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, "ajv": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz", - "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz", + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -11949,6 +14059,22 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.0.tgz", + "integrity": "sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==", + "dev": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", @@ -11966,7 +14092,7 @@ "webpack-sources": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.3.0.tgz", - "integrity": "sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==", + "integrity": "sha1-KijcufH0X+lg2PFJMlK17mUw+oU=", "dev": true, "requires": { "source-list-map": "^2.0.0", @@ -11976,7 +14102,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -11991,57 +14117,94 @@ "tr46": "~0.0.1" } }, - "when": { - "version": "3.7.8", - "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", - "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", - "dev": true, - "optional": true - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", "dev": true, "requires": { "isexe": "^2.0.0" } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", "dev": true }, - "with-callback": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz", - "integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE=", - "dev": true, - "optional": true - }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true, - "optional": true + "dev": true }, "worker-farm": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", - "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "dev": true, "requires": { "errno": "~0.1.7" } }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, "xml-name-validator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", @@ -12049,12 +14212,11 @@ "dev": true, "optional": true }, - "xregexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", - "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", - "dev": true, - "optional": true + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true }, "xtend": { "version": "4.0.1", @@ -12063,9 +14225,9 @@ "dev": true }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { @@ -12075,33 +14237,144 @@ "dev": true }, "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", "dev": true, "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" }, "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } } } }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + }, "yauzl": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", - "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", "dev": true, "requires": { "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.0.1" + "fd-slicer": "~1.1.0" } }, "yeast": { @@ -12109,6 +14382,20 @@ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", "dev": true + }, + "yup": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.27.0.tgz", + "integrity": "sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ==", + "dev": true, + "requires": { + "@babel/runtime": "^7.0.0", + "fn-name": "~2.0.1", + "lodash": "^4.17.11", + "property-expr": "^1.5.0", + "synchronous-promise": "^2.0.6", + "toposort": "^2.0.2" + } } } } diff --git a/package.json b/package.json index 9c46f53eb..ecf5e9fc5 100644 --- a/package.json +++ b/package.json @@ -27,55 +27,68 @@ "jsdelivr": "lib/browser/neo4j-web.js", "types": "types/index.d.ts", "devDependencies": { - "async": "^2.4.0", - "babel-core": "^6.26.3", - "babel-plugin-transform-runtime": "^6.23.0", - "babel-preset-env": "^1.6.1", - "babel-register": "^6.26.0", - "babelify": "^7.3.0", - "browserify": "^13.3.0", + "@babel/core": "^7.4.4", + "@babel/plugin-transform-runtime": "^7.4.4", + "@babel/preset-env": "^7.4.4", + "@babel/register": "^7.4.4", + "async": "^3.0.0", + "babel-eslint": "^10.0.1", + "babelify": "^10.0.0", + "browserify": "^16.2.3", "browserify-transform-tools": "^1.7.0", - "esdoc": "^1.0.4", - "esdoc-importpath-plugin": "^1.0.1", + "esdoc": "^1.1.0", + "esdoc-importpath-plugin": "^1.0.2", "esdoc-standard-plugin": "^1.0.0", - "fs-extra": "^1.0.0", - "gulp": "^3.9.1", - "gulp-babel": "^6.1.3", + "eslint": "^5.16.0", + "eslint-config-standard": "^12.0.0", + "eslint-plugin-import": "^2.17.2", + "eslint-plugin-jasmine": "^2.10.1", + "eslint-plugin-node": "^9.0.1", + "eslint-plugin-promise": "^4.1.1", + "eslint-plugin-standard": "^4.0.0", + "fancy-log": "^1.3.3", + "fs-extra": "^8.0.1", + "gulp": "^4.0.2", + "gulp-babel": "^8.0.0", "gulp-batch": "^1.0.5", - "gulp-decompress": "^1.2.0", + "gulp-decompress": "^2.0.2", "gulp-download": "^0.0.1", - "gulp-file": "^0.3.0", - "gulp-install": "^0.6.0", - "gulp-jasmine": "^2.1.0", - "gulp-replace": "^0.5.4", - "gulp-typescript": "^3.1.7", - "gulp-uglify": "^1.4.2", - "gulp-util": "^3.0.6", - "gulp-watch": "^4.3.5", - "jasmine-console-reporter": "^2.0.1", - "karma": "^2.0.3", + "gulp-file": "^0.4.0", + "gulp-install": "^1.1.0", + "gulp-jasmine": "^4.0.0", + "gulp-replace": "^1.0.0", + "gulp-typescript": "^5.0.1", + "gulp-uglify": "^3.0.2", + "gulp-watch": "^5.0.1", + "husky": "^2.3.0", + "jasmine-console-reporter": "^3.1.0", + "karma": "^4.1.0", + "karma-browserify": "^6.0.0", "karma-chrome-launcher": "^2.2.0", "karma-edge-launcher": "^0.4.2", "karma-firefox-launcher": "^1.1.0", "karma-ie-launcher": "^1.0.0", - "karma-jasmine": "^1.1.2", + "karma-jasmine": "^2.0.1", + "karma-source-map-support": "^1.4.0", "karma-spec-reporter": "^0.0.32", - "lodash": "^4.17.4", - "lolex": "^1.5.2", + "lint-staged": "^8.1.7", + "lodash": "^4.17.11", + "lolex": "^4.0.1", "minimist": "^1.2.0", - "mustache": "^2.3.0", - "run-sequence": "^1.1.4", - "semver": "^5.3.0", - "through2": "~2.0.0", - "tmp": "0.0.31", - "typescript": "^2.3.4", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0", - "webpack": "^4.19.1" + "mustache": "^3.0.1", + "prettier-eslint": "^8.8.2", + "prettier-eslint-cli": "^4.7.1", + "run-sequence": "^2.2.1", + "semver": "^6.0.0", + "tmp": "0.1.0", + "typescript": "^3.4.5", + "vinyl-buffer": "^1.0.1", + "vinyl-source-stream": "^2.0.0", + "webpack": "^4.32.0" }, "dependencies": { - "babel-runtime": "^6.26.0", - "text-encoding": "^0.6.4", - "uri-js": "^4.2.1" + "@babel/runtime": "^7.4.4", + "text-encoding": "^0.7.0", + "uri-js": "^4.2.2" } } diff --git a/support/inject-browser-transform.js b/support/inject-browser-transform.js new file mode 100644 index 000000000..906eb5f8a --- /dev/null +++ b/support/inject-browser-transform.js @@ -0,0 +1,20 @@ +const transformTools = require('browserify-transform-tools') + +const nodeRequire = '/node' +const browserRequire = '/browser' + +module.exports = transformTools.makeRequireTransform( + 'nodeToBrowserRequireTransform', + { evaluateArguments: true }, + function (args, opts, cb) { + const requireArg = args[0] + const endsWithNodeRequire = + requireArg.slice(-nodeRequire.length) === nodeRequire + if (endsWithNodeRequire) { + const newRequireArg = requireArg.replace(nodeRequire, browserRequire) + return cb(null, "require('" + newRequireArg + "')") + } else { + return cb() + } + } +) diff --git a/test/browser/karma-chrome.conf.js b/test/browser/karma-chrome.conf.js index a7a589a30..524aba97d 100644 --- a/test/browser/karma-chrome.conf.js +++ b/test/browser/karma-chrome.conf.js @@ -16,19 +16,31 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -module.exports = function(config) { +module.exports = function (config) { config.set({ - frameworks: ['jasmine'], basePath: '../../', - files: ['build/browser/neo4j-web.test.js'], + browserify: { + debug: true, + transform: ['babelify', './support/inject-browser-transform'] + }, + files: [ + 'src/*.js', + 'src/**/!(node)/*.js', + 'test/**/!(node)/!(examples).test.js', + ], + preprocessors: { + 'src/**/*.js': ['browserify'], + 'test/**/*.test.js': ['browserify'] + }, + frameworks: ['browserify', 'source-map-support', 'jasmine'], reporters: ['spec'], - port: 9876, // karma web server port + port: 9876, // karma web server port colors: true, logLevel: config.LOG_DEBUG, browsers: ['ChromeHeadless'], autoWatch: false, singleRun: true, concurrency: 1, - browserNoActivityTimeout: 30 * 60 * 1000, + browserNoActivityTimeout: 30 * 60 * 1000 }) -}; +} diff --git a/test/browser/karma-firefox.conf.js b/test/browser/karma-firefox.conf.js index 6e311687f..87c6799ac 100644 --- a/test/browser/karma-firefox.conf.js +++ b/test/browser/karma-firefox.conf.js @@ -16,13 +16,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -module.exports = function(config) { +module.exports = function (config) { config.set({ - frameworks: ['jasmine'], basePath: '../../', - files: ['build/browser/neo4j-web.test.js'], + browserify: { + debug: true, + transform: ['babelify', './support/inject-browser-transform'] + }, + files: [ + 'src/*.js', + 'src/**/!(node)/*.js', + 'test/**/!(node)/!(examples).test.js', + ], + preprocessors: { + 'src/**/*.js': ['browserify'], + 'test/**/*.test.js': ['browserify'] + }, + frameworks: ['browserify', 'source-map-support', 'jasmine'], reporters: ['spec'], - port: 9876, // karma web server port + port: 9876, // karma web server port colors: true, logLevel: config.LOG_DEBUG, browsers: ['FirefoxHeadless'], @@ -33,11 +45,11 @@ module.exports = function(config) { customLaunchers: { FirefoxHeadless: { base: 'Firefox', - flags: [ '-headless' ], + flags: ['-headless'], prefs: { 'network.websocket.max-connections': 256 // as in Chrome } - }, - }, + } + } }) -}; +} diff --git a/test/v1/result.test.js b/test/v1/result.test.js index 85f6e1b47..c8e71dc57 100644 --- a/test/v1/result.test.js +++ b/test/v1/result.test.js @@ -90,9 +90,9 @@ describe('result stream', () => { const stack = err.stack; // Then - const contains_fn_a = /at fn_a \(.*?\/result.test.js:\d+:\d+\)/.test(stack); - const contains_fn_b = /at fn_b \(.*?\/result.test.js:\d+:\d+\)/.test(stack); - const contains_fn_c = /at fn_c \(.*?\/result.test.js:\d+:\d+\)/.test(stack); + const contains_fn_a = /fn_a \(.*?\/result.test.js:\d+:\d+\)/.test(stack); + const contains_fn_b = /fn_b \(.*?\/result.test.js:\d+:\d+\)/.test(stack); + const contains_fn_c = /fn_c \(.*?\/result.test.js:\d+:\d+\)/.test(stack); expect(contains_fn_a).toBeTruthy(); expect(contains_fn_b).toBeTruthy(); From 7a85f84acc8fbbcf25528f75e926e5e23430849b Mon Sep 17 00:00:00 2001 From: Ali Ince Date: Mon, 20 May 2019 15:06:13 +0100 Subject: [PATCH 3/5] Introduce eslint and prettier --- .eslintignore | 4 + .eslintrc.json | 20 + CONTRIBUTING.md | 5 - ISSUE_TEMPLATE.md | 13 +- README.md | 267 +- esdoc.json | 4 +- examples/neo4j.html | 359 +- examples/node.js | 86 +- package.json | 13 + src/index.js | 2 +- src/v1/driver.js | 246 +- src/v1/error.js | 21 +- src/v1/graph-types.js | 141 +- src/v1/index.js | 140 +- src/v1/integer.js | 825 ++-- src/v1/internal/bolt-protocol-v1.js | 118 +- src/v1/internal/bolt-protocol-v2.js | 17 +- src/v1/internal/bolt-protocol-v3.js | 84 +- src/v1/internal/bookmark.js | 89 +- src/v1/internal/browser/browser-buf.js | 51 +- src/v1/internal/browser/browser-channel.js | 261 +- .../browser/browser-host-name-resolver.js | 7 +- src/v1/internal/browser/browser-utf8.js | 28 +- src/v1/internal/browser/index.js | 16 +- src/v1/internal/buf/base-buf.js | 297 +- src/v1/internal/buf/combined-buf.js | 39 +- src/v1/internal/channel-config.js | 83 +- src/v1/internal/chunking.js | 167 +- src/v1/internal/connection-error-handler.js | 47 +- src/v1/internal/connection-holder.js | 100 +- src/v1/internal/connection-providers.js | 415 +- src/v1/internal/connection.js | 408 +- src/v1/internal/connectivity-verifier.js | 65 +- src/v1/internal/constants.js | 9 +- src/v1/internal/http/http-driver.js | 30 +- src/v1/internal/http/http-request-runner.js | 194 +- .../internal/http/http-response-converter.js | 436 +- src/v1/internal/http/http-session-tracker.js | 29 +- src/v1/internal/http/http-session.js | 167 +- ...least-connected-load-balancing-strategy.js | 58 +- src/v1/internal/load-balancing-strategy.js | 9 +- src/v1/internal/logger.js | 134 +- src/v1/internal/node/index.js | 16 +- src/v1/internal/node/node-buf.js | 71 +- src/v1/internal/node/node-channel.js | 625 +-- .../internal/node/node-host-name-resolver.js | 22 +- src/v1/internal/node/node-utf8.js | 95 +- src/v1/internal/packstream-v1.js | 758 ++-- src/v1/internal/packstream-v2.js | 498 ++- src/v1/internal/pool-config.js | 59 +- src/v1/internal/pool.js | 235 +- src/v1/internal/protocol-handshaker.js | 91 +- src/v1/internal/rediscovery.js | 68 +- src/v1/internal/request-message.js | 135 +- .../resolver/base-host-name-resolver.js | 9 +- .../resolver/configured-custom-resolver.js | 31 +- src/v1/internal/round-robin-array-index.js | 17 +- .../round-robin-load-balancing-strategy.js | 33 +- src/v1/internal/routing-table.js | 57 +- src/v1/internal/routing-util.js | 156 +- src/v1/internal/server-address.js | 56 +- src/v1/internal/server-version.js | 93 +- src/v1/internal/stream-observer.js | 121 +- src/v1/internal/temporal-util.js | 502 ++- src/v1/internal/transaction-executor.js | 235 +- src/v1/internal/tx-config.js | 53 +- src/v1/internal/url-util.js | 157 +- src/v1/internal/util.js | 106 +- src/v1/record.js | 76 +- src/v1/result-summary.js | 206 +- src/v1/result.js | 127 +- src/v1/routing-driver.js | 117 +- src/v1/session.js | 220 +- src/v1/spatial-types.js | 37 +- src/v1/temporal-types.js | 350 +- src/v1/transaction.js | 298 +- src/version.js | 2 +- test/browser/jasmine-runner.html | 45 +- test/browser/karma-chrome.conf.js | 2 +- test/browser/karma-edge.conf.js | 8 +- test/browser/karma-firefox.conf.js | 2 +- test/browser/karma-ie.conf.js | 8 +- test/internal/bolt-protocol-v1.test.js | 221 +- test/internal/bolt-protocol-v3.test.js | 21 +- test/internal/bolt-stub.js | 120 +- test/internal/bookmark.test.js | 162 +- test/internal/browser/browser-channel.test.js | 242 +- .../browser-host-name-resolver.test.js | 34 +- test/internal/buf.test.js | 174 +- test/internal/channel-config.test.js | 213 +- test/internal/chunking.test.js | 134 +- .../internal/connection-error-handler.test.js | 118 +- test/internal/connection-holder.test.js | 276 +- test/internal/connection-providers.test.js | 1010 ++--- test/internal/connection.test.js | 670 +-- test/internal/connectivity-verifier.test.js | 22 +- test/internal/dummy-channel.js | 39 +- test/internal/fake-connection.js | 71 +- test/internal/http/http-driver.test.js | 624 +-- .../internal/http/http-request-runner.test.js | 528 ++- .../http/http-session-tracker.test.js | 92 +- test/internal/http/http-session.test.js | 39 +- ...-connected-load-balancing-strategy.test.js | 179 +- test/internal/logger.test.js | 225 +- .../node/direct.driver.boltkit.test.js | 586 +-- .../node/node-host-name-resolver.test.js | 114 +- test/internal/node/package.test.js | 86 +- .../node/routing.driver.boltkit.test.js | 3645 ++++++++++------- test/internal/node/tls.test.js | 446 +- test/internal/packstream-v1.test.js | 82 +- test/internal/pool-config.test.js | 98 +- test/internal/pool.test.js | 1026 ++--- test/internal/protocol-handshaker.test.js | 102 +- test/internal/rediscovery.test.js | 230 +- test/internal/request-message.test.js | 197 +- test/internal/round-robin-array-index.test.js | 74 +- ...ound-robin-load-balancing-strategy.test.js | 86 +- test/internal/routing-table.test.js | 239 +- test/internal/routing-util.test.js | 504 ++- test/internal/server-address.test.js | 59 +- test/internal/server-version.test.js | 260 +- test/internal/shared-neo4j.js | 312 +- test/internal/stream-observer.test.js | 233 +- test/internal/temporal-util.test.js | 619 +-- test/internal/test-utils.js | 18 +- test/internal/timers-util.js | 57 +- test/internal/transaction-executor.test.js | 572 +-- test/internal/tx-config.test.js | 106 +- test/internal/url-util.test.js | 600 +-- test/internal/utf8.test.js | 174 +- test/internal/util.test.js | 310 +- test/types/index.test.ts | 143 +- test/types/v1/driver.test.ts | 152 +- test/types/v1/error.test.ts | 22 +- test/types/v1/graph-types.test.ts | 114 +- test/types/v1/index.test.ts | 141 +- test/types/v1/integer.test.ts | 316 +- test/types/v1/record.test.ts | 36 +- test/types/v1/result-summary.test.ts | 123 +- test/types/v1/result.test.ts | 32 +- test/types/v1/session.test.ts | 209 +- test/types/v1/spatial-types.test.ts | 44 +- test/types/v1/temporal-types.test.ts | 328 +- test/types/v1/transaction.test.ts | 100 +- test/v1/auth.test.js | 41 +- test/v1/bolt-v3.test.js | 627 +-- test/v1/driver.test.js | 578 +-- test/v1/examples.test.js | 803 ++-- test/v1/integer.test.js | 100 +- test/v1/record.test.js | 94 +- test/v1/result.test.js | 129 +- test/v1/routing-driver.test.js | 60 +- test/v1/session.test.js | 1664 ++++---- test/v1/spatial-types.test.js | 391 +- test/v1/stress.test.js | 653 +-- test/v1/summary.test.js | 184 +- test/v1/temporal-types.test.js | 2121 ++++++---- test/v1/transaction.test.js | 843 ++-- test/v1/types.test.js | 390 +- tsconfig.json | 2 +- types/index.d.ts | 6 +- types/v1/driver.d.ts | 90 +- types/v1/error.d.ts | 14 +- types/v1/graph-types.d.ts | 78 +- types/v1/index.d.ts | 268 +- types/v1/integer.d.ts | 138 +- types/v1/record.d.ts | 22 +- types/v1/result-summary.d.ts | 116 +- types/v1/result.d.ts | 20 +- types/v1/session.d.ts | 42 +- types/v1/spatial-types.d.ts | 20 +- types/v1/statement-runner.d.ts | 10 +- types/v1/temporal-types.d.ts | 154 +- types/v1/transaction.d.ts | 12 +- 174 files changed, 21884 insertions(+), 16896 deletions(-) create mode 100644 .eslintignore create mode 100644 .eslintrc.json diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..ae7b06ea0 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +build +docs +lib +node_modules diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..b85a56b5c --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "parser": "babel-eslint", + "env": { + "browser": true, + "es6": true, + "node": true, + "jasmine": true + }, + "extends": "standard", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" + }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + "rules": {}, + "plugins": ["jasmine"] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50c05b60f..0cd82218c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,7 +9,6 @@ If you're not already a member, sign up! We love our community and wouldn't be where we are without you. - ## Need to raise an issue? Where you raise an issue depends largely on the nature of the problem. @@ -34,7 +33,6 @@ Include as much information as you can in any request you make: - What errors are you seeing? - What solutions have you tried already? - ## Want to contribute? If you want to contribute a pull request, we have a little bit of process you'll need to follow: @@ -50,7 +48,6 @@ We can't guarantee that we'll accept pull requests and may ask you to make some Occasionally, we might also have logistical, commercial, or legal reasons why we can't accept your work but we'll try to find an alternative way for you to contribute in that case. Remember that many community members have become regular contributors and some are now even Neo employees! - ## Got an idea for a new project? If you have an idea for a new tool or library, start by talking to other people in the community. @@ -58,8 +55,6 @@ Chances are that someone has a similar idea or may have already started working The best software comes from getting like minds together to solve a problem. And we'll do our best to help you promote and co-ordinate your Neo ecosystem projects. - ## Further reading If you want to find out more about how you can contribute, head over to our website for [more information](http://neo4j.com/developer/contributing-code/). - diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 5a6a6f479..bba0133a1 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -9,7 +9,7 @@ If you simply want to get started or have a question on how to use a particular [StackOverflow](http://stackoverflow.com/questions/tagged/neo4j) also hosts a ton of questions and might already have a discussion around your problem. Make sure you have a look there too. -If you want to make a feature request, please prefix your issue title with `[Feature Request]` so that it is clear to us. +If you want to make a feature request, please prefix your issue title with `[Feature Request]` so that it is clear to us. If you have a bug report however, please continue reading. To help us understand your issue, please specify important details, primarily: @@ -32,17 +32,22 @@ I got connection reset by peer errors. **Neo4j Version:** 3.4.10 Community **Neo4j Mode**: Single instance **Driver version**: JS driver 1.7.1 -**Operating System:** Ubuntu 16.10 on AWS +**Operating System:** Ubuntu 16.10 on AWS ### Steps to reproduce + 1. Start Neo4j on a AWS instance 2. Run a query with the driver 3. Put the driver idle for 2h 4. Run another query + ### Expected behavior + The second query shall run successfully + ### Actual behavior + The client failed to run the second query with a `connection reset by peer` stacktrace. -*attach the stacktrace* +_attach the stacktrace_ Meanwhile, in the server log, I found this stacktrace that happened at the same time when the driver failed. -*attach the stacktrace* +_attach the stacktrace_ diff --git a/README.md b/README.md index 14a47c431..60d878368 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,25 @@ # Neo4j Driver for JavaScript - A database driver for Neo4j 3.0.0+. Resources to get you started: -* [Detailed docs](http://neo4j.com/docs/api/javascript-driver/current/). -* [Sample small project using the driver](https://github.com/neo4j-examples/movies-javascript-bolt) -* [Sample application using the driver](https://github.com/neo4j-examples/neo4j-movies-template) -* [Neo4j Manual](https://neo4j.com/docs/) -* [Neo4j Refcard](https://neo4j.com/docs/cypher-refcard/current/) +- [Detailed docs](http://neo4j.com/docs/api/javascript-driver/current/). +- [Sample small project using the driver](https://github.com/neo4j-examples/movies-javascript-bolt) +- [Sample application using the driver](https://github.com/neo4j-examples/neo4j-movies-template) +- [Neo4j Manual](https://neo4j.com/docs/) +- [Neo4j Refcard](https://neo4j.com/docs/cypher-refcard/current/) ## Include module in Node.js application Stable channel: + ```shell npm install neo4j-driver ``` Pre-release channel: + ```shell npm install neo4j-driver@next ``` @@ -27,12 +28,13 @@ Please note that `@next` only points to pre-releases that are not suitable for p To get the latest stable release omit `@next` part altogether or use `@latest` instead. ```javascript -var neo4j = require('neo4j-driver').v1; +var neo4j = require('neo4j-driver').v1 ``` + Driver instance should be closed when Node.js application exits: ```javascript -driver.close(); +driver.close() ``` otherwise application shutdown might hang or it might exit with a non-zero exit code. @@ -55,181 +57,207 @@ It can be included in an HTML page using one of the following tags: - ``` This will make a global `neo4j` object available, where you can access the `v1` API at `neo4j.v1`: ```javascript -var driver = neo4j.v1.driver("bolt://localhost", neo4j.v1.auth.basic("neo4j", "neo4j")); +var driver = neo4j.v1.driver( + 'bolt://localhost', + neo4j.v1.auth.basic('neo4j', 'neo4j') +) ``` -It is not required to explicitly close the driver on a web page. Web browser should gracefully close all open +It is not required to explicitly close the driver on a web page. Web browser should gracefully close all open WebSockets when the page is unloaded. However, driver instance should be explicitly closed when it's lifetime is not the same as the lifetime of the web page: - + ```javascript -driver.close(); +driver.close() ``` ## Usage examples Driver lifecycle: + ```javascript // Create a driver instance, for the user neo4j with password neo4j. // It should be enough to have a single driver per database per application. -var driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j")); +var driver = neo4j.driver( + 'bolt://localhost', + neo4j.auth.basic('neo4j', 'neo4j') +) // Close the driver when application exits. // This closes all used network connections. -driver.close(); +driver.close() ``` Session API: + ```javascript // Create a session to run Cypher statements in. // Note: Always make sure to close sessions when you are done using them! -var session = driver.session(); +var session = driver.session() // Run a Cypher statement, reading the result in a streaming manner as records arrive: session - .run('MERGE (alice:Person {name : {nameParam} }) RETURN alice.name AS name', {nameParam: 'Alice'}) + .run('MERGE (alice:Person {name : {nameParam} }) RETURN alice.name AS name', { + nameParam: 'Alice' + }) .subscribe({ - onNext: function (record) { - console.log(record.get('name')); + onNext: function(record) { + console.log(record.get('name')) }, - onCompleted: function () { - session.close(); + onCompleted: function() { + session.close() }, - onError: function (error) { - console.log(error); + onError: function(error) { + console.log(error) } - }); + }) // or // the Promise way, where the complete result is collected before we act on it: session - .run('MERGE (james:Person {name : {nameParam} }) RETURN james.name AS name', {nameParam: 'James'}) - .then(function (result) { - result.records.forEach(function (record) { - console.log(record.get('name')); - }); - session.close(); + .run('MERGE (james:Person {name : {nameParam} }) RETURN james.name AS name', { + nameParam: 'James' + }) + .then(function(result) { + result.records.forEach(function(record) { + console.log(record.get('name')) + }) + session.close() + }) + .catch(function(error) { + console.log(error) }) - .catch(function (error) { - console.log(error); - }); ``` Transaction functions API: + ```javascript // Transaction functions provide a convenient API with minimal boilerplate and // retries on network fluctuations and transient errors. Maximum retry time is // configured on the driver level and is 30 seconds by default: -neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {maxTransactionRetryTime: 30000}); +neo4j.driver('bolt://localhost', neo4j.auth.basic('neo4j', 'neo4j'), { + maxTransactionRetryTime: 30000 +}) // It is possible to execute read transactions that will benefit from automatic // retries on both single instance ('bolt' URI scheme) and Causal Cluster // ('bolt+routing' URI scheme) and will get automatic load balancing in cluster deployments -var readTxResultPromise = session.readTransaction(function (transaction) { +var readTxResultPromise = session.readTransaction(function(transaction) { // used transaction will be committed automatically, no need for explicit commit/rollback - var result = transaction.run('MATCH (person:Person) RETURN person.name AS name'); + var result = transaction.run( + 'MATCH (person:Person) RETURN person.name AS name' + ) // at this point it is possible to either return the result or process it and return the // result of processing it is also possible to run more statements in the same transaction - return result; -}); + return result +}) // returned Promise can be later consumed like this: -readTxResultPromise.then(function (result) { - session.close(); - console.log(result.records); -}).catch(function (error) { - console.log(error); -}); +readTxResultPromise + .then(function(result) { + session.close() + console.log(result.records) + }) + .catch(function(error) { + console.log(error) + }) // It is possible to execute write transactions that will benefit from automatic retries // on both single instance ('bolt' URI scheme) and Causal Cluster ('bolt+routing' URI scheme) -var writeTxResultPromise = session.writeTransaction(function (transaction) { +var writeTxResultPromise = session.writeTransaction(function(transaction) { // used transaction will be committed automatically, no need for explicit commit/rollback - var result = transaction.run('MERGE (alice:Person {name : \'Alice\' }) RETURN alice.name AS name'); + var result = transaction.run( + "MERGE (alice:Person {name : 'Alice' }) RETURN alice.name AS name" + ) // at this point it is possible to either return the result or process it and return the // result of processing it is also possible to run more statements in the same transaction - return result.records.map(function (record) { - return record.get('name'); - }); -}); + return result.records.map(function(record) { + return record.get('name') + }) +}) // returned Promise can be later consumed like this: -writeTxResultPromise.then(function (namesArray) { - session.close(); - console.log(namesArray); -}).catch(function (error) { - console.log(error); -}); +writeTxResultPromise + .then(function(namesArray) { + session.close() + console.log(namesArray) + }) + .catch(function(error) { + console.log(error) + }) ``` Explicit transactions API: + ```javascript // run statement in a transaction -var tx = session.beginTransaction(); - -tx.run("MERGE (bob:Person {name : {nameParam} }) RETURN bob.name AS name", {nameParam: 'Bob'}) - .subscribe({ - onNext: function (record) { - console.log(record.get('name')); - }, - onCompleted: function () { - console.log('First query completed'); - }, - onError: function (error) { - console.log(error); - } - }); - -tx.run("MERGE (adam:Person {name : {nameParam} }) RETURN adam.name AS name", {nameParam: 'Adam'}) - .subscribe({ - onNext: function (record) { - console.log(record.get('name')); - }, - onCompleted: function () { - console.log('Second query completed'); - }, - onError: function (error) { - console.log(error); - } - }); +var tx = session.beginTransaction() + +tx.run('MERGE (bob:Person {name : {nameParam} }) RETURN bob.name AS name', { + nameParam: 'Bob' +}).subscribe({ + onNext: function(record) { + console.log(record.get('name')) + }, + onCompleted: function() { + console.log('First query completed') + }, + onError: function(error) { + console.log(error) + } +}) + +tx.run('MERGE (adam:Person {name : {nameParam} }) RETURN adam.name AS name', { + nameParam: 'Adam' +}).subscribe({ + onNext: function(record) { + console.log(record.get('name')) + }, + onCompleted: function() { + console.log('Second query completed') + }, + onError: function(error) { + console.log(error) + } +}) //decide if the transaction should be committed or rolled back -var success = false; +var success = false if (success) { - tx.commit() - .subscribe({ - onCompleted: function () { - // this transaction is now committed and session can be closed - session.close(); - }, - onError: function (error) { - console.log(error); - } - }); + tx.commit().subscribe({ + onCompleted: function() { + // this transaction is now committed and session can be closed + session.close() + }, + onError: function(error) { + console.log(error) + } + }) } else { //transaction is rolled black and nothing is created in the database - console.log('rolled back'); - tx.rollback(); + console.log('rolled back') + tx.rollback() } ``` Subscriber API allows following combinations of `onNext`, `onCompleted` and `onError` callback invocations: - * zero or more `onNext` followed by `onCompleted` when operation was successful. `onError` will not be invoked - in this case - * zero or more `onNext` followed by `onError` when operation failed. Callback `onError` might be invoked after - couple `onNext` invocations because records are streamed lazily by the database. `onCompleted` will not be invoked - in this case + +- zero or more `onNext` followed by `onCompleted` when operation was successful. `onError` will not be invoked + in this case +- zero or more `onNext` followed by `onError` when operation failed. Callback `onError` might be invoked after + couple `onNext` invocations because records are streamed lazily by the database. `onCompleted` will not be invoked + in this case ## Parallelization + In a single session, multiple queries will be executed serially. In order to parallelize queries, multiple sessions are required. ## Building @@ -249,10 +277,10 @@ Tests **require** latest [Boltkit](https://github.com/neo4j-contrib/boltkit) to To run tests against "default" Neo4j version: ./runTests.sh - + To run tests against specified Neo4j version: - - ./runTests.sh '-e 3.1.3' + +./runTests.sh '-e 3.1.3' Simple `npm test` can also be used if you already have a running version of a compatible Neo4j server. @@ -262,50 +290,56 @@ the source code: gulp watch-n-test ### Testing on windows + Running tests on windows requires PhantomJS installed and its bin folder added in windows system variable `Path`. To run the same test suite, run `.\runTest.ps1` instead in powershell with admin right. The admin right is required to start/stop Neo4j properly as a system service. While there is no need to grab admin right if you are running tests against an existing Neo4j server using `npm test`. ## A note on numbers and the Integer type + The Neo4j type system includes 64-bit integer values. -However, JavaScript can only safely represent integers between `-(2``53`` - 1)` and `(2``53`` - 1)`. +However, JavaScript can only safely represent integers between `-(2``53``- 1)` and `(2``53``- 1)`. In order to support the full Neo4j type system, the driver will not automatically convert to javascript integers. Any time the driver receives an integer value from Neo4j, it will be represented with an internal integer type by the driver. ### Write integers + Number written directly e.g. `session.run("CREATE (n:Node {age: {age}})", {age: 22})` will be of type `Float` in Neo4j. To write the `age` as an integer the `neo4j.int` method should be used: ```javascript -var neo4j = require('neo4j-driver').v1; +var neo4j = require('neo4j-driver').v1 -session.run("CREATE (n {age: {myIntParam}})", {myIntParam: neo4j.int(22)}); +session.run('CREATE (n {age: {myIntParam}})', { myIntParam: neo4j.int(22) }) ``` To write integers larger than can be represented as JavaScript numbers, use a string argument to `neo4j.int`: ```javascript -session.run("CREATE (n {age: {myIntParam}})", {myIntParam: neo4j.int("9223372036854775807")}); +session.run('CREATE (n {age: {myIntParam}})', { + myIntParam: neo4j.int('9223372036854775807') +}) ``` ### Read integers -Since Integers can be larger than can be represented as JavaScript numbers, it is only safe to convert to JavaScript numbers if you know that they will not exceed `(2``53`` - 1)` in size. + +Since Integers can be larger than can be represented as JavaScript numbers, it is only safe to convert to JavaScript numbers if you know that they will not exceed `(2``53``- 1)` in size. In order to facilitate working with integers the driver include `neo4j.isInt`, `neo4j.integer.inSafeRange`, `neo4j.integer.toNumber`, and `neo4j.integer.toString`. ```javascript -var aSmallInteger = neo4j.int(123); +var aSmallInteger = neo4j.int(123) if (neo4j.integer.inSafeRange(aSmallInteger)) { - var aNumber = aSmallInteger.toNumber(); + var aNumber = aSmallInteger.toNumber() } ``` If you will be handling integers larger than that, you should convert them to strings: ```javascript -var aLargerInteger = neo4j.int("9223372036854775807"); +var aLargerInteger = neo4j.int('9223372036854775807') if (!neo4j.integer.inSafeRange(aLargerInteger)) { - var integerAsString = aLargerInteger.toString(); + var integerAsString = aLargerInteger.toString() } ``` @@ -317,6 +351,9 @@ values being returned if the database contains integer numbers outside of the ra To enable potentially lossy integer values use the driver's configuration object: ```javascript -var driver = neo4j.driver("bolt://localhost", neo4j.auth.basic("neo4j", "neo4j"), {disableLosslessIntegers: true}); +var driver = neo4j.driver( + 'bolt://localhost', + neo4j.auth.basic('neo4j', 'neo4j'), + { disableLosslessIntegers: true } +) ``` - diff --git a/esdoc.json b/esdoc.json index 83c8d96e4..bb7ebd865 100644 --- a/esdoc.json +++ b/esdoc.json @@ -23,9 +23,7 @@ "enable": false }, "accessor": { - "access": [ - "public" - ], + "access": ["public"], "autoPrivate": true }, "undocumentIdentifier": { diff --git a/examples/neo4j.html b/examples/neo4j.html index b630fbfea..753b54701 100644 --- a/examples/neo4j.html +++ b/examples/neo4j.html @@ -1,71 +1,71 @@ - + Cypher Runner for Neo4j Bolt Protocol -
-

Cypher Runner for New Remoting

-
-
- - + - +
- - -
+
+ + + + + + + + + + +
+ + + + + +
+ +
-
-
- - diff --git a/examples/node.js b/examples/node.js index b3b296bd8..a9611f8c2 100644 --- a/examples/node.js +++ b/examples/node.js @@ -16,61 +16,65 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -var neo4j = require('neo4j'); -var statement = ['MERGE (alice:Person {name:{name_a},age:{age_a}})', +var neo4j = require('neo4j') + +var statement = [ + 'MERGE (alice:Person {name:{name_a},age:{age_a}})', 'MERGE (bob:Person {name:{name_b},age:{age_b}})', 'CREATE UNIQUE (alice)-[alice_knows_bob:KNOWS]->(bob)', 'RETURN alice, bob, alice_knows_bob' -]; +] var params = { name_a: 'Alice', age_a: 33, name_b: 'Bob', age_b: 44 -}; +} -var driver = neo4j.driver("bolt://localhost"); +var driver = neo4j.driver('bolt://localhost') -var streamSession = driver.session(); -var streamResult = streamSession.run(statement.join(' '), params); +var streamSession = driver.session() +var streamResult = streamSession.run(statement.join(' '), params) streamResult.subscribe({ - onNext: function(record) { + onNext: function (record) { // On receipt of RECORD - for(var i in record) { - console.log(i); - console.log(record[i]); + for (var i in record) { + console.log(i) + console.log(record[i]) } - }, onCompleted: function() { - var summary = streamResult.summarize(); - //Print number of nodes created - console.log(''); - console.log(summary.updateStatistics.nodesCreated()); - streamSession.close(); - }, onError: function(error) { - console.log(error); + }, + onCompleted: function () { + var summary = streamResult.summarize() + // Print number of nodes created + console.log('') + console.log(summary.updateStatistics.nodesCreated()) + streamSession.close() + }, + onError: function (error) { + console.log(error) } -}); - -var promiseSession = driver.session(); -var promiseResult = promiseSession.run(statement.join(' '), params); -promiseResult.then(function(records) { - records.forEach(function(record) { - for(var i in record) { - console.log(i); - console.log(record[i]); - } - }); - var summary = promiseResult.summarize(); - //Print number of nodes created - console.log(''); - console.log(summary.updateStatistics.nodesCreated()); }) -.catch(function(error) { - console.log(error); -}) -.then(function(){ - promiseSession.close(); -}); + +var promiseSession = driver.session() +var promiseResult = promiseSession.run(statement.join(' '), params) +promiseResult + .then(function (records) { + records.forEach(function (record) { + for (var i in record) { + console.log(i) + console.log(record[i]) + } + }) + var summary = promiseResult.summarize() + // Print number of nodes created + console.log('') + console.log(summary.updateStatistics.nodesCreated()) + }) + .catch(function (error) { + console.log(error) + }) + .then(function () { + promiseSession.close() + }) diff --git a/package.json b/package.json index ecf5e9fc5..1f68ed384 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "url": "git://github.com/neo4j/neo4j-javascript-driver.git" }, "scripts": { + "lint": "eslint --fix --ext .js ./", + "format": "prettier-eslint '**/*.js' '**/*.json' '**/*.md' '**/*.ts' '**/*.html' --write", "test": "gulp test", "build": "gulp all", "start-neo4j": "gulp start-neo4j", @@ -19,6 +21,17 @@ "versionRelease": "gulp set --version $VERSION && npm version $VERSION --no-git-tag-version", "browser": "gulp browser && gulp test-browser" }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "*.{js,json,ts,md,html}": [ + "prettier-eslint --write", + "git add" + ] + }, "main": "lib/index.js", "browser": { "./lib/v1/internal/node/index.js": "./lib/v1/internal/browser/index.js" diff --git a/src/index.js b/src/index.js index 4f4942a75..5a8205b25 100644 --- a/src/index.js +++ b/src/index.js @@ -17,7 +17,7 @@ * limitations under the License. */ -import * as v1 from './v1/index'; +import * as v1 from './v1/index' export { v1 } export default v1 diff --git a/src/v1/driver.js b/src/v1/driver.js index 7ead03a28..25c01053d 100644 --- a/src/v1/driver.js +++ b/src/v1/driver.js @@ -17,36 +17,38 @@ * limitations under the License. */ -import Session from './session'; -import Pool from './internal/pool'; -import Connection from './internal/connection'; -import StreamObserver from './internal/stream-observer'; -import {newError, SERVICE_UNAVAILABLE} from './error'; -import {DirectConnectionProvider} from './internal/connection-providers'; -import Bookmark from './internal/bookmark'; -import ConnectivityVerifier from './internal/connectivity-verifier'; -import PoolConfig, {DEFAULT_ACQUISITION_TIMEOUT, DEFAULT_MAX_SIZE} from './internal/pool-config'; -import Logger from './internal/logger'; -import ConnectionErrorHandler from './internal/connection-error-handler'; -import {ACCESS_MODE_READ, ACCESS_MODE_WRITE} from './internal/constants'; - -const DEFAULT_MAX_CONNECTION_LIFETIME = 60 * 60 * 1000; // 1 hour +import Session from './session' +import Pool from './internal/pool' +import Connection from './internal/connection' +import { newError, SERVICE_UNAVAILABLE } from './error' +import { DirectConnectionProvider } from './internal/connection-providers' +import Bookmark from './internal/bookmark' +import ConnectivityVerifier from './internal/connectivity-verifier' +import PoolConfig, { + DEFAULT_ACQUISITION_TIMEOUT, + DEFAULT_MAX_SIZE +} from './internal/pool-config' +import Logger from './internal/logger' +import ConnectionErrorHandler from './internal/connection-error-handler' +import { ACCESS_MODE_READ, ACCESS_MODE_WRITE } from './internal/constants' + +const DEFAULT_MAX_CONNECTION_LIFETIME = 60 * 60 * 1000 // 1 hour /** * Constant that represents read session access mode. * Should be used like this: `driver.session(neo4j.session.READ)`. * @type {string} */ -const READ = ACCESS_MODE_READ; +const READ = ACCESS_MODE_READ /** * Constant that represents write session access mode. * Should be used like this: `driver.session(neo4j.session.WRITE)`. * @type {string} */ -const WRITE = ACCESS_MODE_WRITE; +const WRITE = ACCESS_MODE_WRITE -let idGenerator = 0; +let idGenerator = 0 /** * A driver maintains one or more {@link Session}s with a remote @@ -68,41 +70,43 @@ class Driver { * @param {object} config * @protected */ - constructor(address, userAgent, authToken = {}, config = {}) { - sanitizeConfig(config); - - this._id = idGenerator++; - this._address = address; - this._userAgent = userAgent; - this._openConnections = {}; - this._authToken = authToken; - this._config = config; - this._log = Logger.create(config); + constructor (address, userAgent, authToken = {}, config = {}) { + sanitizeConfig(config) + + this._id = idGenerator++ + this._address = address + this._userAgent = userAgent + this._openConnections = {} + this._authToken = authToken + this._config = config + this._log = Logger.create(config) this._pool = new Pool( this._createConnection.bind(this), this._destroyConnection.bind(this), this._validateConnection.bind(this), PoolConfig.fromDriverConfig(config), this._log - ); + ) /** * Reference to the connection provider. Initialized lazily by {@link _getOrCreateConnectionProvider}. * @type {ConnectionProvider} * @protected */ - this._connectionProvider = null; + this._connectionProvider = null - this._onCompleted = null; + this._onCompleted = null - this._afterConstruction(); + this._afterConstruction() } /** * @protected */ - _afterConstruction() { - this._log.info(`Direct driver ${this._id} created for server address ${this._address}`); + _afterConstruction () { + this._log.info( + `Direct driver ${this._id} created for server address ${this._address}` + ) } /** @@ -110,8 +114,8 @@ class Driver { * @return {null|function} * @deprecated driver can be used directly once instantiated, use of this callback is not required. */ - get onCompleted() { - return this._onCompleted; + get onCompleted () { + return this._onCompleted } /** @@ -119,12 +123,15 @@ class Driver { * @param {null|function} callback the new function to be notified about successful connection. * @deprecated driver can be used directly once instantiated, use of this callback is not required. */ - set onCompleted(callback) { - this._onCompleted = callback; + set onCompleted (callback) { + this._onCompleted = callback if (this._onCompleted) { - const connectionProvider = this._getOrCreateConnectionProvider(); - const connectivityVerifier = new ConnectivityVerifier(connectionProvider, this._onCompleted); - connectivityVerifier.verify(); + const connectionProvider = this._getOrCreateConnectionProvider() + const connectivityVerifier = new ConnectivityVerifier( + connectionProvider, + this._onCompleted + ) + connectivityVerifier.verify() } } @@ -133,22 +140,26 @@ class Driver { * @return {Promise} promise resolved with a new connection or rejected when failed to connect. * @access private */ - _createConnection(address, release) { - const connection = Connection.create(address, this._config, this._createConnectionErrorHandler(), this._log); - connection._release = () => release(address, connection); - this._openConnections[connection.id] = connection; - - return connection.connect(this._userAgent, this._authToken) - .catch(error => { - if (this.onError) { - // notify Driver.onError callback about connection initialization errors - this.onError(error); - } - // let's destroy this connection - this._destroyConnection(connection); - // propagate the error because connection failed to connect / initialize - throw error; - }); + _createConnection (address, release) { + const connection = Connection.create( + address, + this._config, + this._createConnectionErrorHandler(), + this._log + ) + connection._release = () => release(address, connection) + this._openConnections[connection.id] = connection + + return connection.connect(this._userAgent, this._authToken).catch(error => { + if (this.onError) { + // notify Driver.onError callback about connection initialization errors + this.onError(error) + } + // let's destroy this connection + this._destroyConnection(connection) + // propagate the error because connection failed to connect / initialize + throw error + }) } /** @@ -156,14 +167,14 @@ class Driver { * @return {boolean} true if the connection is open * @access private **/ - _validateConnection(conn) { + _validateConnection (conn) { if (!conn.isOpen()) { - return false; + return false } - const maxConnectionLifetime = this._config.maxConnectionLifetime; - const lifetime = Date.now() - conn.creationTimestamp; - return lifetime <= maxConnectionLifetime; + const maxConnectionLifetime = this._config.maxConnectionLifetime + const lifetime = Date.now() - conn.creationTimestamp + return lifetime <= maxConnectionLifetime } /** @@ -171,9 +182,9 @@ class Driver { * @return {Connection} the connection to dispose. * @access private */ - _destroyConnection(conn) { - delete this._openConnections[conn.id]; - conn.close(); + _destroyConnection (conn) { + delete this._openConnections[conn.id] + conn.close() } /** @@ -192,43 +203,53 @@ class Driver { * transactions. Value is optional and absence indicates that that the bookmarks do not exist or are unknown. * @return {Session} new session. */ - session(mode, bookmarkOrBookmarks) { - const sessionMode = Driver._validateSessionMode(mode); - const connectionProvider = this._getOrCreateConnectionProvider(); - const bookmark = bookmarkOrBookmarks ? new Bookmark(bookmarkOrBookmarks) : Bookmark.empty(); - return new Session(sessionMode, connectionProvider, bookmark, this._config); + session (mode, bookmarkOrBookmarks) { + const sessionMode = Driver._validateSessionMode(mode) + const connectionProvider = this._getOrCreateConnectionProvider() + const bookmark = bookmarkOrBookmarks + ? new Bookmark(bookmarkOrBookmarks) + : Bookmark.empty() + return new Session(sessionMode, connectionProvider, bookmark, this._config) } - static _validateSessionMode(rawMode) { - const mode = rawMode || WRITE; + static _validateSessionMode (rawMode) { + const mode = rawMode || WRITE if (mode !== ACCESS_MODE_READ && mode !== ACCESS_MODE_WRITE) { - throw newError('Illegal session mode ' + mode); + throw newError('Illegal session mode ' + mode) } - return mode; + return mode } // Extension point - _createConnectionProvider(address, connectionPool, driverOnErrorCallback) { - return new DirectConnectionProvider(address, connectionPool, driverOnErrorCallback); + _createConnectionProvider (address, connectionPool, driverOnErrorCallback) { + return new DirectConnectionProvider( + address, + connectionPool, + driverOnErrorCallback + ) } // Extension point - _createConnectionErrorHandler() { - return new ConnectionErrorHandler(SERVICE_UNAVAILABLE); + _createConnectionErrorHandler () { + return new ConnectionErrorHandler(SERVICE_UNAVAILABLE) } - _getOrCreateConnectionProvider() { + _getOrCreateConnectionProvider () { if (!this._connectionProvider) { - const driverOnErrorCallback = this._driverOnErrorCallback.bind(this); - this._connectionProvider = this._createConnectionProvider(this._address, this._pool, driverOnErrorCallback); + const driverOnErrorCallback = this._driverOnErrorCallback.bind(this) + this._connectionProvider = this._createConnectionProvider( + this._address, + this._pool, + driverOnErrorCallback + ) } - return this._connectionProvider; + return this._connectionProvider } - _driverOnErrorCallback(error) { - const userDefinedOnErrorCallback = this.onError; + _driverOnErrorCallback (error) { + const userDefinedOnErrorCallback = this.onError if (userDefinedOnErrorCallback && error.code === SERVICE_UNAVAILABLE) { - userDefinedOnErrorCallback(error); + userDefinedOnErrorCallback(error) } else { // we don't need to tell the driver about this error } @@ -239,64 +260,53 @@ class Driver { * make sure to use this when you are done with this driver instance. * @return undefined */ - close() { - this._log.info(`Driver ${this._id} closing`); + close () { + this._log.info(`Driver ${this._id} closing`) try { // purge all idle connections in the connection pool - this._pool.purgeAll(); + this._pool.purgeAll() } finally { // then close all connections driver has ever created // it is needed to close connections that are active right now and are acquired from the pool for (let connectionId in this._openConnections) { if (this._openConnections.hasOwnProperty(connectionId)) { - this._openConnections[connectionId].close(); + this._openConnections[connectionId].close() } } } } } -/** Internal stream observer used for connection state */ -class _ConnectionStreamObserver extends StreamObserver { - constructor(driver, conn) { - super(); - this._driver = driver; - this._conn = conn; - this._hasFailed = false; - } - - onError(error) { - if (!this._hasFailed) { - super.onError(error); - if (this._driver.onError) { - this._driver.onError(error); - } - this._hasFailed = true; - } - } -} - /** * @private */ -function sanitizeConfig(config) { - config.maxConnectionLifetime = sanitizeIntValue(config.maxConnectionLifetime, DEFAULT_MAX_CONNECTION_LIFETIME); - config.maxConnectionPoolSize = sanitizeIntValue(config.maxConnectionPoolSize, DEFAULT_MAX_SIZE); - config.connectionAcquisitionTimeout = sanitizeIntValue(config.connectionAcquisitionTimeout, DEFAULT_ACQUISITION_TIMEOUT); +function sanitizeConfig (config) { + config.maxConnectionLifetime = sanitizeIntValue( + config.maxConnectionLifetime, + DEFAULT_MAX_CONNECTION_LIFETIME + ) + config.maxConnectionPoolSize = sanitizeIntValue( + config.maxConnectionPoolSize, + DEFAULT_MAX_SIZE + ) + config.connectionAcquisitionTimeout = sanitizeIntValue( + config.connectionAcquisitionTimeout, + DEFAULT_ACQUISITION_TIMEOUT + ) } -function sanitizeIntValue(rawValue, defaultWhenAbsent) { - const sanitizedValue = parseInt(rawValue, 10); +function sanitizeIntValue (rawValue, defaultWhenAbsent) { + const sanitizedValue = parseInt(rawValue, 10) if (sanitizedValue > 0 || sanitizedValue === 0) { - return sanitizedValue; + return sanitizedValue } else if (sanitizedValue < 0) { - return Number.MAX_SAFE_INTEGER; + return Number.MAX_SAFE_INTEGER } else { - return defaultWhenAbsent; + return defaultWhenAbsent } } -export {Driver, READ, WRITE} +export { Driver, READ, WRITE } export default Driver diff --git a/src/v1/error.js b/src/v1/error.js index 756ee4480..121a30c2a 100644 --- a/src/v1/error.js +++ b/src/v1/error.js @@ -24,41 +24,40 @@ * Error code representing complete loss of service. Used by {@link Neo4jError#code}. * @type {string} */ -const SERVICE_UNAVAILABLE = 'ServiceUnavailable'; +const SERVICE_UNAVAILABLE = 'ServiceUnavailable' /** * Error code representing transient loss of service. Used by {@link Neo4jError#code}. * @type {string} */ -const SESSION_EXPIRED = 'SessionExpired'; +const SESSION_EXPIRED = 'SessionExpired' /** * Error code representing serialization/deserialization issue in the Bolt protocol. Used by {@link Neo4jError#code}. * @type {string} */ -const PROTOCOL_ERROR = 'ProtocolError'; +const PROTOCOL_ERROR = 'ProtocolError' -function newError(message, code="N/A") { +function newError (message, code = 'N/A') { // TODO: Idea is that we can check the code here and throw sub-classes // of Neo4jError as appropriate - return new Neo4jError(message, code); + return new Neo4jError(message, code) } /** * Class for all errors thrown/returned by the driver. */ class Neo4jError extends Error { - /** * @constructor * @param {string} message - The error message. * @param {string} code - Optional error code. Will be populated when error originates in the database. */ - constructor(message, code = 'N/A') { - super( message ); - this.message = message; - this.code = code; - this.name = "Neo4jError" + constructor (message, code = 'N/A') { + super(message) + this.message = message + this.code = code + this.name = 'Neo4jError' } } diff --git a/src/v1/graph-types.js b/src/v1/graph-types.js index e70ffe6cb..0a355c240 100644 --- a/src/v1/graph-types.js +++ b/src/v1/graph-types.js @@ -17,11 +17,9 @@ * limitations under the License. */ -import Integer from './integer'; - /** * Class for Node Type. - */ + */ class Node { /** * @constructor @@ -29,34 +27,34 @@ class Node { * @param {Array} labels - Array for all labels * @param {Object} properties - Map with node properties */ - constructor(identity, labels, properties) { - this.identity = identity; - this.labels = labels; - this.properties = properties; + constructor (identity, labels, properties) { + this.identity = identity + this.labels = labels + this.properties = properties } - toString() { - let s = "(" + this.identity; + toString () { + let s = '(' + this.identity for (let i = 0; i < this.labels.length; i++) { - s += ":" + this.labels[i]; + s += ':' + this.labels[i] } - let keys = Object.keys(this.properties); + let keys = Object.keys(this.properties) if (keys.length > 0) { - s += " {"; - for(let i = 0; i < keys.length; i++) { - if (i > 0) s += ","; - s += keys[i] + ":" + JSON.stringify(this.properties[keys[i]]); + s += ' {' + for (let i = 0; i < keys.length; i++) { + if (i > 0) s += ',' + s += keys[i] + ':' + JSON.stringify(this.properties[keys[i]]) } - s += "}"; + s += '}' } - s += ")"; - return s; + s += ')' + return s } } /** * Class for Relationship Type. - */ + */ class Relationship { /** * @constructor @@ -66,34 +64,34 @@ class Relationship { * @param {string} type - Relationship type * @param {Object} properties - Map with relationship properties */ - constructor(identity, start, end, type, properties) { - this.identity = identity; - this.start = start; - this.end = end; - this.type = type; - this.properties = properties; + constructor (identity, start, end, type, properties) { + this.identity = identity + this.start = start + this.end = end + this.type = type + this.properties = properties } - toString() { - let s = "(" + this.start + ")-[:" + this.type; - let keys = Object.keys(this.properties); + toString () { + let s = '(' + this.start + ')-[:' + this.type + let keys = Object.keys(this.properties) if (keys.length > 0) { - s += " {"; - for(let i = 0; i < keys.length; i++) { - if (i > 0) s += ","; - s += keys[i] + ":" + JSON.stringify(this.properties[keys[i]]); + s += ' {' + for (let i = 0; i < keys.length; i++) { + if (i > 0) s += ',' + s += keys[i] + ':' + JSON.stringify(this.properties[keys[i]]) } - s += "}"; + s += '}' } - s += "]->(" + this.end + ")"; - return s; + s += ']->(' + this.end + ')' + return s } } /** * Class for UnboundRelationship Type. * @access private - */ + */ class UnboundRelationship { /** * @constructor @@ -101,10 +99,10 @@ class UnboundRelationship { * @param {string} type - Relationship type * @param {Object} properties - Map with relationship properties */ - constructor(identity, type, properties) { - this.identity = identity; - this.type = type; - this.properties = properties; + constructor (identity, type, properties) { + this.identity = identity + this.type = type + this.properties = properties } /** @@ -113,34 +111,35 @@ class UnboundRelationship { * @param {Integer} end - Identity of end node * @return {Relationship} - Created relationship */ - bind( start, end ) { + bind (start, end) { return new Relationship( - this.identity, - start, - end, - this.type, - this.properties); + this.identity, + start, + end, + this.type, + this.properties + ) } - toString() { - let s = "-[:" + this.type; - let keys = Object.keys(this.properties); + toString () { + let s = '-[:' + this.type + let keys = Object.keys(this.properties) if (keys.length > 0) { - s += " {"; - for(let i = 0; i < keys.length; i++) { - if (i > 0) s += ","; - s += keys[i] + ":" + JSON.stringify(this.properties[keys[i]]); + s += ' {' + for (let i = 0; i < keys.length; i++) { + if (i > 0) s += ',' + s += keys[i] + ':' + JSON.stringify(this.properties[keys[i]]) } - s += "}"; + s += '}' } - s += "]->"; - return s; + s += ']->' + return s } } /** * Class for PathSegment Type. - */ + */ class PathSegment { /** * @constructor @@ -148,16 +147,16 @@ class PathSegment { * @param {Relationship} rel - relationship that connects start and end node * @param {Node} end - end node */ - constructor(start, rel, end) { - this.start = start; - this.relationship = rel; - this.end = end; + constructor (start, rel, end) { + this.start = start + this.relationship = rel + this.end = end } } /** * Class for Path Type. - */ + */ class Path { /** * @constructor @@ -165,18 +164,12 @@ class Path { * @param {Node} end - end node * @param {Array} segments - Array of Segments */ - constructor(start, end, segments) { - this.start = start; - this.end = end; - this.segments = segments; - this.length = segments.length; + constructor (start, end, segments) { + this.start = start + this.end = end + this.segments = segments + this.length = segments.length } } -export { - Node, - Relationship, - UnboundRelationship, - Path, - PathSegment -} +export { Node, Relationship, UnboundRelationship, Path, PathSegment } diff --git a/src/v1/index.js b/src/v1/index.js index cba614ced..6f59794fd 100644 --- a/src/v1/index.js +++ b/src/v1/index.js @@ -17,21 +17,45 @@ * limitations under the License. */ -import Integer, {inSafeRange, int, isInt, toNumber, toString} from './integer'; -import {Node, Path, PathSegment, Relationship, UnboundRelationship} from './graph-types'; -import {Neo4jError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from './error'; -import Result from './result'; -import ResultSummary from './result-summary'; -import Record from './record'; -import {Driver, READ, WRITE} from './driver'; -import RoutingDriver from './routing-driver'; -import VERSION from '../version'; -import {assertString, isEmptyObjectOrNull} from './internal/util'; -import urlUtil from './internal/url-util'; -import HttpDriver from './internal/http/http-driver'; -import {isPoint, Point} from './spatial-types'; -import {Date, DateTime, Duration, isDate, isDateTime, isDuration, isLocalDateTime, isLocalTime, isTime, LocalDateTime, LocalTime, Time} from './temporal-types'; -import ServerAddress from './internal/server-address'; +import Integer, { inSafeRange, int, isInt, toNumber, toString } from './integer' +import { + Node, + Path, + PathSegment, + Relationship, + UnboundRelationship +} from './graph-types' +import { + Neo4jError, + PROTOCOL_ERROR, + SERVICE_UNAVAILABLE, + SESSION_EXPIRED +} from './error' +import Result from './result' +import ResultSummary from './result-summary' +import Record from './record' +import { Driver, READ, WRITE } from './driver' +import RoutingDriver from './routing-driver' +import VERSION from '../version' +import { assertString, isEmptyObjectOrNull } from './internal/util' +import urlUtil from './internal/url-util' +import HttpDriver from './internal/http/http-driver' +import { isPoint, Point } from './spatial-types' +import { + Date, + DateTime, + Duration, + isDate, + isDateTime, + isDuration, + isLocalDateTime, + isLocalTime, + isTime, + LocalDateTime, + LocalTime, + Time +} from './temporal-types' +import ServerAddress from './internal/server-address' /** * @property {function(username: string, password: string, realm: ?string)} basic the function to create a @@ -44,30 +68,43 @@ import ServerAddress from './internal/server-address'; const auth = { basic: (username, password, realm = undefined) => { if (realm) { - return {scheme: 'basic', principal: username, credentials: password, realm: realm}; + return { + scheme: 'basic', + principal: username, + credentials: password, + realm: realm + } } else { - return {scheme: 'basic', principal: username, credentials: password}; + return { scheme: 'basic', principal: username, credentials: password } } }, - kerberos: (base64EncodedTicket) => { + kerberos: base64EncodedTicket => { return { scheme: 'kerberos', principal: '', // This empty string is required for backwards compatibility. credentials: base64EncodedTicket - }; + } }, custom: (principal, credentials, realm, scheme, parameters = undefined) => { if (parameters) { return { - scheme: scheme, principal: principal, credentials: credentials, realm: realm, + scheme: scheme, + principal: principal, + credentials: credentials, + realm: realm, parameters: parameters - }; + } } else { - return {scheme: scheme, principal: principal, credentials: credentials, realm: realm}; + return { + scheme: scheme, + principal: principal, + credentials: credentials, + realm: realm + } } } -}; -const USER_AGENT = "neo4j-javascript/" + VERSION; +} +const USER_AGENT = 'neo4j-javascript/' + VERSION /** * Object containing predefined logging configurations. These are expected to be used as values of the driver config's `logging` property. @@ -78,10 +115,11 @@ const logging = { console: level => { return { level: level, - logger: (level, message) => console.log(`${global.Date.now()} ${level.toUpperCase()} ${message}`) - }; + logger: (level, message) => + console.log(`${global.Date.now()} ${level.toUpperCase()} ${message}`) + } } -}; +} /** * Construct a new Neo4j Driver. This is your main entry point for this @@ -224,20 +262,33 @@ const logging = { * @param {Object} config Configuration object. See the configuration section above for details. * @returns {Driver} */ -function driver(url, authToken, config = {}) { - assertString(url, 'Bolt URL'); - const parsedUrl = urlUtil.parseDatabaseUrl(url); +function driver (url, authToken, config = {}) { + assertString(url, 'Bolt URL') + const parsedUrl = urlUtil.parseDatabaseUrl(url) if (['bolt+routing', 'neo4j'].indexOf(parsedUrl.scheme) !== -1) { - return new RoutingDriver(ServerAddress.fromUrl(parsedUrl.hostAndPort), parsedUrl.query, USER_AGENT, authToken, config); + return new RoutingDriver( + ServerAddress.fromUrl(parsedUrl.hostAndPort), + parsedUrl.query, + USER_AGENT, + authToken, + config + ) } else if (parsedUrl.scheme === 'bolt') { if (!isEmptyObjectOrNull(parsedUrl.query)) { - throw new Error(`Parameters are not supported with scheme 'bolt'. Given URL: '${url}'`); + throw new Error( + `Parameters are not supported with scheme 'bolt'. Given URL: '${url}'` + ) } - return new Driver(ServerAddress.fromUrl(parsedUrl.hostAndPort), USER_AGENT, authToken, config); + return new Driver( + ServerAddress.fromUrl(parsedUrl.hostAndPort), + USER_AGENT, + authToken, + config + ) } else if (parsedUrl.scheme === 'http' || parsedUrl.scheme === 'https') { - return new HttpDriver(parsedUrl, USER_AGENT, authToken, config); + return new HttpDriver(parsedUrl, USER_AGENT, authToken, config) } else { - throw new Error(`Unknown scheme: ${parsedUrl.scheme}`); + throw new Error(`Unknown scheme: ${parsedUrl.scheme}`) } } @@ -261,7 +312,7 @@ const types = { LocalTime, Time, Integer -}; +} /** * Object containing string constants representing session access modes. @@ -269,7 +320,7 @@ const types = { const session = { READ, WRITE -}; +} /** * Object containing string constants representing predefined {@link Neo4jError} codes. @@ -278,7 +329,7 @@ const error = { SERVICE_UNAVAILABLE, SESSION_EXPIRED, PROTOCOL_ERROR -}; +} /** * Object containing functions to work with {@link Integer} objects. @@ -287,14 +338,14 @@ const integer = { toNumber, toString, inSafeRange -}; +} /** * Object containing functions to work with spatial types, like {@link Point}. */ const spatial = { isPoint -}; +} /** * Object containing functions to work with temporal types, like {@link Time} or {@link Duration}. @@ -306,8 +357,7 @@ const temporal = { isDate, isLocalDateTime, isDateTime -}; - +} /** * @private @@ -332,7 +382,7 @@ const forExport = { error, spatial, temporal -}; +} export { driver, @@ -354,5 +404,5 @@ export { error, spatial, temporal -}; -export default forExport; +} +export default forExport diff --git a/src/v1/integer.js b/src/v1/integer.js index 0d9e0ae0b..b52db5f08 100644 --- a/src/v1/integer.js +++ b/src/v1/integer.js @@ -21,7 +21,7 @@ // https://github.com/dcodeIO/Long.js // License Apache 2 -import {newError} from './error'; +import { newError } from './error' /** * Constructs a 64 bit two's-complement integer, given its low and high 32 bit values as *signed* integers. @@ -37,20 +37,20 @@ import {newError} from './error'; * @constructor */ class Integer { - constructor(low, high) { + constructor (low, high) { /** * The low 32 bits as a signed value. * @type {number} * @expose */ - this.low = low|0; + this.low = low | 0 /** * The high 32 bits as a signed value. * @type {number} * @expose */ - this.high = high|0; + this.high = high | 0 } // The internal representation of an Integer is the two given signed, 32-bit values. @@ -70,34 +70,42 @@ class Integer { // Common constant values ZERO, ONE, NEG_ONE, etc. are defined below the from* // methods on which they depend. - - inSafeRange() {return this.greaterThanOrEqual(Integer.MIN_SAFE_VALUE) && this.lessThanOrEqual(Integer.MAX_SAFE_VALUE)} + inSafeRange () { + return ( + this.greaterThanOrEqual(Integer.MIN_SAFE_VALUE) && + this.lessThanOrEqual(Integer.MAX_SAFE_VALUE) + ) + } /** * Converts the Integer to an exact javascript Number, assuming it is a 32 bit integer. * @returns {number} * @expose */ - toInt() { return this.low; }; + toInt () { + return this.low + } /** * Converts the Integer to a the nearest floating-point representation of this value (double, 53 bit mantissa). * @returns {number} * @expose */ - toNumber(){ return this.high * TWO_PWR_32_DBL + (this.low >>> 0); } + toNumber () { + return this.high * TWO_PWR_32_DBL + (this.low >>> 0) + } /** * Converts the Integer to native number or -Infinity/+Infinity when it does not fit. * @return {number} * @package */ - toNumberOrInfinity() { + toNumberOrInfinity () { if (this.lessThan(Integer.MIN_SAFE_VALUE)) { - return Number.NEGATIVE_INFINITY; + return Number.NEGATIVE_INFINITY } else if (this.greaterThan(Integer.MAX_SAFE_VALUE)) { - return Number.POSITIVE_INFINITY; + return Number.POSITIVE_INFINITY } else { - return this.toNumber(); + return this.toNumber() } } @@ -109,41 +117,45 @@ class Integer { * @throws {RangeError} If `radix` is out of range * @expose */ - toString(radix) { - radix = radix || 10; - if (radix < 2 || 36 < radix) - throw RangeError('radix out of range: ' + radix); - if (this.isZero()) - return '0'; - var rem; + toString (radix) { + radix = radix || 10 + if (radix < 2 || radix > 36) { + throw RangeError('radix out of range: ' + radix) + } + if (this.isZero()) { + return '0' + } + var rem if (this.isNegative()) { if (this.equals(Integer.MIN_VALUE)) { // We need to change the Integer value before it can be negated, so we remove // the bottom-most digit in this base and then recurse to do the rest. - var radixInteger = Integer.fromNumber(radix); - var div = this.div(radixInteger); - rem = div.multiply(radixInteger).subtract(this); - return div.toString(radix) + rem.toInt().toString(radix); - } else - return '-' + this.negate().toString(radix); + var radixInteger = Integer.fromNumber(radix) + var div = this.div(radixInteger) + rem = div.multiply(radixInteger).subtract(this) + return div.toString(radix) + rem.toInt().toString(radix) + } else { + return '-' + this.negate().toString(radix) + } } // Do several (6) digits each time through the loop, so as to // minimize the calls to the very expensive emulated div. - var radixToPower = Integer.fromNumber(Math.pow(radix, 6) ); - rem = this; - var result = ''; + var radixToPower = Integer.fromNumber(Math.pow(radix, 6)) + rem = this + var result = '' while (true) { - var remDiv = rem.div(radixToPower), - intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() >>> 0, - digits = intval.toString(radix); - rem = remDiv; - if (rem.isZero()) - return digits + result; - else { - while (digits.length < 6) - digits = '0' + digits; - result = '' + digits + result; + var remDiv = rem.div(radixToPower) + var intval = rem.subtract(remDiv.multiply(radixToPower)).toInt() >>> 0 + var digits = intval.toString(radix) + rem = remDiv + if (rem.isZero()) { + return digits + result + } else { + while (digits.length < 6) { + digits = '0' + digits + } + result = '' + digits + result } } } @@ -153,28 +165,35 @@ class Integer { * @returns {number} Signed high bits * @expose */ - getHighBits() { return this.high; } + getHighBits () { + return this.high + } /** * Gets the low 32 bits as a signed integer. * @returns {number} Signed low bits * @expose */ - getLowBits() { return this.low; } + getLowBits () { + return this.low + } /** * Gets the number of bits needed to represent the absolute value of this Integer. * @returns {number} * @expose */ - getNumBitsAbs() { - if (this.isNegative()) - return this.equals(Integer.MIN_VALUE) ? 64 : this.negate().getNumBitsAbs(); - var val = this.high != 0 ? this.high : this.low; - for (var bit = 31; bit > 0; bit--) - if ((val & (1 << bit)) != 0) - break; - return this.high != 0 ? bit + 33 : bit + 1; + getNumBitsAbs () { + if (this.isNegative()) { + return this.equals(Integer.MIN_VALUE) ? 64 : this.negate().getNumBitsAbs() + } + var val = this.high !== 0 ? this.high : this.low + for (var bit = 31; bit > 0; bit--) { + if ((val & (1 << bit)) !== 0) { + break + } + } + return this.high !== 0 ? bit + 33 : bit + 1 } /** @@ -182,8 +201,8 @@ class Integer { * @returns {boolean} * @expose */ - isZero() { - return this.high === 0 && this.low === 0; + isZero () { + return this.high === 0 && this.low === 0 } /** @@ -191,8 +210,8 @@ class Integer { * @returns {boolean} * @expose */ - isNegative() { - return this.high < 0; + isNegative () { + return this.high < 0 } /** @@ -200,8 +219,8 @@ class Integer { * @returns {boolean} * @expose */ - isPositive() { - return this.high >= 0; + isPositive () { + return this.high >= 0 } /** @@ -209,14 +228,18 @@ class Integer { * @returns {boolean} * @expose */ - isOdd() { return (this.low & 1) === 1; } + isOdd () { + return (this.low & 1) === 1 + } /** * Tests if this Integer's value is even. * @returns {boolean} * @expose */ - isEven() { return (this.low & 1) === 0; }; + isEven () { + return (this.low & 1) === 0 + } /** * Tests if this Integer's value equals the specified's. @@ -224,10 +247,11 @@ class Integer { * @returns {boolean} * @expose */ - equals(other) { - if (!Integer.isInteger(other)) - other = Integer.fromValue(other); - return this.high === other.high && this.low === other.low; + equals (other) { + if (!Integer.isInteger(other)) { + other = Integer.fromValue(other) + } + return this.high === other.high && this.low === other.low } /** @@ -236,8 +260,8 @@ class Integer { * @returns {boolean} * @expose */ - notEquals(other) { - return !this.equals(/* validates */ other); + notEquals (other) { + return !this.equals(/* validates */ other) } /** @@ -246,7 +270,9 @@ class Integer { * @returns {boolean} * @expose */ - lessThan(other) { return this.compare(/* validates */ other) < 0; } + lessThan (other) { + return this.compare(/* validates */ other) < 0 + } /** * Tests if this Integer's value is less than or equal the specified's. @@ -254,7 +280,9 @@ class Integer { * @returns {boolean} * @expose */ - lessThanOrEqual(other) { return this.compare(/* validates */ other) <= 0; } + lessThanOrEqual (other) { + return this.compare(/* validates */ other) <= 0 + } /** * Tests if this Integer's value is greater than the specified's. @@ -262,7 +290,9 @@ class Integer { * @returns {boolean} * @expose */ - greaterThan(other) { return this.compare(/* validates */ other) > 0; } + greaterThan (other) { + return this.compare(/* validates */ other) > 0 + } /** * Tests if this Integer's value is greater than or equal the specified's. @@ -270,7 +300,9 @@ class Integer { * @returns {boolean} * @expose */ - greaterThanOrEqual(other) { return this.compare(/* validates */ other) >= 0; } + greaterThanOrEqual (other) { + return this.compare(/* validates */ other) >= 0 + } /** * Compares this Integer's value with the specified's. @@ -279,19 +311,23 @@ class Integer { * if the given one is greater * @expose */ - compare(other) { - if (!Integer.isInteger(other)) - other = Integer.fromValue(other); - if (this.equals(other)) - return 0; - var thisNeg = this.isNegative(), - otherNeg = other.isNegative(); - if (thisNeg && !otherNeg) - return -1; - if (!thisNeg && otherNeg) - return 1; + compare (other) { + if (!Integer.isInteger(other)) { + other = Integer.fromValue(other) + } + if (this.equals(other)) { + return 0 + } + var thisNeg = this.isNegative() + var otherNeg = other.isNegative() + if (thisNeg && !otherNeg) { + return -1 + } + if (!thisNeg && otherNeg) { + return 1 + } // At this point the sign bits are the same - return this.subtract(other).isNegative() ? -1 : 1; + return this.subtract(other).isNegative() ? -1 : 1 } /** @@ -299,10 +335,11 @@ class Integer { * @returns {!Integer} Negated Integer * @expose */ - negate() { - if (this.equals(Integer.MIN_VALUE)) - return Integer.MIN_VALUE; - return this.not().add(Integer.ONE); + negate () { + if (this.equals(Integer.MIN_VALUE)) { + return Integer.MIN_VALUE + } + return this.not().add(Integer.ONE) } /** @@ -311,35 +348,39 @@ class Integer { * @returns {!Integer} Sum * @expose */ - add(addend) { - if (!Integer.isInteger(addend)) - addend = Integer.fromValue(addend); + add (addend) { + if (!Integer.isInteger(addend)) { + addend = Integer.fromValue(addend) + } // Divide each number into 4 chunks of 16 bits, and then sum the chunks. - var a48 = this.high >>> 16; - var a32 = this.high & 0xFFFF; - var a16 = this.low >>> 16; - var a00 = this.low & 0xFFFF; - - var b48 = addend.high >>> 16; - var b32 = addend.high & 0xFFFF; - var b16 = addend.low >>> 16; - var b00 = addend.low & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 + b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 + b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 + b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 + b48; - c48 &= 0xFFFF; - return Integer.fromBits((c16 << 16) | c00, (c48 << 16) | c32); + var a48 = this.high >>> 16 + var a32 = this.high & 0xffff + var a16 = this.low >>> 16 + var a00 = this.low & 0xffff + + var b48 = addend.high >>> 16 + var b32 = addend.high & 0xffff + var b16 = addend.low >>> 16 + var b00 = addend.low & 0xffff + + var c48 = 0 + var c32 = 0 + var c16 = 0 + var c00 = 0 + c00 += a00 + b00 + c16 += c00 >>> 16 + c00 &= 0xffff + c16 += a16 + b16 + c32 += c16 >>> 16 + c16 &= 0xffff + c32 += a32 + b32 + c48 += c32 >>> 16 + c32 &= 0xffff + c48 += a48 + b48 + c48 &= 0xffff + return Integer.fromBits((c16 << 16) | c00, (c48 << 16) | c32) } /** @@ -348,10 +389,11 @@ class Integer { * @returns {!Integer} Difference * @expose */ - subtract(subtrahend) { - if (!Integer.isInteger(subtrahend)) - subtrahend = Integer.fromValue(subtrahend); - return this.add(subtrahend.negate()); + subtract (subtrahend) { + if (!Integer.isInteger(subtrahend)) { + subtrahend = Integer.fromValue(subtrahend) + } + return this.add(subtrahend.negate()) } /** @@ -360,66 +402,79 @@ class Integer { * @returns {!Integer} Product * @expose */ - multiply(multiplier) { - if (this.isZero()) - return Integer.ZERO; - if (!Integer.isInteger(multiplier)) - multiplier = Integer.fromValue(multiplier); - if (multiplier.isZero()) - return Integer.ZERO; - if (this.equals(Integer.MIN_VALUE)) - return multiplier.isOdd() ? Integer.MIN_VALUE : Integer.ZERO; - if (multiplier.equals(Integer.MIN_VALUE)) - return this.isOdd() ? Integer.MIN_VALUE : Integer.ZERO; + multiply (multiplier) { + if (this.isZero()) { + return Integer.ZERO + } + if (!Integer.isInteger(multiplier)) { + multiplier = Integer.fromValue(multiplier) + } + if (multiplier.isZero()) { + return Integer.ZERO + } + if (this.equals(Integer.MIN_VALUE)) { + return multiplier.isOdd() ? Integer.MIN_VALUE : Integer.ZERO + } + if (multiplier.equals(Integer.MIN_VALUE)) { + return this.isOdd() ? Integer.MIN_VALUE : Integer.ZERO + } if (this.isNegative()) { - if (multiplier.isNegative()) - return this.negate().multiply(multiplier.negate()); - else - return this.negate().multiply(multiplier).negate(); - } else if (multiplier.isNegative()) - return this.multiply(multiplier.negate()).negate(); + if (multiplier.isNegative()) { + return this.negate().multiply(multiplier.negate()) + } else { + return this.negate() + .multiply(multiplier) + .negate() + } + } else if (multiplier.isNegative()) { + return this.multiply(multiplier.negate()).negate() + } // If both longs are small, use float multiplication - if (this.lessThan(TWO_PWR_24) && multiplier.lessThan(TWO_PWR_24)) - return Integer.fromNumber(this.toNumber() * multiplier.toNumber()); + if (this.lessThan(TWO_PWR_24) && multiplier.lessThan(TWO_PWR_24)) { + return Integer.fromNumber(this.toNumber() * multiplier.toNumber()) + } // Divide each long into 4 chunks of 16 bits, and then add up 4x4 products. // We can skip products that would overflow. - var a48 = this.high >>> 16; - var a32 = this.high & 0xFFFF; - var a16 = this.low >>> 16; - var a00 = this.low & 0xFFFF; - - var b48 = multiplier.high >>> 16; - var b32 = multiplier.high & 0xFFFF; - var b16 = multiplier.low >>> 16; - var b00 = multiplier.low & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 * b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 * b00; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c16 += a00 * b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 * b00; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a16 * b16; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a00 * b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; - c48 &= 0xFFFF; - return Integer.fromBits((c16 << 16) | c00, (c48 << 16) | c32); - }; + var a48 = this.high >>> 16 + var a32 = this.high & 0xffff + var a16 = this.low >>> 16 + var a00 = this.low & 0xffff + + var b48 = multiplier.high >>> 16 + var b32 = multiplier.high & 0xffff + var b16 = multiplier.low >>> 16 + var b00 = multiplier.low & 0xffff + + var c48 = 0 + var c32 = 0 + var c16 = 0 + var c00 = 0 + c00 += a00 * b00 + c16 += c00 >>> 16 + c00 &= 0xffff + c16 += a16 * b00 + c32 += c16 >>> 16 + c16 &= 0xffff + c16 += a00 * b16 + c32 += c16 >>> 16 + c16 &= 0xffff + c32 += a32 * b00 + c48 += c32 >>> 16 + c32 &= 0xffff + c32 += a16 * b16 + c48 += c32 >>> 16 + c32 &= 0xffff + c32 += a00 * b32 + c48 += c32 >>> 16 + c32 &= 0xffff + c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48 + c48 &= 0xffff + return Integer.fromBits((c16 << 16) | c00, (c48 << 16) | c32) + } /** * Returns this Integer divided by the specified. @@ -427,76 +482,85 @@ class Integer { * @returns {!Integer} Quotient * @expose */ - div(divisor) { - if (!Integer.isInteger(divisor)) - divisor = Integer.fromValue(divisor); - if (divisor.isZero()) - throw newError('division by zero'); - if (this.isZero()) - return Integer.ZERO; - var approx, rem, res; + div (divisor) { + if (!Integer.isInteger(divisor)) { + divisor = Integer.fromValue(divisor) + } + if (divisor.isZero()) { + throw newError('division by zero') + } + if (this.isZero()) { + return Integer.ZERO + } + var approx, rem, res if (this.equals(Integer.MIN_VALUE)) { - if (divisor.equals(Integer.ONE) || divisor.equals(Integer.NEG_ONE)) - return Integer.MIN_VALUE; // recall that -MIN_VALUE == MIN_VALUE - else if (divisor.equals(Integer.MIN_VALUE)) - return Integer.ONE; - else { + if (divisor.equals(Integer.ONE) || divisor.equals(Integer.NEG_ONE)) { + return Integer.MIN_VALUE + } else if (divisor.equals(Integer.MIN_VALUE)) { + return Integer.ONE + } else { // At this point, we have |other| >= 2, so |this/other| < |MIN_VALUE|. - var halfThis = this.shiftRight(1); - approx = halfThis.div(divisor).shiftLeft(1); + var halfThis = this.shiftRight(1) + approx = halfThis.div(divisor).shiftLeft(1) if (approx.equals(Integer.ZERO)) { - return divisor.isNegative() ? Integer.ONE : Integer.NEG_ONE; + return divisor.isNegative() ? Integer.ONE : Integer.NEG_ONE } else { - rem = this.subtract(divisor.multiply(approx)); - res = approx.add(rem.div(divisor)); - return res; + rem = this.subtract(divisor.multiply(approx)) + res = approx.add(rem.div(divisor)) + return res } } - } else if (divisor.equals(Integer.MIN_VALUE)) - return Integer.ZERO; + } else if (divisor.equals(Integer.MIN_VALUE)) { + return Integer.ZERO + } if (this.isNegative()) { - if (divisor.isNegative()) - return this.negate().div(divisor.negate()); - return this.negate().div(divisor).negate(); - } else if (divisor.isNegative()) - return this.div(divisor.negate()).negate(); + if (divisor.isNegative()) { + return this.negate().div(divisor.negate()) + } + return this.negate() + .div(divisor) + .negate() + } else if (divisor.isNegative()) { + return this.div(divisor.negate()).negate() + } // Repeat the following until the remainder is less than other: find a // floating-point that approximates remainder / other *from below*, add this // into the result, and subtract it from the remainder. It is critical that // the approximate value is less than or equal to the real value so that the // remainder never becomes negative. - res = Integer.ZERO; - rem = this; + res = Integer.ZERO + rem = this while (rem.greaterThanOrEqual(divisor)) { // Approximate the result of division. This may be a little greater or // smaller than the actual value. - approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())); + approx = Math.max(1, Math.floor(rem.toNumber() / divisor.toNumber())) // We will tweak the approximate result by changing it in the 48-th digit or // the smallest non-fractional digit, whichever is larger. - var log2 = Math.ceil(Math.log(approx) / Math.LN2), - delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48), + var log2 = Math.ceil(Math.log(approx) / Math.LN2) + var delta = log2 <= 48 ? 1 : Math.pow(2, log2 - 48) // Decrease the approximation until it is smaller than the remainder. Note // that if it is too large, the product overflows and is negative. - approxRes = Integer.fromNumber(approx), - approxRem = approxRes.multiply(divisor); + var approxRes = Integer.fromNumber(approx) + var approxRem = approxRes.multiply(divisor) while (approxRem.isNegative() || approxRem.greaterThan(rem)) { - approx -= delta; - approxRes = Integer.fromNumber(approx); - approxRem = approxRes.multiply(divisor); + approx -= delta + approxRes = Integer.fromNumber(approx) + approxRem = approxRes.multiply(divisor) } // We know the answer can't be zero... and actually, zero would cause // infinite recursion since we would make no progress. - if (approxRes.isZero()) - approxRes = Integer.ONE; + if (approxRes.isZero()) { + approxRes = Integer.ONE + } - res = res.add(approxRes); - rem = rem.subtract(approxRem); + res = res.add(approxRes) + rem = rem.subtract(approxRem) } - return res; + return res } /** @@ -505,10 +569,11 @@ class Integer { * @returns {!Integer} Remainder * @expose */ - modulo(divisor) { - if (!Integer.isInteger(divisor)) - divisor = Integer.fromValue(divisor); - return this.subtract(this.div(divisor).multiply(divisor)); + modulo (divisor) { + if (!Integer.isInteger(divisor)) { + divisor = Integer.fromValue(divisor) + } + return this.subtract(this.div(divisor).multiply(divisor)) } /** @@ -516,8 +581,8 @@ class Integer { * @returns {!Integer} * @expose */ - not() { - return Integer.fromBits(~this.low, ~this.high); + not () { + return Integer.fromBits(~this.low, ~this.high) } /** @@ -526,10 +591,11 @@ class Integer { * @returns {!Integer} * @expose */ - and(other) { - if (!Integer.isInteger(other)) - other = Integer.fromValue(other); - return Integer.fromBits(this.low & other.low, this.high & other.high); + and (other) { + if (!Integer.isInteger(other)) { + other = Integer.fromValue(other) + } + return Integer.fromBits(this.low & other.low, this.high & other.high) } /** @@ -538,10 +604,11 @@ class Integer { * @returns {!Integer} * @expose */ - or(other) { - if (!Integer.isInteger(other)) - other = Integer.fromValue(other); - return Integer.fromBits(this.low | other.low, this.high | other.high); + or (other) { + if (!Integer.isInteger(other)) { + other = Integer.fromValue(other) + } + return Integer.fromBits(this.low | other.low, this.high | other.high) } /** @@ -550,10 +617,11 @@ class Integer { * @returns {!Integer} * @expose */ - xor(other) { - if (!Integer.isInteger(other)) - other = Integer.fromValue(other); - return Integer.fromBits(this.low ^ other.low, this.high ^ other.high); + xor (other) { + if (!Integer.isInteger(other)) { + other = Integer.fromValue(other) + } + return Integer.fromBits(this.low ^ other.low, this.high ^ other.high) } /** @@ -562,15 +630,20 @@ class Integer { * @returns {!Integer} Shifted Integer * @expose */ - shiftLeft(numBits) { - if (Integer.isInteger(numBits)) - numBits = numBits.toInt(); - if ((numBits &= 63) === 0) - return this; - else if (numBits < 32) - return Integer.fromBits(this.low << numBits, (this.high << numBits) | (this.low >>> (32 - numBits))); - else - return Integer.fromBits(0, this.low << (numBits - 32)); + shiftLeft (numBits) { + if (Integer.isInteger(numBits)) { + numBits = numBits.toInt() + } + if ((numBits &= 63) === 0) { + return this + } else if (numBits < 32) { + return Integer.fromBits( + this.low << numBits, + (this.high << numBits) | (this.low >>> (32 - numBits)) + ) + } else { + return Integer.fromBits(0, this.low << (numBits - 32)) + } } /** @@ -579,15 +652,23 @@ class Integer { * @returns {!Integer} Shifted Integer * @expose */ - shiftRight(numBits) { - if (Integer.isInteger(numBits)) - numBits = numBits.toInt(); - if ((numBits &= 63) === 0) - return this; - else if (numBits < 32) - return Integer.fromBits((this.low >>> numBits) | (this.high << (32 - numBits)), this.high >> numBits); - else - return Integer.fromBits(this.high >> (numBits - 32), this.high >= 0 ? 0 : -1); + shiftRight (numBits) { + if (Integer.isInteger(numBits)) { + numBits = numBits.toInt() + } + if ((numBits &= 63) === 0) { + return this + } else if (numBits < 32) { + return Integer.fromBits( + (this.low >>> numBits) | (this.high << (32 - numBits)), + this.high >> numBits + ) + } else { + return Integer.fromBits( + this.high >> (numBits - 32), + this.high >= 0 ? 0 : -1 + ) + } } } @@ -598,13 +679,13 @@ class Integer { * @expose * @private */ -Integer.__isInteger__; +Integer.__isInteger__ = true -Object.defineProperty(Integer.prototype, "__isInteger__", { - value: true, - enumerable: false, - configurable: false -}); +Object.defineProperty(Integer.prototype, '__isInteger__', { + value: true, + enumerable: false, + configurable: false +}) /** * Tests if the specified object is a Integer. @@ -613,11 +694,9 @@ Object.defineProperty(Integer.prototype, "__isInteger__", { * @returns {boolean} * @expose */ -Integer.isInteger = function(obj) { - return (obj && obj["__isInteger__"]) === true; -}; - - +Integer.isInteger = function (obj) { + return (obj && obj['__isInteger__']) === true +} /** * A cache of the Integer representations of small integer values. @@ -625,7 +704,7 @@ Integer.isInteger = function(obj) { * @inner * @private */ -var INT_CACHE = {}; +var INT_CACHE = {} /** * Returns a Integer representing the given 32 bit integer value. @@ -634,19 +713,21 @@ var INT_CACHE = {}; * @returns {!Integer} The corresponding Integer value * @expose */ -Integer.fromInt = function(value) { - var obj, cachedObj; - value = value | 0; - if (-128 <= value && value < 128) { - cachedObj = INT_CACHE[value]; - if (cachedObj) - return cachedObj; - } - obj = new Integer(value, value < 0 ? -1 : 0, false); - if (-128 <= value && value < 128) - INT_CACHE[value] = obj; - return obj; -}; +Integer.fromInt = function (value) { + var obj, cachedObj + value = value | 0 + if (value >= -128 && value < 128) { + cachedObj = INT_CACHE[value] + if (cachedObj) { + return cachedObj + } + } + obj = new Integer(value, value < 0 ? -1 : 0, false) + if (value >= -128 && value < 128) { + INT_CACHE[value] = obj + } + return obj +} /** * Returns a Integer representing the given value, provided that it is a finite number. Otherwise, zero is returned. @@ -655,17 +736,21 @@ Integer.fromInt = function(value) { * @returns {!Integer} The corresponding Integer value * @expose */ -Integer.fromNumber = function(value) { - if (isNaN(value) || !isFinite(value)) - return Integer.ZERO; - if (value <= -TWO_PWR_63_DBL) - return Integer.MIN_VALUE; - if (value + 1 >= TWO_PWR_63_DBL) - return Integer.MAX_VALUE; - if (value < 0) - return Integer.fromNumber(-value).negate(); - return new Integer((value % TWO_PWR_32_DBL) | 0, (value / TWO_PWR_32_DBL) | 0 ); -}; +Integer.fromNumber = function (value) { + if (isNaN(value) || !isFinite(value)) { + return Integer.ZERO + } + if (value <= -TWO_PWR_63_DBL) { + return Integer.MIN_VALUE + } + if (value + 1 >= TWO_PWR_63_DBL) { + return Integer.MAX_VALUE + } + if (value < 0) { + return Integer.fromNumber(-value).negate() + } + return new Integer(value % TWO_PWR_32_DBL | 0, (value / TWO_PWR_32_DBL) | 0) +} /** * Returns a Integer representing the 64 bit integer that comes by concatenating the given low and high bits. Each is @@ -676,9 +761,9 @@ Integer.fromNumber = function(value) { * @returns {!Integer} The corresponding Integer value * @expose */ -Integer.fromBits = function(lowBits, highBits) { - return new Integer(lowBits, highBits); -}; +Integer.fromBits = function (lowBits, highBits) { + return new Integer(lowBits, highBits) +} /** * Returns a Integer representation of the given string, written using the specified radix. @@ -688,39 +773,48 @@ Integer.fromBits = function(lowBits, highBits) { * @returns {!Integer} The corresponding Integer value * @expose */ -Integer.fromString = function(str, radix) { - if (str.length === 0) - throw newError('number format error: empty string'); - if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity") - return Integer.ZERO; - radix = radix || 10; - if (radix < 2 || 36 < radix) - throw newError('radix out of range: ' + radix); - - var p; - if ((p = str.indexOf('-')) > 0) - throw newError('number format error: interior "-" character: ' + str); - else if (p === 0) - return Integer.fromString(str.substring(1), radix).negate(); - - // Do several (8) digits each time through the loop, so as to - // minimize the calls to the very expensive emulated div. - var radixToPower = Integer.fromNumber(Math.pow(radix, 8)); - - var result = Integer.ZERO; - for (var i = 0; i < str.length; i += 8) { - var size = Math.min(8, str.length - i); - var value = parseInt(str.substring(i, i + size), radix); - if (size < 8) { - var power = Integer.fromNumber(Math.pow(radix, size)); - result = result.multiply(power).add(Integer.fromNumber(value)); - } else { - result = result.multiply(radixToPower); - result = result.add(Integer.fromNumber(value)); - } +Integer.fromString = function (str, radix) { + if (str.length === 0) { + throw newError('number format error: empty string') + } + if ( + str === 'NaN' || + str === 'Infinity' || + str === '+Infinity' || + str === '-Infinity' + ) { + return Integer.ZERO + } + radix = radix || 10 + if (radix < 2 || radix > 36) { + throw newError('radix out of range: ' + radix) + } + + var p + if ((p = str.indexOf('-')) > 0) { + throw newError('number format error: interior "-" character: ' + str) + } else if (p === 0) { + return Integer.fromString(str.substring(1), radix).negate() + } + + // Do several (8) digits each time through the loop, so as to + // minimize the calls to the very expensive emulated div. + var radixToPower = Integer.fromNumber(Math.pow(radix, 8)) + + var result = Integer.ZERO + for (var i = 0; i < str.length; i += 8) { + var size = Math.min(8, str.length - i) + var value = parseInt(str.substring(i, i + size), radix) + if (size < 8) { + var power = Integer.fromNumber(Math.pow(radix, size)) + result = result.multiply(power).add(Integer.fromNumber(value)) + } else { + result = result.multiply(radixToPower) + result = result.add(Integer.fromNumber(value)) } - return result; -}; + } + return result +} /** * Converts the specified value to a Integer. @@ -729,16 +823,19 @@ Integer.fromString = function(str, radix) { * @returns {!Integer} * @expose */ -Integer.fromValue = function(val) { - if (val /* is compatible */ instanceof Integer) - return val; - if (typeof val === 'number') - return Integer.fromNumber(val); - if (typeof val === 'string') - return Integer.fromString(val); - // Throws for non-objects, converts non-instanceof Integer: - return new Integer(val.low, val.high); -}; +Integer.fromValue = function (val) { + if (val /* is compatible */ instanceof Integer) { + return val + } + if (typeof val === 'number') { + return Integer.fromNumber(val) + } + if (typeof val === 'string') { + return Integer.fromString(val) + } + // Throws for non-objects, converts non-instanceof Integer: + return new Integer(val.low, val.high) +} /** * Converts the specified value to a number. @@ -747,21 +844,21 @@ Integer.fromValue = function(val) { * @returns {number} * @expose */ -Integer.toNumber = function(val) { - return Integer.fromValue(val).toNumber(); -}; +Integer.toNumber = function (val) { + return Integer.fromValue(val).toNumber() +} /** -* Converts the specified value to a string. -* @access private -* @param {!Integer|number|string|!{low: number, high: number}} val Value -* @param {number} radix optional radix for string conversion, defaults to 10 -* @returns {String} -* @expose -*/ -Integer.toString = function(val, radix) { + * Converts the specified value to a string. + * @access private + * @param {!Integer|number|string|!{low: number, high: number}} val Value + * @param {number} radix optional radix for string conversion, defaults to 10 + * @returns {String} + * @expose + */ +Integer.toString = function (val, radix) { return Integer.fromValue(val).toString(radix) -}; +} /** * Checks if the given value is in the safe range in order to be converted to a native number @@ -771,9 +868,9 @@ Integer.toString = function(val, radix) { * @returns {boolean} * @expose */ -Integer.inSafeRange = function(val) { - return Integer.fromValue(val).inSafeRange(); -}; +Integer.inSafeRange = function (val) { + return Integer.fromValue(val).inSafeRange() +} /** * @type {number} @@ -781,7 +878,7 @@ Integer.inSafeRange = function(val) { * @inner * @private */ -var TWO_PWR_16_DBL = 1 << 16; +var TWO_PWR_16_DBL = 1 << 16 /** * @type {number} @@ -789,7 +886,7 @@ var TWO_PWR_16_DBL = 1 << 16; * @inner * @private */ -var TWO_PWR_24_DBL = 1 << 24; +var TWO_PWR_24_DBL = 1 << 24 /** * @type {number} @@ -797,7 +894,7 @@ var TWO_PWR_24_DBL = 1 << 24; * @inner * @private */ -var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; +var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL /** * @type {number} @@ -805,7 +902,7 @@ var TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL; * @inner * @private */ -var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; +var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL /** * @type {number} @@ -813,7 +910,7 @@ var TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL; * @inner * @private */ -var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; +var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2 /** * @type {!Integer} @@ -821,56 +918,56 @@ var TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2; * @inner * @private */ -var TWO_PWR_24 = Integer.fromInt(TWO_PWR_24_DBL); +var TWO_PWR_24 = Integer.fromInt(TWO_PWR_24_DBL) /** * Signed zero. * @type {!Integer} * @expose */ -Integer.ZERO = Integer.fromInt(0); +Integer.ZERO = Integer.fromInt(0) /** * Signed one. * @type {!Integer} * @expose */ -Integer.ONE = Integer.fromInt(1); +Integer.ONE = Integer.fromInt(1) /** * Signed negative one. * @type {!Integer} * @expose */ -Integer.NEG_ONE = Integer.fromInt(-1); +Integer.NEG_ONE = Integer.fromInt(-1) /** * Maximum signed value. * @type {!Integer} * @expose */ -Integer.MAX_VALUE = Integer.fromBits(0xFFFFFFFF|0, 0x7FFFFFFF|0, false); +Integer.MAX_VALUE = Integer.fromBits(0xffffffff | 0, 0x7fffffff | 0, false) /** * Minimum signed value. * @type {!Integer} * @expose */ -Integer.MIN_VALUE = Integer.fromBits(0, 0x80000000|0, false); +Integer.MIN_VALUE = Integer.fromBits(0, 0x80000000 | 0, false) /** * Minimum safe value. * @type {!Integer} * @expose */ -Integer.MIN_SAFE_VALUE = Integer.fromBits(0x1|0, 0xFFFFFFFFFFE00000|0); +Integer.MIN_SAFE_VALUE = Integer.fromBits(0x1 | 0, 0xffffffffffe00000 | 0) /** -* Maximum safe value. -* @type {!Integer} -* @expose -*/ -Integer.MAX_SAFE_VALUE = Integer.fromBits(0xFFFFFFFF|0,0x1FFFFF|0); + * Maximum safe value. + * @type {!Integer} + * @expose + */ +Integer.MAX_SAFE_VALUE = Integer.fromBits(0xffffffff | 0, 0x1fffff | 0) /** * Cast value to Integer type. @@ -878,7 +975,7 @@ Integer.MAX_SAFE_VALUE = Integer.fromBits(0xFFFFFFFF|0,0x1FFFFF|0); * @param {Mixed} value - The value to use. * @return {Integer} - An object of type Integer. */ -let int = Integer.fromValue; +let int = Integer.fromValue /** * Check if a variable is of Integer type. @@ -886,7 +983,7 @@ let int = Integer.fromValue; * @param {Mixed} value - The variable to check. * @return {Boolean} - Is it of the Integer type? */ -let isInt = Integer.isInteger; +let isInt = Integer.isInteger /** * Check if a variable can be safely converted to a number @@ -894,7 +991,7 @@ let isInt = Integer.isInteger; * @param {Mixed} value - The variable to check * @return {Boolean} - true if it is safe to call toNumber on variable otherwise false */ -let inSafeRange = Integer.inSafeRange; +let inSafeRange = Integer.inSafeRange /** * Converts a variable to a number @@ -902,7 +999,7 @@ let inSafeRange = Integer.inSafeRange; * @param {Mixed} value - The variable to convert * @return {number} - the variable as a number */ -let toNumber = Integer.toNumber; +let toNumber = Integer.toNumber /** * Converts the integer to a string representation @@ -911,14 +1008,8 @@ let toNumber = Integer.toNumber; * @param {number} radix - radix to use in string conversion, defaults to 10 * @return {String} - returns a string representation of the integer */ -let toString = Integer.toString; - -export { - int, - isInt, - inSafeRange, - toNumber, - toString -} +let toString = Integer.toString + +export { int, isInt, inSafeRange, toNumber, toString } export default Integer diff --git a/src/v1/internal/bolt-protocol-v1.js b/src/v1/internal/bolt-protocol-v1.js index a34e4fd81..af0434003 100644 --- a/src/v1/internal/bolt-protocol-v1.js +++ b/src/v1/internal/bolt-protocol-v1.js @@ -16,41 +16,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import RequestMessage from './request-message'; -import * as v1 from './packstream-v1'; -import {newError} from '../error'; -import Bookmark from './bookmark'; -import TxConfig from './tx-config'; -import {ACCESS_MODE_WRITE} from "./constants"; +import RequestMessage from './request-message' +import * as v1 from './packstream-v1' +import { newError } from '../error' +import Bookmark from './bookmark' +import TxConfig from './tx-config' +import { ACCESS_MODE_WRITE } from './constants' export default class BoltProtocol { - /** * @constructor * @param {Connection} connection the connection. * @param {Chunker} chunker the chunker. * @param {boolean} disableLosslessIntegers if this connection should convert all received integers to native JS numbers. */ - constructor(connection, chunker, disableLosslessIntegers) { - this._connection = connection; - this._packer = this._createPacker(chunker); - this._unpacker = this._createUnpacker(disableLosslessIntegers); + constructor (connection, chunker, disableLosslessIntegers) { + this._connection = connection + this._packer = this._createPacker(chunker) + this._unpacker = this._createUnpacker(disableLosslessIntegers) } /** * Get the packer. * @return {Packer} the protocol's packer. */ - packer() { - return this._packer; + packer () { + return this._packer } /** * Get the unpacker. * @return {Unpacker} the protocol's unpacker. */ - unpacker() { - return this._unpacker; + unpacker () { + return this._unpacker } /** @@ -58,8 +57,8 @@ export default class BoltProtocol { * @param {object} metadata the received metadata. * @return {object} transformed metadata. */ - transformMetadata(metadata) { - return metadata; + transformMetadata (metadata) { + return metadata } /** @@ -68,12 +67,12 @@ export default class BoltProtocol { * @param {object} authToken the authentication token. * @param {StreamObserver} observer the response observer. */ - initialize(clientName, authToken, observer) { - const message = RequestMessage.init(clientName, authToken); - this._connection.write(message, observer, true); + initialize (clientName, authToken, observer) { + const message = RequestMessage.init(clientName, authToken) + this._connection.write(message, observer, true) } - prepareToClose(observer) { + prepareToClose (observer) { // no need to notify the database in this protocol version } @@ -84,34 +83,51 @@ export default class BoltProtocol { * @param {string} mode the access mode. * @param {StreamObserver} observer the response observer. */ - beginTransaction(bookmark, txConfig, mode, observer) { - assertTxConfigIsEmpty(txConfig, this._connection, observer); + beginTransaction (bookmark, txConfig, mode, observer) { + assertTxConfigIsEmpty(txConfig, this._connection, observer) - const runMessage = RequestMessage.run('BEGIN', bookmark.asBeginTransactionParameters()); - const pullAllMessage = RequestMessage.pullAll(); + const runMessage = RequestMessage.run( + 'BEGIN', + bookmark.asBeginTransactionParameters() + ) + const pullAllMessage = RequestMessage.pullAll() - this._connection.write(runMessage, observer, false); - this._connection.write(pullAllMessage, observer, false); + this._connection.write(runMessage, observer, false) + this._connection.write(pullAllMessage, observer, false) } /** * Commit the explicit transaction. * @param {StreamObserver} observer the response observer. */ - commitTransaction(observer) { + commitTransaction (observer) { // WRITE access mode is used as a place holder here, it has // no effect on behaviour for Bolt V1 & V2 - this.run('COMMIT', {}, Bookmark.empty(), TxConfig.empty(), ACCESS_MODE_WRITE, observer); + this.run( + 'COMMIT', + {}, + Bookmark.empty(), + TxConfig.empty(), + ACCESS_MODE_WRITE, + observer + ) } /** * Rollback the explicit transaction. * @param {StreamObserver} observer the response observer. */ - rollbackTransaction(observer) { + rollbackTransaction (observer) { // WRITE access mode is used as a place holder here, it has // no effect on behaviour for Bolt V1 & V2 - this.run('ROLLBACK', {}, Bookmark.empty(), TxConfig.empty(), ACCESS_MODE_WRITE, observer); + this.run( + 'ROLLBACK', + {}, + Bookmark.empty(), + TxConfig.empty(), + ACCESS_MODE_WRITE, + observer + ) } /** @@ -123,32 +139,32 @@ export default class BoltProtocol { * @param {string} mode the access mode. * @param {StreamObserver} observer the response observer. */ - run(statement, parameters, bookmark, txConfig, mode, observer) { + run (statement, parameters, bookmark, txConfig, mode, observer) { // bookmark and mode are ignored in this versioon of the protocol - assertTxConfigIsEmpty(txConfig, this._connection, observer); + assertTxConfigIsEmpty(txConfig, this._connection, observer) - const runMessage = RequestMessage.run(statement, parameters); - const pullAllMessage = RequestMessage.pullAll(); + const runMessage = RequestMessage.run(statement, parameters) + const pullAllMessage = RequestMessage.pullAll() - this._connection.write(runMessage, observer, false); - this._connection.write(pullAllMessage, observer, true); + this._connection.write(runMessage, observer, false) + this._connection.write(pullAllMessage, observer, true) } /** * Send a RESET through the underlying connection. * @param {StreamObserver} observer the response observer. */ - reset(observer) { - const message = RequestMessage.reset(); - this._connection.write(message, observer, true); + reset (observer) { + const message = RequestMessage.reset() + this._connection.write(message, observer, true) } - _createPacker(chunker) { - return new v1.Packer(chunker); + _createPacker (chunker) { + return new v1.Packer(chunker) } - _createUnpacker(disableLosslessIntegers) { - return new v1.Unpacker(disableLosslessIntegers); + _createUnpacker (disableLosslessIntegers) { + return new v1.Unpacker(disableLosslessIntegers) } } @@ -157,14 +173,16 @@ export default class BoltProtocol { * @param {Connection} connection the connection. * @param {StreamObserver} observer the response observer. */ -function assertTxConfigIsEmpty(txConfig, connection, observer) { +function assertTxConfigIsEmpty (txConfig, connection, observer) { if (!txConfig.isEmpty()) { - const error = newError('Driver is connected to the database that does not support transaction configuration. ' + - 'Please upgrade to neo4j 3.5.0 or later in order to use this functionality'); + const error = newError( + 'Driver is connected to the database that does not support transaction configuration. ' + + 'Please upgrade to neo4j 3.5.0 or later in order to use this functionality' + ) // unsupported API was used, consider this a fatal error for the current connection - connection._handleFatalError(error); - observer.onError(error); - throw error; + connection._handleFatalError(error) + observer.onError(error) + throw error } } diff --git a/src/v1/internal/bolt-protocol-v2.js b/src/v1/internal/bolt-protocol-v2.js index e5830e2ee..4b8846301 100644 --- a/src/v1/internal/bolt-protocol-v2.js +++ b/src/v1/internal/bolt-protocol-v2.js @@ -16,20 +16,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import BoltProtocolV1 from './bolt-protocol-v1'; -import * as v2 from './packstream-v2'; +import BoltProtocolV1 from './bolt-protocol-v1' +import * as v2 from './packstream-v2' export default class BoltProtocol extends BoltProtocolV1 { - - constructor(connection, chunker, disableLosslessIntegers) { - super(connection, chunker, disableLosslessIntegers); - } - - _createPacker(chunker) { - return new v2.Packer(chunker); + _createPacker (chunker) { + return new v2.Packer(chunker) } - _createUnpacker(disableLosslessIntegers) { - return new v2.Unpacker(disableLosslessIntegers); + _createUnpacker (disableLosslessIntegers) { + return new v2.Unpacker(disableLosslessIntegers) } } diff --git a/src/v1/internal/bolt-protocol-v3.js b/src/v1/internal/bolt-protocol-v3.js index 04096a344..175ef5dee 100644 --- a/src/v1/internal/bolt-protocol-v3.js +++ b/src/v1/internal/bolt-protocol-v3.js @@ -16,71 +16,75 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import BoltProtocolV2 from './bolt-protocol-v2'; -import RequestMessage from './request-message'; +import BoltProtocolV2 from './bolt-protocol-v2' +import RequestMessage from './request-message' export default class BoltProtocol extends BoltProtocolV2 { - - constructor(connection, chunker, disableLosslessIntegers) { - super(connection, chunker, disableLosslessIntegers); - } - - transformMetadata(metadata) { + transformMetadata (metadata) { if (metadata.t_first) { // Bolt V3 uses shorter key 't_first' to represent 'result_available_after' // adjust the key to be the same as in Bolt V1 so that ResultSummary can retrieve the value - metadata.result_available_after = metadata.t_first; - delete metadata.t_first; + metadata.result_available_after = metadata.t_first + delete metadata.t_first } if (metadata.t_last) { // Bolt V3 uses shorter key 't_last' to represent 'result_consumed_after' // adjust the key to be the same as in Bolt V1 so that ResultSummary can retrieve the value - metadata.result_consumed_after = metadata.t_last; - delete metadata.t_last; + metadata.result_consumed_after = metadata.t_last + delete metadata.t_last } - return metadata; + return metadata } - initialize(userAgent, authToken, observer) { - prepareToHandleSingleResponse(observer); - const message = RequestMessage.hello(userAgent, authToken); - this._connection.write(message, observer, true); + initialize (userAgent, authToken, observer) { + prepareToHandleSingleResponse(observer) + const message = RequestMessage.hello(userAgent, authToken) + this._connection.write(message, observer, true) } - prepareToClose(observer) { - const message = RequestMessage.goodbye(); - this._connection.write(message, observer, true); + prepareToClose (observer) { + const message = RequestMessage.goodbye() + this._connection.write(message, observer, true) } - beginTransaction(bookmark, txConfig, mode, observer) { - prepareToHandleSingleResponse(observer); - const message = RequestMessage.begin(bookmark, txConfig, mode); - this._connection.write(message, observer, true); + beginTransaction (bookmark, txConfig, mode, observer) { + prepareToHandleSingleResponse(observer) + const message = RequestMessage.begin(bookmark, txConfig, mode) + this._connection.write(message, observer, true) } - commitTransaction(observer) { - prepareToHandleSingleResponse(observer); - const message = RequestMessage.commit(); - this._connection.write(message, observer, true); + commitTransaction (observer) { + prepareToHandleSingleResponse(observer) + const message = RequestMessage.commit() + this._connection.write(message, observer, true) } - rollbackTransaction(observer) { - prepareToHandleSingleResponse(observer); - const message = RequestMessage.rollback(); - this._connection.write(message, observer, true); + rollbackTransaction (observer) { + prepareToHandleSingleResponse(observer) + const message = RequestMessage.rollback() + this._connection.write(message, observer, true) } - run(statement, parameters, bookmark, txConfig, mode, observer) { - const runMessage = RequestMessage.runWithMetadata(statement, parameters, bookmark, txConfig, mode); - const pullAllMessage = RequestMessage.pullAll(); + run (statement, parameters, bookmark, txConfig, mode, observer) { + const runMessage = RequestMessage.runWithMetadata( + statement, + parameters, + bookmark, + txConfig, + mode + ) + const pullAllMessage = RequestMessage.pullAll() - this._connection.write(runMessage, observer, false); - this._connection.write(pullAllMessage, observer, true); + this._connection.write(runMessage, observer, false) + this._connection.write(pullAllMessage, observer, true) } } -function prepareToHandleSingleResponse(observer) { - if (observer && typeof observer.prepareToHandleSingleResponse === 'function') { - observer.prepareToHandleSingleResponse(); +function prepareToHandleSingleResponse (observer) { + if ( + observer && + typeof observer.prepareToHandleSingleResponse === 'function' + ) { + observer.prepareToHandleSingleResponse() } } diff --git a/src/v1/internal/bookmark.js b/src/v1/internal/bookmark.js index 685e2999a..94de52fa1 100644 --- a/src/v1/internal/bookmark.js +++ b/src/v1/internal/bookmark.js @@ -17,60 +17,59 @@ * limitations under the License. */ -import * as util from './util'; +import * as util from './util' -const BOOKMARK_KEY = 'bookmark'; -const BOOKMARKS_KEY = 'bookmarks'; -const BOOKMARK_PREFIX = 'neo4j:bookmark:v1:tx'; +const BOOKMARK_KEY = 'bookmark' +const BOOKMARKS_KEY = 'bookmarks' +const BOOKMARK_PREFIX = 'neo4j:bookmark:v1:tx' -const UNKNOWN_BOOKMARK_VALUE = -1; +const UNKNOWN_BOOKMARK_VALUE = -1 export default class Bookmark { - /** * @constructor * @param {string|string[]} values single bookmark as string or multiple bookmarks as a string array. */ - constructor(values) { - this._values = asStringArray(values); - this._maxValue = maxBookmark(this._values); + constructor (values) { + this._values = asStringArray(values) + this._maxValue = maxBookmark(this._values) } - static empty() { - return EMPTY_BOOKMARK; + static empty () { + return EMPTY_BOOKMARK } /** * Check if the given bookmark is meaningful and can be send to the database. * @return {boolean} returns `true` bookmark has a value, `false` otherwise. */ - isEmpty() { - return this._maxValue === null; + isEmpty () { + return this._maxValue === null } /** * Get maximum value of this bookmark as string. * @return {string|null} the maximum value or `null` if it is not defined. */ - maxBookmarkAsString() { - return this._maxValue; + maxBookmarkAsString () { + return this._maxValue } /** * Get all bookmark values as an array. * @return {string[]} all values. */ - values() { - return this._values; + values () { + return this._values } /** * Get this bookmark as an object for begin transaction call. * @return {object} the value of this bookmark as object. */ - asBeginTransactionParameters() { + asBeginTransactionParameters () { if (this.isEmpty()) { - return {}; + return {} } // Driver sends {bookmark: "max", bookmarks: ["one", "two", "max"]} instead of simple @@ -80,42 +79,46 @@ export default class Bookmark { return { [BOOKMARK_KEY]: this._maxValue, [BOOKMARKS_KEY]: this._values - }; + } } } -const EMPTY_BOOKMARK = new Bookmark(null); +const EMPTY_BOOKMARK = new Bookmark(null) /** * Converts given value to an array. * @param {string|string[]} [value=undefined] argument to convert. * @return {string[]} value converted to an array. */ -function asStringArray(value) { +function asStringArray (value) { if (!value) { - return []; + return [] } if (util.isString(value)) { - return [value]; + return [value] } if (Array.isArray(value)) { - const result = []; + const result = [] for (let i = 0; i < value.length; i++) { - const element = value[i]; + const element = value[i] // if it is undefined or null, ignore it if (element !== undefined && element !== null) { if (!util.isString(element)) { - throw new TypeError(`Bookmark should be a string, given: '${element}'`); + throw new TypeError( + `Bookmark should be a string, given: '${element}'` + ) } - result.push(element); + result.push(element) } } - return result; + return result } - throw new TypeError(`Bookmark should either be a string or a string array, given: '${value}'`); + throw new TypeError( + `Bookmark should either be a string or a string array, given: '${value}'` + ) } /** @@ -123,25 +126,25 @@ function asStringArray(value) { * @param {string[]} bookmarks array of bookmarks. * @return {string|null} latest bookmark value. */ -function maxBookmark(bookmarks) { +function maxBookmark (bookmarks) { if (!bookmarks || bookmarks.length === 0) { - return null; + return null } - let maxBookmark = bookmarks[0]; - let maxValue = bookmarkValue(maxBookmark); + let maxBookmark = bookmarks[0] + let maxValue = bookmarkValue(maxBookmark) for (let i = 1; i < bookmarks.length; i++) { - const bookmark = bookmarks[i]; - const value = bookmarkValue(bookmark); + const bookmark = bookmarks[i] + const value = bookmarkValue(bookmark) if (value > maxValue) { - maxBookmark = bookmark; - maxValue = value; + maxBookmark = bookmark + maxValue = value } } - return maxBookmark; + return maxBookmark } /** @@ -149,10 +152,10 @@ function maxBookmark(bookmarks) { * @param {string} bookmark argument to get numeric value for. * @return {number} value of the bookmark. */ -function bookmarkValue(bookmark) { +function bookmarkValue (bookmark) { if (bookmark && bookmark.indexOf(BOOKMARK_PREFIX) === 0) { - const result = parseInt(bookmark.substring(BOOKMARK_PREFIX.length)); - return result ? result : UNKNOWN_BOOKMARK_VALUE; + const result = parseInt(bookmark.substring(BOOKMARK_PREFIX.length)) + return result || UNKNOWN_BOOKMARK_VALUE } - return UNKNOWN_BOOKMARK_VALUE; + return UNKNOWN_BOOKMARK_VALUE } diff --git a/src/v1/internal/browser/browser-buf.js b/src/v1/internal/browser/browser-buf.js index d70b76eb9..ed275322b 100644 --- a/src/v1/internal/browser/browser-buf.js +++ b/src/v1/internal/browser/browser-buf.js @@ -17,53 +17,52 @@ * limitations under the License. */ -import BaseBuffer from '../buf/base-buf'; +import BaseBuffer from '../buf/base-buf' export default class HeapBuffer extends BaseBuffer { - - constructor(arg) { - const buffer = arg instanceof ArrayBuffer ? arg : new ArrayBuffer(arg); - super(buffer.byteLength); - this._buffer = buffer; - this._view = new DataView(this._buffer); + constructor (arg) { + const buffer = arg instanceof ArrayBuffer ? arg : new ArrayBuffer(arg) + super(buffer.byteLength) + this._buffer = buffer + this._view = new DataView(this._buffer) } - putUInt8(position, val) { - this._view.setUint8(position, val); + putUInt8 (position, val) { + this._view.setUint8(position, val) } - getUInt8(position) { - return this._view.getUint8(position); + getUInt8 (position) { + return this._view.getUint8(position) } - putInt8(position, val) { - this._view.setInt8(position, val); + putInt8 (position, val) { + this._view.setInt8(position, val) } - getInt8(position) { - return this._view.getInt8(position); + getInt8 (position) { + return this._view.getInt8(position) } - getFloat64(position) { - return this._view.getFloat64(position); + getFloat64 (position) { + return this._view.getFloat64(position) } - putFloat64(position, val) { - this._view.setFloat64(position, val); + putFloat64 (position, val) { + this._view.setFloat64(position, val) } - getSlice(start, length) { + getSlice (start, length) { if (this._buffer.slice) { - return new HeapBuffer(this._buffer.slice(start, start + length)); + return new HeapBuffer(this._buffer.slice(start, start + length)) } else { // Some platforms (eg. phantomjs) don't support slice, so fall back to a copy // We do this rather than return a SliceBuffer, because sliceBuffer cannot // be passed to native network write ops etc - we need ArrayBuffer for that - const copy = new HeapBuffer(length); + const copy = new HeapBuffer(length) for (let i = 0; i < length; i++) { - copy.putUInt8(i, this.getUInt8(i + start)); + copy.putUInt8(i, this.getUInt8(i + start)) } - return copy; + return copy } } @@ -71,7 +70,7 @@ export default class HeapBuffer extends BaseBuffer { * Specific to HeapBuffer, this gets a DataView from the * current position and of the specified length. */ - readView(length) { - return new DataView(this._buffer, this._updatePos(length), length); + readView (length) { + return new DataView(this._buffer, this._updatePos(length), length) } } diff --git a/src/v1/internal/browser/browser-channel.js b/src/v1/internal/browser/browser-channel.js index 10ee4ff7c..b81038c48 100644 --- a/src/v1/internal/browser/browser-channel.js +++ b/src/v1/internal/browser/browser-channel.js @@ -17,93 +17,98 @@ * limitations under the License. */ -import HeapBuffer from './browser-buf'; -import {newError} from '../../error'; -import {ENCRYPTION_OFF, ENCRYPTION_ON} from '../util'; +import HeapBuffer from './browser-buf' +import { newError } from '../../error' +import { ENCRYPTION_OFF, ENCRYPTION_ON } from '../util' /** * Create a new WebSocketChannel to be used in web browsers. * @access private */ export default class WebSocketChannel { - /** * Create new instance * @param {ChannelConfig} config - configuration for this channel. * @param {function(): string} protocolSupplier - function that detects protocol of the web page. Should only be used in tests. */ - constructor(config, protocolSupplier = detectWebPageProtocol) { - - this._open = true; - this._pending = []; - this._error = null; - this._handleConnectionError = this._handleConnectionError.bind(this); - this._config = config; - - const {scheme, error} = determineWebSocketScheme(config, protocolSupplier); + constructor (config, protocolSupplier = detectWebPageProtocol) { + this._open = true + this._pending = [] + this._error = null + this._handleConnectionError = this._handleConnectionError.bind(this) + this._config = config + + const { scheme, error } = determineWebSocketScheme(config, protocolSupplier) if (error) { - this._error = error; - return; + this._error = error + return } - this._ws = createWebSocket(scheme, config.address); - this._ws.binaryType = "arraybuffer"; + this._ws = createWebSocket(scheme, config.address) + this._ws.binaryType = 'arraybuffer' - let self = this; - //All connection errors are not sent to the error handler - //we must also check for dirty close calls - this._ws.onclose = function(e) { - if (!e.wasClean) { - self._handleConnectionError(); - } - }; - this._ws.onopen = function() { + let self = this + // All connection errors are not sent to the error handler + // we must also check for dirty close calls + this._ws.onclose = function (e) { + if (!e.wasClean) { + self._handleConnectionError() + } + } + this._ws.onopen = function () { // Connected! Cancel the connection timeout - self._clearConnectionTimeout(); + self._clearConnectionTimeout() // Drain all pending messages - let pending = self._pending; - self._pending = null; + let pending = self._pending + self._pending = null for (let i = 0; i < pending.length; i++) { - self.write( pending[i] ); + self.write(pending[i]) } - }; - this._ws.onmessage = (event) => { - if( self.onmessage ) { - const b = new HeapBuffer(event.data); - self.onmessage( b ); + } + this._ws.onmessage = event => { + if (self.onmessage) { + const b = new HeapBuffer(event.data) + self.onmessage(b) } - }; + } - this._ws.onerror = this._handleConnectionError; + this._ws.onerror = this._handleConnectionError - this._connectionTimeoutFired = false; - this._connectionTimeoutId = this._setupConnectionTimeout(); + this._connectionTimeoutFired = false + this._connectionTimeoutId = this._setupConnectionTimeout() } - _handleConnectionError() { + _handleConnectionError () { if (this._connectionTimeoutFired) { // timeout fired - not connected within configured time - this._error = newError(`Failed to establish connection in ${this._config.connectionTimeout}ms`, this._config.connectionErrorCode); + this._error = newError( + `Failed to establish connection in ${this._config.connectionTimeout}ms`, + this._config.connectionErrorCode + ) if (this.onerror) { - this.onerror(this._error); + this.onerror(this._error) } - return; + return } // onerror triggers on websocket close as well.. don't get me started. - if( this._open ) { + if (this._open) { // http://stackoverflow.com/questions/25779831/how-to-catch-websocket-connection-to-ws-xxxnn-failed-connection-closed-be - this._error = newError( "WebSocket connection failure. Due to security " + - "constraints in your web browser, the reason for the failure is not available " + - "to this Neo4j Driver. Please use your browsers development console to determine " + - "the root cause of the failure. Common reasons include the database being " + - "unavailable, using the wrong connection URL or temporary network problems. " + - "If you have enabled encryption, ensure your browser is configured to trust the " + - 'certificate Neo4j is configured to use. WebSocket `readyState` is: ' + this._ws.readyState, this._config.connectionErrorCode); + this._error = newError( + 'WebSocket connection failure. Due to security ' + + 'constraints in your web browser, the reason for the failure is not available ' + + 'to this Neo4j Driver. Please use your browsers development console to determine ' + + 'the root cause of the failure. Common reasons include the database being ' + + 'unavailable, using the wrong connection URL or temporary network problems. ' + + 'If you have enabled encryption, ensure your browser is configured to trust the ' + + 'certificate Neo4j is configured to use. WebSocket `readyState` is: ' + + this._ws.readyState, + this._config.connectionErrorCode + ) if (this.onerror) { - this.onerror(this._error); + this.onerror(this._error) } } } @@ -112,15 +117,15 @@ export default class WebSocketChannel { * Write the passed in buffer to connection * @param {HeapBuffer} buffer - Buffer to write */ - write ( buffer ) { + write (buffer) { // If there is a pending queue, push this on that queue. This means // we are not yet connected, so we queue things locally. - if( this._pending !== null ) { - this._pending.push( buffer ); - } else if( buffer instanceof HeapBuffer ) { - this._ws.send( buffer._buffer ); + if (this._pending !== null) { + this._pending.push(buffer) + } else if (buffer instanceof HeapBuffer) { + this._ws.send(buffer._buffer) } else { - throw newError( "Don't know how to send buffer: " + buffer ); + throw newError("Don't know how to send buffer: " + buffer) } } @@ -128,11 +133,11 @@ export default class WebSocketChannel { * Close the connection * @param {function} cb - Function to call on close. */ - close ( cb = ( () => null )) { - this._open = false; - this._clearConnectionTimeout(); - this._ws.close(); - this._ws.onclose = cb; + close (cb = () => null) { + this._open = false + this._clearConnectionTimeout() + this._ws.close() + this._ws.onclose = cb } /** @@ -140,43 +145,42 @@ export default class WebSocketChannel { * @return {number} the timeout id or null. * @private */ - _setupConnectionTimeout() { - const timeout = this._config.connectionTimeout; + _setupConnectionTimeout () { + const timeout = this._config.connectionTimeout if (timeout) { - const webSocket = this._ws; + const webSocket = this._ws return setTimeout(() => { if (webSocket.readyState !== WebSocket.OPEN) { - this._connectionTimeoutFired = true; - webSocket.close(); + this._connectionTimeoutFired = true + webSocket.close() } - }, timeout); + }, timeout) } - return null; + return null } /** * Remove active connection timeout, if any. * @private */ - _clearConnectionTimeout() { - const timeoutId = this._connectionTimeoutId; + _clearConnectionTimeout () { + const timeoutId = this._connectionTimeoutId if (timeoutId || timeoutId === 0) { - this._connectionTimeoutFired = false; - this._connectionTimeoutId = null; - clearTimeout(timeoutId); + this._connectionTimeoutFired = false + this._connectionTimeoutId = null + clearTimeout(timeoutId) } } } -function createWebSocket(scheme, address) { - const url = scheme + '://' + address.asHostPort(); +function createWebSocket (scheme, address) { + const url = scheme + '://' + address.asHostPort() try { - return new WebSocket(url); + return new WebSocket(url) } catch (error) { if (isIPv6AddressIssueOnWindows(error, address)) { - // WebSocket in IE and Edge browsers on Windows do not support regular IPv6 address syntax because they contain ':'. // It's an invalid character for UNC (https://en.wikipedia.org/wiki/IPv6_address#Literal_IPv6_addresses_in_UNC_path_names) // and Windows requires IPv6 to be changes in the following way: @@ -190,33 +194,33 @@ function createWebSocket(scheme, address) { // Creation of WebSocket with unconverted address results in SyntaxError without message or stacktrace. // That is why here we "catch" SyntaxError and rewrite IPv6 address if needed. - const windowsFriendlyUrl = asWindowsFriendlyIPv6Address(scheme, address); - return new WebSocket(windowsFriendlyUrl); + const windowsFriendlyUrl = asWindowsFriendlyIPv6Address(scheme, address) + return new WebSocket(windowsFriendlyUrl) } else { - throw error; + throw error } } } -function isIPv6AddressIssueOnWindows(error, address) { - return error.name === 'SyntaxError' && isIPv6Address(address.asHostPort()); +function isIPv6AddressIssueOnWindows (error, address) { + return error.name === 'SyntaxError' && isIPv6Address(address.asHostPort()) } -function isIPv6Address(hostAndPort) { - return hostAndPort.charAt(0) === '[' && hostAndPort.indexOf(']') !== -1; +function isIPv6Address (hostAndPort) { + return hostAndPort.charAt(0) === '[' && hostAndPort.indexOf(']') !== -1 } -function asWindowsFriendlyIPv6Address(scheme, address) { +function asWindowsFriendlyIPv6Address (scheme, address) { // replace all ':' with '-' - const hostWithoutColons = address.host().replace(new RegExp(':', 'g'), '-'); + const hostWithoutColons = address.host().replace(new RegExp(':', 'g'), '-') // replace '%' with 's' for link-local IPv6 address like 'fe80::1%lo0' - const hostWithoutPercent = hostWithoutColons.replace('%', 's'); + const hostWithoutPercent = hostWithoutColons.replace('%', 's') // append magic '.ipv6-literal.net' suffix - const ipv6Host = hostWithoutPercent + '.ipv6-literal.net'; + const ipv6Host = hostWithoutPercent + '.ipv6-literal.net' - return `${scheme}://${ipv6Host}:${address.port()}`; + return `${scheme}://${ipv6Host}:${address.port()}` } /** @@ -224,80 +228,93 @@ function asWindowsFriendlyIPv6Address(scheme, address) { * @param {function(): string} protocolSupplier - function that detects protocol of the web page. * @return {{scheme: string|null, error: Neo4jError|null}} object containing either scheme or error. */ -function determineWebSocketScheme(config, protocolSupplier) { - const encryptionOn = isEncryptionExplicitlyTurnedOn(config); - const encryptionOff = isEncryptionExplicitlyTurnedOff(config); - const trust = config.trust; - const secureProtocol = isProtocolSecure(protocolSupplier); - verifyEncryptionSettings(encryptionOn, encryptionOff, secureProtocol); +function determineWebSocketScheme (config, protocolSupplier) { + const encryptionOn = isEncryptionExplicitlyTurnedOn(config) + const encryptionOff = isEncryptionExplicitlyTurnedOff(config) + const trust = config.trust + const secureProtocol = isProtocolSecure(protocolSupplier) + verifyEncryptionSettings(encryptionOn, encryptionOff, secureProtocol) if (encryptionOff) { // encryption explicitly turned off in the config - return {scheme: 'ws', error: null}; + return { scheme: 'ws', error: null } } if (secureProtocol) { // driver is used in a secure https web page, use 'wss' - return {scheme: 'wss', error: null}; + return { scheme: 'wss', error: null } } if (encryptionOn) { // encryption explicitly requested in the config if (!trust || trust === 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES') { // trust strategy not specified or the only supported strategy is specified - return {scheme: 'wss', error: null}; + return { scheme: 'wss', error: null } } else { - const error = newError('The browser version of this driver only supports one trust ' + - 'strategy, \'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES\'. ' + trust + ' is not supported. Please ' + - 'either use TRUST_CUSTOM_CA_SIGNED_CERTIFICATES or disable encryption by setting ' + - '`encrypted:"' + ENCRYPTION_OFF + '"` in the driver configuration.'); - return {scheme: null, error: error}; + const error = newError( + 'The browser version of this driver only supports one trust ' + + "strategy, 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES'. " + + trust + + ' is not supported. Please ' + + 'either use TRUST_CUSTOM_CA_SIGNED_CERTIFICATES or disable encryption by setting ' + + '`encrypted:"' + + ENCRYPTION_OFF + + '"` in the driver configuration.' + ) + return { scheme: null, error: error } } } // default to unencrypted web socket - return {scheme: 'ws', error: null}; + return { scheme: 'ws', error: null } } /** * @param {ChannelConfig} config - configuration for the channel. * @return {boolean} `true` if encryption enabled in the config, `false` otherwise. */ -function isEncryptionExplicitlyTurnedOn(config) { - return config.encrypted === true || config.encrypted === ENCRYPTION_ON; +function isEncryptionExplicitlyTurnedOn (config) { + return config.encrypted === true || config.encrypted === ENCRYPTION_ON } /** * @param {ChannelConfig} config - configuration for the channel. * @return {boolean} `true` if encryption disabled in the config, `false` otherwise. */ -function isEncryptionExplicitlyTurnedOff(config) { - return config.encrypted === false || config.encrypted === ENCRYPTION_OFF; +function isEncryptionExplicitlyTurnedOff (config) { + return config.encrypted === false || config.encrypted === ENCRYPTION_OFF } /** * @param {function(): string} protocolSupplier - function that detects protocol of the web page. * @return {boolean} `true` if protocol returned by the given function is secure, `false` otherwise. */ -function isProtocolSecure(protocolSupplier) { - const protocol = typeof protocolSupplier === 'function' ? protocolSupplier() : ''; - return protocol && protocol.toLowerCase().indexOf('https') >= 0; +function isProtocolSecure (protocolSupplier) { + const protocol = + typeof protocolSupplier === 'function' ? protocolSupplier() : '' + return protocol && protocol.toLowerCase().indexOf('https') >= 0 } -function verifyEncryptionSettings(encryptionOn, encryptionOff, secureProtocol) { +function verifyEncryptionSettings (encryptionOn, encryptionOff, secureProtocol) { if (encryptionOn && !secureProtocol) { // encryption explicitly turned on for a driver used on a HTTP web page - console.warn('Neo4j driver is configured to use secure WebSocket on a HTTP web page. ' + - 'WebSockets might not work in a mixed content environment. ' + - 'Please consider configuring driver to not use encryption.'); + console.warn( + 'Neo4j driver is configured to use secure WebSocket on a HTTP web page. ' + + 'WebSockets might not work in a mixed content environment. ' + + 'Please consider configuring driver to not use encryption.' + ) } else if (encryptionOff && secureProtocol) { // encryption explicitly turned off for a driver used on a HTTPS web page - console.warn('Neo4j driver is configured to use insecure WebSocket on a HTTPS web page. ' + - 'WebSockets might not work in a mixed content environment. ' + - 'Please consider configuring driver to use encryption.'); + console.warn( + 'Neo4j driver is configured to use insecure WebSocket on a HTTPS web page. ' + + 'WebSockets might not work in a mixed content environment. ' + + 'Please consider configuring driver to use encryption.' + ) } } -function detectWebPageProtocol() { - return typeof window != 'undefined' && window.location ? window.location.protocol : null; +function detectWebPageProtocol () { + return typeof window !== 'undefined' && window.location + ? window.location.protocol + : null } diff --git a/src/v1/internal/browser/browser-host-name-resolver.js b/src/v1/internal/browser/browser-host-name-resolver.js index b069d891f..400fc35c9 100644 --- a/src/v1/internal/browser/browser-host-name-resolver.js +++ b/src/v1/internal/browser/browser-host-name-resolver.js @@ -17,11 +17,10 @@ * limitations under the License. */ -import BaseHostNameResolver from '../resolver/base-host-name-resolver'; +import BaseHostNameResolver from '../resolver/base-host-name-resolver' export default class BrowserHostNameResolver extends BaseHostNameResolver { - - resolve(address) { - return this._resolveToItself(address); + resolve (address) { + return this._resolveToItself(address) } } diff --git a/src/v1/internal/browser/browser-utf8.js b/src/v1/internal/browser/browser-utf8.js index 4a1cb8b15..c1475ed3c 100644 --- a/src/v1/internal/browser/browser-utf8.js +++ b/src/v1/internal/browser/browser-utf8.js @@ -17,31 +17,33 @@ * limitations under the License. */ -import HeapBuffer from '../browser/browser-buf'; -import textEncoding from 'text-encoding'; +import HeapBuffer from '../browser/browser-buf' +import textEncoding from 'text-encoding' -const encoder = new textEncoding.TextEncoder('utf-8'); -const decoder = new textEncoding.TextDecoder('utf-8'); +const encoder = new textEncoding.TextEncoder('utf-8') +const decoder = new textEncoding.TextDecoder('utf-8') -function encode(str) { - return new HeapBuffer(encoder.encode(str).buffer); +function encode (str) { + return new HeapBuffer(encoder.encode(str).buffer) } -function decode(buffer, length) { +function decode (buffer, length) { if (buffer instanceof HeapBuffer) { - return decoder.decode(buffer.readView(Math.min(length, buffer.length - buffer.position))); + return decoder.decode( + buffer.readView(Math.min(length, buffer.length - buffer.position)) + ) } else { // Copy the given buffer into a regular buffer and decode that - const tmpBuf = new HeapBuffer(length); + const tmpBuf = new HeapBuffer(length) for (let i = 0; i < length; i++) { - tmpBuf.writeUInt8(buffer.readUInt8()); + tmpBuf.writeUInt8(buffer.readUInt8()) } - tmpBuf.reset(); - return decoder.decode(tmpBuf.readView(length)); + tmpBuf.reset() + return decoder.decode(tmpBuf.readView(length)) } } export default { encode, decode -}; +} diff --git a/src/v1/internal/browser/index.js b/src/v1/internal/browser/index.js index f2bc2d458..926391373 100644 --- a/src/v1/internal/browser/index.js +++ b/src/v1/internal/browser/index.js @@ -17,10 +17,10 @@ * limitations under the License. */ -import HeapBuffer from './browser-buf'; -import WebSocketChannel from './browser-channel'; -import BrowserHosNameResolver from './browser-host-name-resolver'; -import utf8Codec from './browser-utf8'; +import HeapBuffer from './browser-buf' +import WebSocketChannel from './browser-channel' +import BrowserHosNameResolver from './browser-host-name-resolver' +import utf8Codec from './browser-utf8' /* @@ -33,7 +33,7 @@ NOTE: exports in this module should have exactly the same names/structure as exp */ -export const alloc = arg => new HeapBuffer(arg); -export const Channel = WebSocketChannel; -export const HostNameResolver = BrowserHosNameResolver; -export const utf8 = utf8Codec; +export const alloc = arg => new HeapBuffer(arg) +export const Channel = WebSocketChannel +export const HostNameResolver = BrowserHosNameResolver +export const utf8 = utf8Codec diff --git a/src/v1/internal/buf/base-buf.js b/src/v1/internal/buf/base-buf.js index 92044b631..9ff8a4150 100644 --- a/src/v1/internal/buf/base-buf.js +++ b/src/v1/internal/buf/base-buf.js @@ -27,74 +27,92 @@ * @access private */ export default class BaseBuffer { - /** * Create a instance with the injected size. * @constructor * @param {Integer} size */ - constructor(size) { - this.position = 0; - this.length = size; - // Calling these out - this is the required - // methods a subclass needs to implement - let getUInt8 = null; - let getInt8 = null; - let getFloat64 = null; - let getSlice = null; - let putFloat64 = null; - let putUInt8 = null; - let putInt8 = null; + constructor (size) { + this.position = 0 + this.length = size + } + + getUInt8 (position) { + throw new Error('Not implemented') + } + + getInt8 (position) { + throw new Error('Not implemented') + } + + getFloat64 (position) { + throw new Error('Not implemented') + } + + putUInt8 (position, val) { + throw new Error('Not implemented') + } + + putInt8 (position, val) { + throw new Error('Not implemented') + } + + putFloat64 (position, val) { + throw new Error('Not implemented') } /** * @param p */ - getInt16(p) { - return this.getInt8(p) << 8 - | this.getUInt8(p + 1); + getInt16 (p) { + return (this.getInt8(p) << 8) | this.getUInt8(p + 1) } /** * @param p */ - getUInt16(p) { - return this.getUInt8(p) << 8 - | this.getUInt8(p + 1); + getUInt16 (p) { + return (this.getUInt8(p) << 8) | this.getUInt8(p + 1) } /** * @param p */ - getInt32(p) { - return this.getInt8(p) << 24 - | this.getUInt8(p + 1) << 16 - | this.getUInt8(p + 2) << 8 - | this.getUInt8(p + 3); + getInt32 (p) { + return ( + (this.getInt8(p) << 24) | + (this.getUInt8(p + 1) << 16) | + (this.getUInt8(p + 2) << 8) | + this.getUInt8(p + 3) + ) } /** * @param p */ - getUInt32(p) { - return this.getUInt8(p) << 24 - | this.getUInt8(p + 1) << 16 - | this.getUInt8(p + 2) << 8 - | this.getUInt8(p + 3); + getUInt32 (p) { + return ( + (this.getUInt8(p) << 24) | + (this.getUInt8(p + 1) << 16) | + (this.getUInt8(p + 2) << 8) | + this.getUInt8(p + 3) + ) } /** * @param p */ - getInt64(p) { - return this.getInt8(p) << 56 - | this.getUInt8(p + 1) << 48 - | this.getUInt8(p + 2) << 40 - | this.getUInt8(p + 3) << 32 - | this.getUInt8(p + 4) << 24 - | this.getUInt8(p + 5) << 16 - | this.getUInt8(p + 6) << 8 - | this.getUInt8(p + 7); + getInt64 (p) { + return ( + (this.getInt8(p) << 56) | + (this.getUInt8(p + 1) << 48) | + (this.getUInt8(p + 2) << 40) | + (this.getUInt8(p + 3) << 32) | + (this.getUInt8(p + 4) << 24) | + (this.getUInt8(p + 5) << 16) | + (this.getUInt8(p + 6) << 8) | + this.getUInt8(p + 7) + ) } /** @@ -103,193 +121,193 @@ export default class BaseBuffer { * @param start * @param length */ - getSlice(start, length) { - return new SliceBuffer(start, length, this); + getSlice (start, length) { + return new SliceBuffer(start, length, this) } /** * @param p * @param val */ - putInt16(p, val) { - this.putInt8(p, val >> 8); - this.putUInt8(p + 1, val & 0xFF); + putInt16 (p, val) { + this.putInt8(p, val >> 8) + this.putUInt8(p + 1, val & 0xff) } /** * @param p * @param val */ - putUInt16(p, val) { - this.putUInt8(p, val >> 8 & 0xFF); - this.putUInt8(p + 1, val & 0xFF); + putUInt16 (p, val) { + this.putUInt8(p, (val >> 8) & 0xff) + this.putUInt8(p + 1, val & 0xff) } /** * @param p * @param val */ - putInt32(p, val) { - this.putInt8(p, val >> 24); - this.putUInt8(p + 1, val >> 16 & 0xFF); - this.putUInt8(p + 2, val >> 8 & 0xFF); - this.putUInt8(p + 3, val & 0xFF); + putInt32 (p, val) { + this.putInt8(p, val >> 24) + this.putUInt8(p + 1, (val >> 16) & 0xff) + this.putUInt8(p + 2, (val >> 8) & 0xff) + this.putUInt8(p + 3, val & 0xff) } /** * @param p * @param val */ - putUInt32(p, val) { - this.putUInt8(p, val >> 24 & 0xFF); - this.putUInt8(p + 1, val >> 16 & 0xFF); - this.putUInt8(p + 2, val >> 8 & 0xFF); - this.putUInt8(p + 3, val & 0xFF); + putUInt32 (p, val) { + this.putUInt8(p, (val >> 24) & 0xff) + this.putUInt8(p + 1, (val >> 16) & 0xff) + this.putUInt8(p + 2, (val >> 8) & 0xff) + this.putUInt8(p + 3, val & 0xff) } /** * @param p * @param val */ - putInt64(p, val) { - this.putInt8(p, val >> 48); - this.putUInt8(p + 1, val >> 42 & 0xFF); - this.putUInt8(p + 2, val >> 36 & 0xFF); - this.putUInt8(p + 3, val >> 30 & 0xFF); - this.putUInt8(p + 4, val >> 24 & 0xFF); - this.putUInt8(p + 5, val >> 16 & 0xFF); - this.putUInt8(p + 6, val >> 8 & 0xFF); - this.putUInt8(p + 7, val & 0xFF); + putInt64 (p, val) { + this.putInt8(p, val >> 48) + this.putUInt8(p + 1, (val >> 42) & 0xff) + this.putUInt8(p + 2, (val >> 36) & 0xff) + this.putUInt8(p + 3, (val >> 30) & 0xff) + this.putUInt8(p + 4, (val >> 24) & 0xff) + this.putUInt8(p + 5, (val >> 16) & 0xff) + this.putUInt8(p + 6, (val >> 8) & 0xff) + this.putUInt8(p + 7, val & 0xff) } /** * @param position * @param other */ - putBytes(position, other) { + putBytes (position, other) { for (let i = 0, end = other.remaining(); i < end; i++) { - this.putUInt8(position + i, other.readUInt8()); + this.putUInt8(position + i, other.readUInt8()) } } /** * Read from state position. */ - readUInt8() { - return this.getUInt8(this._updatePos(1)); + readUInt8 () { + return this.getUInt8(this._updatePos(1)) } /** * Read from state position. */ - readInt8() { - return this.getInt8(this._updatePos(1)); + readInt8 () { + return this.getInt8(this._updatePos(1)) } /** * Read from state position. */ - readUInt16() { - return this.getUInt16(this._updatePos(2)); + readUInt16 () { + return this.getUInt16(this._updatePos(2)) } /** * Read from state position. */ - readUInt32() { - return this.getUInt32(this._updatePos(4)); + readUInt32 () { + return this.getUInt32(this._updatePos(4)) } /** * Read from state position. */ - readInt16() { - return this.getInt16(this._updatePos(2)); + readInt16 () { + return this.getInt16(this._updatePos(2)) } /** * Read from state position. */ - readInt32() { - return this.getInt32(this._updatePos(4)); + readInt32 () { + return this.getInt32(this._updatePos(4)) } /** * Read from state position. */ - readInt64() { - return this.getInt32(this._updatePos(8)); + readInt64 () { + return this.getInt32(this._updatePos(8)) } /** * Read from state position. */ - readFloat64() { - return this.getFloat64(this._updatePos(8)); + readFloat64 () { + return this.getFloat64(this._updatePos(8)) } /** * Write to state position. * @param val */ - writeUInt8(val) { - this.putUInt8(this._updatePos(1), val); + writeUInt8 (val) { + this.putUInt8(this._updatePos(1), val) } /** * Write to state position. * @param val */ - writeInt8(val) { - this.putInt8(this._updatePos(1), val); + writeInt8 (val) { + this.putInt8(this._updatePos(1), val) } /** * Write to state position. * @param val */ - writeInt16(val) { - this.putInt16(this._updatePos(2), val); + writeInt16 (val) { + this.putInt16(this._updatePos(2), val) } /** * Write to state position. * @param val */ - writeInt32(val) { - this.putInt32(this._updatePos(4), val); + writeInt32 (val) { + this.putInt32(this._updatePos(4), val) } /** * Write to state position. * @param val */ - writeUInt32(val) { - this.putUInt32(this._updatePos(4), val); + writeUInt32 (val) { + this.putUInt32(this._updatePos(4), val) } /** * Write to state position. * @param val */ - writeInt64(val) { - this.putInt64(this._updatePos(8), val); + writeInt64 (val) { + this.putInt64(this._updatePos(8), val) } /** * Write to state position. * @param val */ - writeFloat64(val) { - this.putFloat64(this._updatePos(8), val); + writeFloat64 (val) { + this.putFloat64(this._updatePos(8), val) } /** * Write to state position. * @param val */ - writeBytes(val) { - this.putBytes(this._updatePos(val.remaining()), val); + writeBytes (val) { + this.putBytes(this._updatePos(val.remaining()), val) } /** @@ -297,62 +315,68 @@ export default class BaseBuffer { * but simply provides a slice view of this buffer * @param length */ - readSlice(length) { - return this.getSlice(this._updatePos(length), length); + readSlice (length) { + return this.getSlice(this._updatePos(length), length) } - _updatePos(length) { - let p = this.position; - this.position += length; - return p; + _updatePos (length) { + let p = this.position + this.position += length + return p } /** * Get remaining */ - remaining() { - return this.length - this.position; + remaining () { + return this.length - this.position } /** * Has remaining */ - hasRemaining() { - return this.remaining() > 0; + hasRemaining () { + return this.remaining() > 0 } /** * Reset position state */ - reset() { - this.position = 0; + reset () { + this.position = 0 } /** * Get string representation of buffer and it's state. * @return {string} Buffer as a string */ - toString() { - return this.constructor.name + '( position=' + this.position + ' )\n ' + this.toHex(); + toString () { + return ( + this.constructor.name + + '( position=' + + this.position + + ' )\n ' + + this.toHex() + ) } /** * Get string representation of buffer. * @return {string} Buffer as a string */ - toHex() { - let out = ''; + toHex () { + let out = '' for (let i = 0; i < this.length; i++) { - let hexByte = this.getUInt8(i).toString(16); + let hexByte = this.getUInt8(i).toString(16) if (hexByte.length === 1) { - hexByte = '0' + hexByte; + hexByte = '0' + hexByte } - out += hexByte; + out += hexByte if (i !== this.length - 1) { - out += ' '; + out += ' ' } } - return out; + return out } } @@ -361,34 +385,33 @@ export default class BaseBuffer { * @access private */ class SliceBuffer extends BaseBuffer { - - constructor(start, length, inner) { - super(length); - this._start = start; - this._inner = inner; + constructor (start, length, inner) { + super(length) + this._start = start + this._inner = inner } - putUInt8(position, val) { - this._inner.putUInt8(this._start + position, val); + putUInt8 (position, val) { + this._inner.putUInt8(this._start + position, val) } - getUInt8(position) { - return this._inner.getUInt8(this._start + position); + getUInt8 (position) { + return this._inner.getUInt8(this._start + position) } - putInt8(position, val) { - this._inner.putInt8(this._start + position, val); + putInt8 (position, val) { + this._inner.putInt8(this._start + position, val) } - putFloat64(position, val) { - this._inner.putFloat64(this._start + position, val); + putFloat64 (position, val) { + this._inner.putFloat64(this._start + position, val) } - getInt8(position) { - return this._inner.getInt8(this._start + position); + getInt8 (position) { + return this._inner.getInt8(this._start + position) } - getFloat64(position) { - return this._inner.getFloat64(this._start + position); + getFloat64 (position) { + return this._inner.getFloat64(this._start + position) } } diff --git a/src/v1/internal/buf/combined-buf.js b/src/v1/internal/buf/combined-buf.js index f1ab290a2..5c8a11038 100644 --- a/src/v1/internal/buf/combined-buf.js +++ b/src/v1/internal/buf/combined-buf.js @@ -17,56 +17,55 @@ * limitations under the License. */ -import BaseBuffer from './base-buf'; -import {alloc} from '../node'; +import BaseBuffer from './base-buf' +import { alloc } from '../node' /** * Buffer that combines multiple buffers, exposing them as one single buffer. */ export default class CombinedBuffer extends BaseBuffer { - - constructor(buffers) { - let length = 0; + constructor (buffers) { + let length = 0 for (let i = 0; i < buffers.length; i++) { - length += buffers[i].length; + length += buffers[i].length } - super(length); - this._buffers = buffers; + super(length) + this._buffers = buffers } - getUInt8(position) { + getUInt8 (position) { // Surely there's a faster way to do this.. some sort of lookup table thing? for (let i = 0; i < this._buffers.length; i++) { - const buffer = this._buffers[i]; + const buffer = this._buffers[i] // If the position is not in the current buffer, skip the current buffer if (position >= buffer.length) { - position -= buffer.length; + position -= buffer.length } else { - return buffer.getUInt8(position); + return buffer.getUInt8(position) } } } - getInt8(position) { + getInt8 (position) { // Surely there's a faster way to do this.. some sort of lookup table thing? for (let i = 0; i < this._buffers.length; i++) { - const buffer = this._buffers[i]; + const buffer = this._buffers[i] // If the position is not in the current buffer, skip the current buffer if (position >= buffer.length) { - position -= buffer.length; + position -= buffer.length } else { - return buffer.getInt8(position); + return buffer.getInt8(position) } } } - getFloat64(position) { + getFloat64 (position) { // At some point, a more efficient impl. For now, we copy the 8 bytes // we want to read and depend on the platform impl of IEEE 754. - const b = alloc(8); + const b = alloc(8) for (let i = 0; i < 8; i++) { - b.putUInt8(i, this.getUInt8(position + i)); + b.putUInt8(i, this.getUInt8(position + i)) } - return b.getFloat64(0); + return b.getFloat64(0) } } diff --git a/src/v1/internal/channel-config.js b/src/v1/internal/channel-config.js index bfd9cf522..6760f5fc8 100644 --- a/src/v1/internal/channel-config.js +++ b/src/v1/internal/channel-config.js @@ -17,72 +17,89 @@ * limitations under the License. */ -import {newError, SERVICE_UNAVAILABLE} from '../error'; -import {ENCRYPTION_OFF, ENCRYPTION_ON} from './util'; +import { newError, SERVICE_UNAVAILABLE } from '../error' +import { ENCRYPTION_OFF, ENCRYPTION_ON } from './util' -const DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000; // 5 seconds by default +const DEFAULT_CONNECTION_TIMEOUT_MILLIS = 5000 // 5 seconds by default -const ALLOWED_VALUES_ENCRYPTED = [null, undefined, true, false, ENCRYPTION_ON, ENCRYPTION_OFF]; +const ALLOWED_VALUES_ENCRYPTED = [ + null, + undefined, + true, + false, + ENCRYPTION_ON, + ENCRYPTION_OFF +] -const ALLOWED_VALUES_TRUST = [null, undefined, 'TRUST_ALL_CERTIFICATES', 'TRUST_ON_FIRST_USE', - 'TRUST_SIGNED_CERTIFICATES', 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES', 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES']; +const ALLOWED_VALUES_TRUST = [ + null, + undefined, + 'TRUST_ALL_CERTIFICATES', + 'TRUST_ON_FIRST_USE', + 'TRUST_SIGNED_CERTIFICATES', + 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES', + 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES' +] export default class ChannelConfig { - /** * @constructor * @param {ServerAddress} address the address for the channel to connect to. * @param {object} driverConfig the driver config provided by the user when driver is created. * @param {string} connectionErrorCode the default error code to use on connection errors. */ - constructor(address, driverConfig, connectionErrorCode) { - this.address = address; - this.encrypted = extractEncrypted(driverConfig); - this.trust = extractTrust(driverConfig); - this.trustedCertificates = extractTrustedCertificates(driverConfig); - this.knownHostsPath = extractKnownHostsPath(driverConfig); - this.connectionErrorCode = connectionErrorCode || SERVICE_UNAVAILABLE; - this.connectionTimeout = extractConnectionTimeout(driverConfig); + constructor (address, driverConfig, connectionErrorCode) { + this.address = address + this.encrypted = extractEncrypted(driverConfig) + this.trust = extractTrust(driverConfig) + this.trustedCertificates = extractTrustedCertificates(driverConfig) + this.knownHostsPath = extractKnownHostsPath(driverConfig) + this.connectionErrorCode = connectionErrorCode || SERVICE_UNAVAILABLE + this.connectionTimeout = extractConnectionTimeout(driverConfig) } } -function extractEncrypted(driverConfig) { - const value = driverConfig.encrypted; +function extractEncrypted (driverConfig) { + const value = driverConfig.encrypted if (ALLOWED_VALUES_ENCRYPTED.indexOf(value) === -1) { - throw newError(`Illegal value of the encrypted setting ${value}. Expected one of ${ALLOWED_VALUES_ENCRYPTED}`); + throw newError( + `Illegal value of the encrypted setting ${value}. Expected one of ${ALLOWED_VALUES_ENCRYPTED}` + ) } - return value; + return value } -function extractTrust(driverConfig) { - const value = driverConfig.trust; +function extractTrust (driverConfig) { + const value = driverConfig.trust if (ALLOWED_VALUES_TRUST.indexOf(value) === -1) { - throw newError(`Illegal value of the trust setting ${value}. Expected one of ${ALLOWED_VALUES_TRUST}`); + throw newError( + `Illegal value of the trust setting ${value}. Expected one of ${ALLOWED_VALUES_TRUST}` + ) } - return value; + return value } -function extractTrustedCertificates(driverConfig) { - return driverConfig.trustedCertificates || []; +function extractTrustedCertificates (driverConfig) { + return driverConfig.trustedCertificates || [] } -function extractKnownHostsPath(driverConfig) { - return driverConfig.knownHosts || null; +function extractKnownHostsPath (driverConfig) { + return driverConfig.knownHosts || null } -function extractConnectionTimeout(driverConfig) { - const configuredTimeout = parseInt(driverConfig.connectionTimeout, 10); +function extractConnectionTimeout (driverConfig) { + const configuredTimeout = parseInt(driverConfig.connectionTimeout, 10) if (configuredTimeout === 0) { // timeout explicitly configured to 0 - return null; + return null } else if (configuredTimeout && configuredTimeout < 0) { // timeout explicitly configured to a negative value - return null; + return null } else if (!configuredTimeout) { // timeout not configured, use default value - return DEFAULT_CONNECTION_TIMEOUT_MILLIS; + return DEFAULT_CONNECTION_TIMEOUT_MILLIS } else { // timeout configured, use the provided value - return configuredTimeout; + return configuredTimeout } } diff --git a/src/v1/internal/chunking.js b/src/v1/internal/chunking.js index 0a497277c..e05e91b3c 100644 --- a/src/v1/internal/chunking.js +++ b/src/v1/internal/chunking.js @@ -17,75 +17,74 @@ * limitations under the License. */ -import BaseBuffer from './buf/base-buf'; -import {alloc} from './node'; -import CombinedBuffer from './buf/combined-buf'; +import BaseBuffer from './buf/base-buf' +import { alloc } from './node' +import CombinedBuffer from './buf/combined-buf' -let - _CHUNK_HEADER_SIZE = 2, - _MESSAGE_BOUNDARY = 0x00, - _DEFAULT_BUFFER_SIZE = 1400; // http://stackoverflow.com/questions/2613734/maximum-packet-size-for-a-tcp-connection +let _CHUNK_HEADER_SIZE = 2 +let _MESSAGE_BOUNDARY = 0x00 +let _DEFAULT_BUFFER_SIZE = 1400 // http://stackoverflow.com/questions/2613734/maximum-packet-size-for-a-tcp-connection /** * Looks like a writable buffer, chunks output transparently into a channel below. * @access private */ class Chunker extends BaseBuffer { - constructor(channel, bufferSize) { - super(0); - this._bufferSize = bufferSize || _DEFAULT_BUFFER_SIZE; - this._ch = channel; - this._buffer = alloc(this._bufferSize); - this._currentChunkStart = 0; - this._chunkOpen = false; + constructor (channel, bufferSize) { + super(0) + this._bufferSize = bufferSize || _DEFAULT_BUFFER_SIZE + this._ch = channel + this._buffer = alloc(this._bufferSize) + this._currentChunkStart = 0 + this._chunkOpen = false } - putUInt8(position, val) { - this._ensure(1); - this._buffer.writeUInt8(val); + putUInt8 (position, val) { + this._ensure(1) + this._buffer.writeUInt8(val) } - putInt8(position, val) { - this._ensure(1); - this._buffer.writeInt8(val); + putInt8 (position, val) { + this._ensure(1) + this._buffer.writeInt8(val) } - putFloat64(position, val) { - this._ensure(8); - this._buffer.writeFloat64(val); + putFloat64 (position, val) { + this._ensure(8) + this._buffer.writeFloat64(val) } - putBytes(position, data) { + putBytes (position, data) { // TODO: If data is larger than our chunk size or so, we're very likely better off just passing this buffer on // rather than doing the copy here TODO: *however* note that we need some way to find out when the data has been // written (and thus the buffer can be re-used) if we take that approach while (data.remaining() > 0) { // Ensure there is an open chunk, and that it has at least one byte of space left - this._ensure(1); + this._ensure(1) if (this._buffer.remaining() > data.remaining()) { - this._buffer.writeBytes(data); + this._buffer.writeBytes(data) } else { - this._buffer.writeBytes(data.readSlice(this._buffer.remaining())); + this._buffer.writeBytes(data.readSlice(this._buffer.remaining())) } } - return this; + return this } - flush() { + flush () { if (this._buffer.position > 0) { - this._closeChunkIfOpen(); + this._closeChunkIfOpen() // Local copy and clear the buffer field. This ensures that the buffer is not re-released if the flush call fails - let out = this._buffer; - this._buffer = null; + let out = this._buffer + this._buffer = null - this._ch.write(out.getSlice(0, out.position)); + this._ch.write(out.getSlice(0, out.position)) // Alloc a new output buffer. We assume we're using NodeJS's buffer pooling under the hood here! - this._buffer = alloc(this._bufferSize); - this._chunkOpen = false; + this._buffer = alloc(this._bufferSize) + this._chunkOpen = false } - return this; + return this } /** @@ -93,114 +92,110 @@ class Chunker extends BaseBuffer { * is encoded as a 0-length chunk, `00 00`. This inserts such a message boundary, closing * any currently open chunk as needed */ - messageBoundary() { - - this._closeChunkIfOpen(); + messageBoundary () { + this._closeChunkIfOpen() if (this._buffer.remaining() < _CHUNK_HEADER_SIZE) { - this.flush(); + this.flush() } // Write message boundary - this._buffer.writeInt16(_MESSAGE_BOUNDARY); + this._buffer.writeInt16(_MESSAGE_BOUNDARY) } /** Ensure at least the given size is available for writing */ - _ensure(size) { - let toWriteSize = this._chunkOpen ? size : size + _CHUNK_HEADER_SIZE; + _ensure (size) { + let toWriteSize = this._chunkOpen ? size : size + _CHUNK_HEADER_SIZE if (this._buffer.remaining() < toWriteSize) { - this.flush(); + this.flush() } if (!this._chunkOpen) { - this._currentChunkStart = this._buffer.position; - this._buffer.position = this._buffer.position + _CHUNK_HEADER_SIZE; - this._chunkOpen = true; + this._currentChunkStart = this._buffer.position + this._buffer.position = this._buffer.position + _CHUNK_HEADER_SIZE + this._chunkOpen = true } } - _closeChunkIfOpen() { + _closeChunkIfOpen () { if (this._chunkOpen) { - let chunkSize = this._buffer.position - (this._currentChunkStart + _CHUNK_HEADER_SIZE); - this._buffer.putUInt16(this._currentChunkStart, chunkSize); - this._chunkOpen = false; + let chunkSize = + this._buffer.position - (this._currentChunkStart + _CHUNK_HEADER_SIZE) + this._buffer.putUInt16(this._currentChunkStart, chunkSize) + this._chunkOpen = false } } } - /** * Combines chunks until a complete message is gathered up, and then forwards that * message to an 'onmessage' listener. * @access private */ class Dechunker { - constructor() { - this._currentMessage = []; - this._partialChunkHeader = 0; - this._state = this.AWAITING_CHUNK; + constructor () { + this._currentMessage = [] + this._partialChunkHeader = 0 + this._state = this.AWAITING_CHUNK } - AWAITING_CHUNK(buf) { + AWAITING_CHUNK (buf) { if (buf.remaining() >= 2) { // Whole header available, read that - return this._onHeader(buf.readUInt16()); + return this._onHeader(buf.readUInt16()) } else { // Only one byte available, read that and wait for the second byte - this._partialChunkHeader = buf.readUInt8() << 8; - return this.IN_HEADER; + this._partialChunkHeader = buf.readUInt8() << 8 + return this.IN_HEADER } } - IN_HEADER(buf) { + IN_HEADER (buf) { // First header byte read, now we read the next one - return this._onHeader((this._partialChunkHeader | buf.readUInt8()) & 0xFFFF); + return this._onHeader((this._partialChunkHeader | buf.readUInt8()) & 0xffff) } - IN_CHUNK(buf) { + IN_CHUNK (buf) { if (this._chunkSize <= buf.remaining()) { // Current packet is larger than current chunk, or same size: - this._currentMessage.push(buf.readSlice(this._chunkSize)); - return this.AWAITING_CHUNK; + this._currentMessage.push(buf.readSlice(this._chunkSize)) + return this.AWAITING_CHUNK } else { // Current packet is smaller than the chunk we're reading, split the current chunk itself up - this._chunkSize -= buf.remaining(); - this._currentMessage.push(buf.readSlice(buf.remaining())); - return this.IN_CHUNK; + this._chunkSize -= buf.remaining() + this._currentMessage.push(buf.readSlice(buf.remaining())) + return this.IN_CHUNK } } - CLOSED(buf) { + CLOSED (buf) { // no-op } /** Called when a complete chunk header has been received */ - _onHeader(header) { - if (header == 0) { + _onHeader (header) { + if (header === 0) { // Message boundary - let message; - if (this._currentMessage.length == 1) { - message = this._currentMessage[0]; + let message + if (this._currentMessage.length === 1) { + message = this._currentMessage[0] } else { - message = new CombinedBuffer( this._currentMessage ); + message = new CombinedBuffer(this._currentMessage) } - this._currentMessage = []; - this.onmessage(message); - return this.AWAITING_CHUNK; + this._currentMessage = [] + this.onmessage(message) + return this.AWAITING_CHUNK } else { - this._chunkSize = header; - return this.IN_CHUNK; + this._chunkSize = header + return this.IN_CHUNK } } - write(buf) { + write (buf) { while (buf.hasRemaining()) { - this._state = this._state(buf); + this._state = this._state(buf) } } } -export { - Chunker, - Dechunker -} +export { Chunker, Dechunker } diff --git a/src/v1/internal/connection-error-handler.js b/src/v1/internal/connection-error-handler.js index 3c1def379..d027aae13 100644 --- a/src/v1/internal/connection-error-handler.js +++ b/src/v1/internal/connection-error-handler.js @@ -17,22 +17,21 @@ * limitations under the License. */ -import {SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../error'; +import { SERVICE_UNAVAILABLE, SESSION_EXPIRED } from '../error' export default class ConnectionErrorHandler { - - constructor(errorCode, handleUnavailability, handleWriteFailure) { - this._errorCode = errorCode; - this._handleUnavailability = handleUnavailability || noOpHandler; - this._handleWriteFailure = handleWriteFailure || noOpHandler; + constructor (errorCode, handleUnavailability, handleWriteFailure) { + this._errorCode = errorCode + this._handleUnavailability = handleUnavailability || noOpHandler + this._handleWriteFailure = handleWriteFailure || noOpHandler } /** * Error code to use for network errors. * @return {string} the error code. */ - errorCode() { - return this._errorCode; + errorCode () { + return this._errorCode } /** @@ -41,34 +40,38 @@ export default class ConnectionErrorHandler { * @param {ServerAddress} address the address of the connection where the error happened. * @return {Neo4jError} new error that should be propagated to the user. */ - handleAndTransformError(error, address) { + handleAndTransformError (error, address) { if (isAvailabilityError(error)) { - return this._handleUnavailability(error, address); + return this._handleUnavailability(error, address) } if (isFailureToWrite(error)) { - return this._handleWriteFailure(error, address); + return this._handleWriteFailure(error, address) } - return error; + return error } } -function isAvailabilityError(error) { +function isAvailabilityError (error) { if (error) { - return error.code === SESSION_EXPIRED || + return ( + error.code === SESSION_EXPIRED || error.code === SERVICE_UNAVAILABLE || - error.code === 'Neo.TransientError.General.DatabaseUnavailable'; + error.code === 'Neo.TransientError.General.DatabaseUnavailable' + ) } - return false; + return false } -function isFailureToWrite(error) { +function isFailureToWrite (error) { if (error) { - return error.code === 'Neo.ClientError.Cluster.NotALeader' || - error.code === 'Neo.ClientError.General.ForbiddenOnReadOnlyDatabase'; + return ( + error.code === 'Neo.ClientError.Cluster.NotALeader' || + error.code === 'Neo.ClientError.General.ForbiddenOnReadOnlyDatabase' + ) } - return false; + return false } -function noOpHandler(error) { - return error; +function noOpHandler (error) { + return error } diff --git a/src/v1/internal/connection-holder.js b/src/v1/internal/connection-holder.js index 047ec75be..94141ccd1 100644 --- a/src/v1/internal/connection-holder.js +++ b/src/v1/internal/connection-holder.js @@ -17,42 +17,43 @@ * limitations under the License. */ -import {newError} from '../error'; +import { newError } from '../error' /** * Utility to lazily initialize connections and return them back to the pool when unused. */ export default class ConnectionHolder { - /** * @constructor * @param {string} mode - the access mode for new connection holder. * @param {ConnectionProvider} connectionProvider - the connection provider to acquire connections from. */ - constructor(mode, connectionProvider) { - this._mode = mode; - this._connectionProvider = connectionProvider; - this._referenceCount = 0; - this._connectionPromise = Promise.resolve(null); + constructor (mode, connectionProvider) { + this._mode = mode + this._connectionProvider = connectionProvider + this._referenceCount = 0 + this._connectionPromise = Promise.resolve(null) } /** * Returns the assigned access mode. * @returns {string} access mode */ - mode() { - return this._mode; + mode () { + return this._mode } /** * Make this holder initialize new connection if none exists already. * @return {undefined} */ - initializeConnection() { + initializeConnection () { if (this._referenceCount === 0) { - this._connectionPromise = this._connectionProvider.acquireConnection(this._mode); + this._connectionPromise = this._connectionProvider.acquireConnection( + this._mode + ) } - this._referenceCount++; + this._referenceCount++ } /** @@ -60,39 +61,39 @@ export default class ConnectionHolder { * @param {StreamObserver} streamObserver an observer for this connection. * @return {Promise} promise resolved with the current connection. */ - getConnection(streamObserver) { + getConnection (streamObserver) { return this._connectionPromise.then(connection => { - streamObserver.resolveConnection(connection); - return connection; - }); + streamObserver.resolveConnection(connection) + return connection + }) } /** * Notify this holder that single party does not require current connection any more. * @return {Promise} promise resolved with the current connection, never a rejected promise. */ - releaseConnection() { + releaseConnection () { if (this._referenceCount === 0) { - return this._connectionPromise; + return this._connectionPromise } - this._referenceCount--; + this._referenceCount-- if (this._referenceCount === 0) { - return this._releaseConnection(); + return this._releaseConnection() } - return this._connectionPromise; + return this._connectionPromise } /** * Closes this holder and releases current connection (if any) despite any existing users. * @return {Promise} promise resolved when current connection is released to the pool. */ - close() { + close () { if (this._referenceCount === 0) { - return this._connectionPromise; + return this._connectionPromise } - this._referenceCount = 0; - return this._releaseConnection(); + this._referenceCount = 0 + return this._releaseConnection() } /** @@ -102,45 +103,48 @@ export default class ConnectionHolder { * @return {Promise} - promise resolved then connection is returned to the pool. * @private */ - _releaseConnection() { - this._connectionPromise = this._connectionPromise.then(connection => { - if (connection) { - return connection.resetAndFlush() - .catch(ignoreError) - .then(() => connection._release()); - } else { - return Promise.resolve(); - } - }).catch(ignoreError); - - return this._connectionPromise; + _releaseConnection () { + this._connectionPromise = this._connectionPromise + .then(connection => { + if (connection) { + return connection + .resetAndFlush() + .catch(ignoreError) + .then(() => connection._release()) + } else { + return Promise.resolve() + } + }) + .catch(ignoreError) + + return this._connectionPromise } } class EmptyConnectionHolder extends ConnectionHolder { - - initializeConnection() { + initializeConnection () { // nothing to initialize } - getConnection(streamObserver) { - return Promise.reject(newError('This connection holder does not serve connections')); + getConnection (streamObserver) { + return Promise.reject( + newError('This connection holder does not serve connections') + ) } - releaseConnection() { - return Promise.resolve(); + releaseConnection () { + return Promise.resolve() } - close() { - return Promise.resolve(); + close () { + return Promise.resolve() } } -function ignoreError(error) { -} +function ignoreError () {} /** * Connection holder that does not manage any connections. * @type {ConnectionHolder} */ -export const EMPTY_CONNECTION_HOLDER = new EmptyConnectionHolder(); +export const EMPTY_CONNECTION_HOLDER = new EmptyConnectionHolder() diff --git a/src/v1/internal/connection-providers.js b/src/v1/internal/connection-providers.js index 9072fa9cd..0a220d5ca 100644 --- a/src/v1/internal/connection-providers.js +++ b/src/v1/internal/connection-providers.js @@ -17,274 +17,349 @@ * limitations under the License. */ -import {newError, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../error'; -import {READ, WRITE} from '../driver'; -import Session from '../session'; -import RoutingTable from './routing-table'; -import Rediscovery from './rediscovery'; -import RoutingUtil from './routing-util'; -import { HostNameResolver } from './node'; +import { newError, SERVICE_UNAVAILABLE, SESSION_EXPIRED } from '../error' +import { READ, WRITE } from '../driver' +import Session from '../session' +import RoutingTable from './routing-table' +import Rediscovery from './rediscovery' +import RoutingUtil from './routing-util' +import { HostNameResolver } from './node' -const UNAUTHORIZED_ERROR_CODE = 'Neo.ClientError.Security.Unauthorized'; +const UNAUTHORIZED_ERROR_CODE = 'Neo.ClientError.Security.Unauthorized' class ConnectionProvider { - - acquireConnection(mode) { - throw new Error('Abstract function'); + acquireConnection (mode) { + throw new Error('Abstract function') } - _withAdditionalOnErrorCallback(connectionPromise, driverOnErrorCallback) { + _withAdditionalOnErrorCallback (connectionPromise, driverOnErrorCallback) { // install error handler from the driver on the connection promise; this callback is installed separately // so that it does not handle errors, instead it is just an additional error reporting facility. connectionPromise.catch(error => { - driverOnErrorCallback(error); - }); + driverOnErrorCallback(error) + }) // return the original connection promise - return connectionPromise; + return connectionPromise } } export class DirectConnectionProvider extends ConnectionProvider { - - constructor(address, connectionPool, driverOnErrorCallback) { - super(); - this._address = address; - this._connectionPool = connectionPool; - this._driverOnErrorCallback = driverOnErrorCallback; + constructor (address, connectionPool, driverOnErrorCallback) { + super() + this._address = address + this._connectionPool = connectionPool + this._driverOnErrorCallback = driverOnErrorCallback } - acquireConnection(mode) { - const connectionPromise = this._connectionPool.acquire(this._address); - return this._withAdditionalOnErrorCallback(connectionPromise, this._driverOnErrorCallback); + acquireConnection (mode) { + const connectionPromise = this._connectionPool.acquire(this._address) + return this._withAdditionalOnErrorCallback( + connectionPromise, + this._driverOnErrorCallback + ) } } export class LoadBalancer extends ConnectionProvider { - - constructor(address, routingContext, connectionPool, loadBalancingStrategy, hostNameResolver, driverOnErrorCallback, log) { - super(); - this._seedRouter = address; - this._routingTable = new RoutingTable(); - this._rediscovery = new Rediscovery(new RoutingUtil(routingContext)); - this._connectionPool = connectionPool; - this._driverOnErrorCallback = driverOnErrorCallback; - this._loadBalancingStrategy = loadBalancingStrategy; - this._hostNameResolver = hostNameResolver; - this._dnsResolver = new HostNameResolver(); - this._log = log; - this._useSeedRouter = true; + constructor ( + address, + routingContext, + connectionPool, + loadBalancingStrategy, + hostNameResolver, + driverOnErrorCallback, + log + ) { + super() + this._seedRouter = address + this._routingTable = new RoutingTable() + this._rediscovery = new Rediscovery(new RoutingUtil(routingContext)) + this._connectionPool = connectionPool + this._driverOnErrorCallback = driverOnErrorCallback + this._loadBalancingStrategy = loadBalancingStrategy + this._hostNameResolver = hostNameResolver + this._dnsResolver = new HostNameResolver() + this._log = log + this._useSeedRouter = true } - acquireConnection(accessMode) { - const connectionPromise = this._freshRoutingTable(accessMode).then(routingTable => { - if (accessMode === READ) { - const address = this._loadBalancingStrategy.selectReader(routingTable.readers); - return this._acquireConnectionToServer(address, 'read'); - } else if (accessMode === WRITE) { - const address = this._loadBalancingStrategy.selectWriter(routingTable.writers); - return this._acquireConnectionToServer(address, 'write'); - } else { - throw newError('Illegal mode ' + accessMode); + acquireConnection (accessMode) { + const connectionPromise = this._freshRoutingTable(accessMode).then( + routingTable => { + if (accessMode === READ) { + const address = this._loadBalancingStrategy.selectReader( + routingTable.readers + ) + return this._acquireConnectionToServer(address, 'read') + } else if (accessMode === WRITE) { + const address = this._loadBalancingStrategy.selectWriter( + routingTable.writers + ) + return this._acquireConnectionToServer(address, 'write') + } else { + throw newError('Illegal mode ' + accessMode) + } } - }); - return this._withAdditionalOnErrorCallback(connectionPromise, this._driverOnErrorCallback); + ) + return this._withAdditionalOnErrorCallback( + connectionPromise, + this._driverOnErrorCallback + ) } - forget(address) { - this._routingTable.forget(address); - this._connectionPool.purge(address); + forget (address) { + this._routingTable.forget(address) + this._connectionPool.purge(address) } - forgetWriter(address) { - this._routingTable.forgetWriter(address); + forgetWriter (address) { + this._routingTable.forgetWriter(address) } - _acquireConnectionToServer(address, serverName) { + _acquireConnectionToServer (address, serverName) { if (!address) { - return Promise.reject(newError( - `Failed to obtain connection towards ${serverName} server. Known routing table is: ${this._routingTable}`, - SESSION_EXPIRED)); + return Promise.reject( + newError( + `Failed to obtain connection towards ${serverName} server. Known routing table is: ${ + this._routingTable + }`, + SESSION_EXPIRED + ) + ) } - return this._connectionPool.acquire(address); + return this._connectionPool.acquire(address) } - _freshRoutingTable(accessMode) { - const currentRoutingTable = this._routingTable; + _freshRoutingTable (accessMode) { + const currentRoutingTable = this._routingTable if (!currentRoutingTable.isStaleFor(accessMode)) { - return Promise.resolve(currentRoutingTable); + return Promise.resolve(currentRoutingTable) } - this._log.info(`Routing table is stale for ${accessMode}: ${currentRoutingTable}`); - return this._refreshRoutingTable(currentRoutingTable); + this._log.info( + `Routing table is stale for ${accessMode}: ${currentRoutingTable}` + ) + return this._refreshRoutingTable(currentRoutingTable) } - _refreshRoutingTable(currentRoutingTable) { - const knownRouters = currentRoutingTable.routers; + _refreshRoutingTable (currentRoutingTable) { + const knownRouters = currentRoutingTable.routers if (this._useSeedRouter) { - return this._fetchRoutingTableFromSeedRouterFallbackToKnownRouters(knownRouters, currentRoutingTable); + return this._fetchRoutingTableFromSeedRouterFallbackToKnownRouters( + knownRouters, + currentRoutingTable + ) } - return this._fetchRoutingTableFromKnownRoutersFallbackToSeedRouter(knownRouters, currentRoutingTable); + return this._fetchRoutingTableFromKnownRoutersFallbackToSeedRouter( + knownRouters, + currentRoutingTable + ) } - _fetchRoutingTableFromSeedRouterFallbackToKnownRouters(knownRouters, currentRoutingTable) { + _fetchRoutingTableFromSeedRouterFallbackToKnownRouters ( + knownRouters, + currentRoutingTable + ) { // we start with seed router, no routers were probed before - const seenRouters = []; - return this._fetchRoutingTableUsingSeedRouter(seenRouters, this._seedRouter).then(newRoutingTable => { - if (newRoutingTable) { - this._useSeedRouter = false; - return newRoutingTable; - } + const seenRouters = [] + return this._fetchRoutingTableUsingSeedRouter(seenRouters, this._seedRouter) + .then(newRoutingTable => { + if (newRoutingTable) { + this._useSeedRouter = false + return newRoutingTable + } - // seed router did not return a valid routing table - try to use other known routers - return this._fetchRoutingTableUsingKnownRouters(knownRouters, currentRoutingTable); - }).then(newRoutingTable => { - this._applyRoutingTableIfPossible(newRoutingTable); - return newRoutingTable; - }); + // seed router did not return a valid routing table - try to use other known routers + return this._fetchRoutingTableUsingKnownRouters( + knownRouters, + currentRoutingTable + ) + }) + .then(newRoutingTable => { + this._applyRoutingTableIfPossible(newRoutingTable) + return newRoutingTable + }) } - _fetchRoutingTableFromKnownRoutersFallbackToSeedRouter(knownRouters, currentRoutingTable) { - return this._fetchRoutingTableUsingKnownRouters(knownRouters, currentRoutingTable).then(newRoutingTable => { - if (newRoutingTable) { - return newRoutingTable; - } + _fetchRoutingTableFromKnownRoutersFallbackToSeedRouter ( + knownRouters, + currentRoutingTable + ) { + return this._fetchRoutingTableUsingKnownRouters( + knownRouters, + currentRoutingTable + ) + .then(newRoutingTable => { + if (newRoutingTable) { + return newRoutingTable + } - // none of the known routers returned a valid routing table - try to use seed router address for rediscovery - return this._fetchRoutingTableUsingSeedRouter(knownRouters, this._seedRouter); - }).then(newRoutingTable => { - this._applyRoutingTableIfPossible(newRoutingTable); - return newRoutingTable; - }); + // none of the known routers returned a valid routing table - try to use seed router address for rediscovery + return this._fetchRoutingTableUsingSeedRouter( + knownRouters, + this._seedRouter + ) + }) + .then(newRoutingTable => { + this._applyRoutingTableIfPossible(newRoutingTable) + return newRoutingTable + }) } - _fetchRoutingTableUsingKnownRouters(knownRouters, currentRoutingTable) { - return this._fetchRoutingTable(knownRouters, currentRoutingTable).then(newRoutingTable => { - if (newRoutingTable) { - // one of the known routers returned a valid routing table - use it - return newRoutingTable; - } + _fetchRoutingTableUsingKnownRouters (knownRouters, currentRoutingTable) { + return this._fetchRoutingTable(knownRouters, currentRoutingTable).then( + newRoutingTable => { + if (newRoutingTable) { + // one of the known routers returned a valid routing table - use it + return newRoutingTable + } - // returned routing table was undefined, this means a connection error happened and the last known - // router did not return a valid routing table, so we need to forget it - const lastRouterIndex = knownRouters.length - 1; - LoadBalancer._forgetRouter(currentRoutingTable, knownRouters, lastRouterIndex); + // returned routing table was undefined, this means a connection error happened and the last known + // router did not return a valid routing table, so we need to forget it + const lastRouterIndex = knownRouters.length - 1 + LoadBalancer._forgetRouter( + currentRoutingTable, + knownRouters, + lastRouterIndex + ) - return null; - }); + return null + } + ) } - _fetchRoutingTableUsingSeedRouter(seenRouters, seedRouter) { - const resolvedAddresses = this._resolveSeedRouter(seedRouter); + _fetchRoutingTableUsingSeedRouter (seenRouters, seedRouter) { + const resolvedAddresses = this._resolveSeedRouter(seedRouter) return resolvedAddresses.then(resolvedRouterAddresses => { // filter out all addresses that we've already tried - const newAddresses = resolvedRouterAddresses.filter(address => seenRouters.indexOf(address) < 0); - return this._fetchRoutingTable(newAddresses, null); - }); + const newAddresses = resolvedRouterAddresses.filter( + address => seenRouters.indexOf(address) < 0 + ) + return this._fetchRoutingTable(newAddresses, null) + }) } - _resolveSeedRouter(seedRouter) { - const customResolution = this._hostNameResolver.resolve(seedRouter); + _resolveSeedRouter (seedRouter) { + const customResolution = this._hostNameResolver.resolve(seedRouter) const dnsResolutions = customResolution.then(resolvedAddresses => { - return Promise.all(resolvedAddresses.map(address => { - return this._dnsResolver.resolve(address); - })); - }); + return Promise.all( + resolvedAddresses.map(address => { + return this._dnsResolver.resolve(address) + }) + ) + }) return dnsResolutions.then(results => { - return [].concat.apply([], results); - }); + return [].concat.apply([], results) + }) } - _fetchRoutingTable(routerAddresses, routingTable) { - return routerAddresses.reduce((refreshedTablePromise, currentRouter, currentIndex) => { - return refreshedTablePromise.then(newRoutingTable => { - if (newRoutingTable) { - // valid routing table was fetched - just return it, try next router otherwise - return newRoutingTable; - } else { - // returned routing table was undefined, this means a connection error happened and we need to forget the - // previous router and try the next one - const previousRouterIndex = currentIndex - 1; - LoadBalancer._forgetRouter(routingTable, routerAddresses, previousRouterIndex); - } - - // try next router - return this._createSessionForRediscovery(currentRouter).then(session => { - if (session) { - return this._rediscovery.lookupRoutingTableOnRouter(session, currentRouter).catch(error => { - this._log.warn(`unable to fetch routing table because of an error ${error}`); - return null; - }); + _fetchRoutingTable (routerAddresses, routingTable) { + return routerAddresses.reduce( + (refreshedTablePromise, currentRouter, currentIndex) => { + return refreshedTablePromise.then(newRoutingTable => { + if (newRoutingTable) { + // valid routing table was fetched - just return it, try next router otherwise + return newRoutingTable } else { - // unable to acquire connection and create session towards the current router - // return null to signal that the next router should be tried - return null; + // returned routing table was undefined, this means a connection error happened and we need to forget the + // previous router and try the next one + const previousRouterIndex = currentIndex - 1 + LoadBalancer._forgetRouter( + routingTable, + routerAddresses, + previousRouterIndex + ) } - }); - }); - }, Promise.resolve(null)); + + // try next router + return this._createSessionForRediscovery(currentRouter).then( + session => { + if (session) { + return this._rediscovery + .lookupRoutingTableOnRouter(session, currentRouter) + .catch(error => { + this._log.warn( + `unable to fetch routing table because of an error ${error}` + ) + return null + }) + } else { + // unable to acquire connection and create session towards the current router + // return null to signal that the next router should be tried + return null + } + } + ) + }) + }, + Promise.resolve(null) + ) } - _createSessionForRediscovery(routerAddress) { - return this._connectionPool.acquire(routerAddress) + _createSessionForRediscovery (routerAddress) { + return this._connectionPool + .acquire(routerAddress) .then(connection => { - const connectionProvider = new SingleConnectionProvider(connection); - return new Session(READ, connectionProvider); + const connectionProvider = new SingleConnectionProvider(connection) + return new Session(READ, connectionProvider) }) .catch(error => { // unable to acquire connection towards the given router if (error && error.code === UNAUTHORIZED_ERROR_CODE) { // auth error is a sign of a configuration issue, rediscovery should not proceed - throw error; + throw error } - return null; - }); + return null + }) } - _applyRoutingTableIfPossible(newRoutingTable) { + _applyRoutingTableIfPossible (newRoutingTable) { if (!newRoutingTable) { // none of routing servers returned valid routing table, throw exception throw newError( - `Could not perform discovery. No routing servers available. Known routing table: ${this._routingTable}`, - SERVICE_UNAVAILABLE); + `Could not perform discovery. No routing servers available. Known routing table: ${ + this._routingTable + }`, + SERVICE_UNAVAILABLE + ) } if (newRoutingTable.writers.length === 0) { // use seed router next time. this is important when cluster is partitioned. it tries to make sure driver // does not always get routing table without writers because it talks exclusively to a minority partition - this._useSeedRouter = true; + this._useSeedRouter = true } - this._updateRoutingTable(newRoutingTable); + this._updateRoutingTable(newRoutingTable) } - _updateRoutingTable(newRoutingTable) { + _updateRoutingTable (newRoutingTable) { // close old connections to servers not present in the new routing table - this._connectionPool.keepAll(newRoutingTable.allServers()); + this._connectionPool.keepAll(newRoutingTable.allServers()) // make this driver instance aware of the new table - this._routingTable = newRoutingTable; - this._log.info(`Updated routing table ${newRoutingTable}`); + this._routingTable = newRoutingTable + this._log.info(`Updated routing table ${newRoutingTable}`) } - static _forgetRouter(routingTable, routersArray, routerIndex) { - const address = routersArray[routerIndex]; + static _forgetRouter (routingTable, routersArray, routerIndex) { + const address = routersArray[routerIndex] if (routingTable && address) { - routingTable.forgetRouter(address); + routingTable.forgetRouter(address) } } } export class SingleConnectionProvider extends ConnectionProvider { - - constructor(connection) { - super(); - this._connection = connection; + constructor (connection) { + super() + this._connection = connection } - acquireConnection(mode) { - const connection = this._connection; - this._connection = null; - return Promise.resolve(connection); + acquireConnection (mode) { + const connection = this._connection + this._connection = null + return Promise.resolve(connection) } } diff --git a/src/v1/internal/connection.js b/src/v1/internal/connection.js index d24c4a5f2..395cb18db 100644 --- a/src/v1/internal/connection.js +++ b/src/v1/internal/connection.js @@ -17,35 +17,30 @@ * limitations under the License. */ -import {Channel} from './node'; -import {Chunker, Dechunker} from './chunking'; -import {newError, PROTOCOL_ERROR} from './../error'; -import ChannelConfig from './channel-config'; -import urlUtil from './url-util'; -import StreamObserver from './stream-observer'; -import {ServerVersion, VERSION_3_2_0} from './server-version'; -import Logger from './logger'; -import ProtocolHandshaker from './protocol-handshaker'; -import RequestMessage from './request-message'; +import { Channel } from './node' +import { Chunker, Dechunker } from './chunking' +import { newError, PROTOCOL_ERROR } from './../error' +import ChannelConfig from './channel-config' +import { ServerVersion, VERSION_3_2_0 } from './server-version' +import ProtocolHandshaker from './protocol-handshaker' // Signature bytes for each response message type -const SUCCESS = 0x70; // 0111 0000 // SUCCESS -const RECORD = 0x71; // 0111 0001 // RECORD -const IGNORED = 0x7E; // 0111 1110 // IGNORED -const FAILURE = 0x7F; // 0111 1111 // FAILURE +const SUCCESS = 0x70 // 0111 0000 // SUCCESS +const RECORD = 0x71 // 0111 0001 // RECORD +const IGNORED = 0x7e // 0111 1110 // IGNORED +const FAILURE = 0x7f // 0111 1111 // FAILURE -function NO_OP(){} +function NO_OP () {} const NO_OP_OBSERVER = { - onNext : NO_OP, - onCompleted : NO_OP, - onError : NO_OP -}; + onNext: NO_OP, + onCompleted: NO_OP, + onError: NO_OP +} -let idGenerator = 0; +let idGenerator = 0 export default class Connection { - /** * @constructor * @param {Channel} channel - channel with a 'write' function and a 'onmessage' callback property. @@ -54,34 +49,40 @@ export default class Connection { * @param {Logger} log - the configured logger. * @param {boolean} disableLosslessIntegers if this connection should convert all received integers to native JS numbers. */ - constructor(channel, errorHandler, address, log, disableLosslessIntegers = false) { - this.id = idGenerator++; - this.address = address; - this.server = { address: address.asHostPort() }; - this.creationTimestamp = Date.now(); - this._errorHandler = errorHandler; - this._disableLosslessIntegers = disableLosslessIntegers; - this._pendingObservers = []; - this._currentObserver = undefined; - this._ch = channel; - this._dechunker = new Dechunker(); - this._chunker = new Chunker( channel ); - this._log = log; + constructor ( + channel, + errorHandler, + address, + log, + disableLosslessIntegers = false + ) { + this.id = idGenerator++ + this.address = address + this.server = { address: address.asHostPort() } + this.creationTimestamp = Date.now() + this._errorHandler = errorHandler + this._disableLosslessIntegers = disableLosslessIntegers + this._pendingObservers = [] + this._currentObserver = undefined + this._ch = channel + this._dechunker = new Dechunker() + this._chunker = new Chunker(channel) + this._log = log // connection from the database, returned in response for HELLO message and might not be available - this._dbConnectionId = null; + this._dbConnectionId = null // bolt protocol is initially not initialized - this._protocol = null; + this._protocol = null // error extracted from a FAILURE message - this._currentFailure = null; + this._currentFailure = null // Set to true on fatal errors, to get this out of connection pool. - this._isBroken = false; + this._isBroken = false if (this._log.isDebugEnabled()) { - this._log.debug(`${this} created towards ${address}`); + this._log.debug(`${this} created towards ${address}`) } } @@ -93,9 +94,19 @@ export default class Connection { * @param {Logger} log - configured logger. * @return {Connection} - new connection. */ - static create(address, config, errorHandler, log) { - const channelConfig = new ChannelConfig(address, config, errorHandler.errorCode()); - return new Connection(new Channel(channelConfig), errorHandler, address, log, config.disableLosslessIntegers); + static create (address, config, errorHandler, log) { + const channelConfig = new ChannelConfig( + address, + config, + errorHandler.errorCode() + ) + return new Connection( + new Channel(channelConfig), + errorHandler, + address, + log, + config.disableLosslessIntegers + ) } /** @@ -104,59 +115,66 @@ export default class Connection { * @param {object} authToken the object containing auth information. * @return {Promise} promise resolved with the current connection if connection is successful. Rejected promise otherwise. */ - connect(userAgent, authToken) { - return this._negotiateProtocol().then(() => this._initialize(userAgent, authToken)); + connect (userAgent, authToken) { + return this._negotiateProtocol().then(() => + this._initialize(userAgent, authToken) + ) } /** * Execute Bolt protocol handshake to initialize the protocol version. * @return {Promise} promise resolved with the current connection if handshake is successful. Rejected promise otherwise. */ - _negotiateProtocol() { - const protocolHandshaker = new ProtocolHandshaker(this, this._ch, this._chunker, this._disableLosslessIntegers, this._log); + _negotiateProtocol () { + const protocolHandshaker = new ProtocolHandshaker( + this, + this._ch, + this._chunker, + this._disableLosslessIntegers, + this._log + ) return new Promise((resolve, reject) => { - const handshakeErrorHandler = error => { - this._handleFatalError(error); - reject(error); - }; + this._handleFatalError(error) + reject(error) + } - this._ch.onerror = handshakeErrorHandler.bind(this); + this._ch.onerror = handshakeErrorHandler.bind(this) if (this._ch._error) { // channel is already broken - handshakeErrorHandler(this._ch._error); + handshakeErrorHandler(this._ch._error) } this._ch.onmessage = buffer => { try { // read the response buffer and initialize the protocol - this._protocol = protocolHandshaker.createNegotiatedProtocol(buffer); + this._protocol = protocolHandshaker.createNegotiatedProtocol(buffer) // reset the error handler to just handle errors and forget about the handshake promise - this._ch.onerror = this._handleFatalError.bind(this); + this._ch.onerror = this._handleFatalError.bind(this) // Ok, protocol running. Simply forward all messages to the dechunker - this._ch.onmessage = buf => this._dechunker.write(buf); + this._ch.onmessage = buf => this._dechunker.write(buf) // setup dechunker to dechunk messages and forward them to the message handler - this._dechunker.onmessage = (buf) => { - this._handleMessage(this._protocol.unpacker().unpack(buf)); - }; + this._dechunker.onmessage = buf => { + this._handleMessage(this._protocol.unpacker().unpack(buf)) + } // forward all pending bytes to the dechunker if (buffer.hasRemaining()) { - this._dechunker.write(buffer.readSlice(buffer.remaining())); + this._dechunker.write(buffer.readSlice(buffer.remaining())) } - resolve(this); + resolve(this) } catch (e) { - this._handleFatalError(e); - reject(e); + this._handleFatalError(e) + reject(e) } - }; + } - protocolHandshaker.writeHandshakeRequest(); - }); + protocolHandshaker.writeHandshakeRequest() + }) } /** @@ -165,19 +183,19 @@ export default class Connection { * @param {object} authToken the object containing auth information. * @return {Promise} promise resolved with the current connection if initialization is successful. Rejected promise otherwise. */ - _initialize(userAgent, authToken) { + _initialize (userAgent, authToken) { return new Promise((resolve, reject) => { - const observer = new InitializationObserver(this, resolve, reject); - this._protocol.initialize(userAgent, authToken, observer); - }); + const observer = new InitializationObserver(this, resolve, reject) + this._protocol.initialize(userAgent, authToken, observer) + }) } /** * Get the Bolt protocol for the connection. * @return {BoltProtocol} the protocol. */ - protocol() { - return this._protocol; + protocol () { + return this._protocol } /** @@ -186,23 +204,26 @@ export default class Connection { * @param {StreamObserver} observer the response observer. * @param {boolean} flush `true` if flush should happen after the message is written to the buffer. */ - write(message, observer, flush) { - const queued = this._queueObserver(observer); + write (message, observer, flush) { + const queued = this._queueObserver(observer) if (queued) { if (this._log.isDebugEnabled()) { - this._log.debug(`${this} C: ${message}`); + this._log.debug(`${this} C: ${message}`) } - this._protocol.packer().packStruct( - message.signature, - message.fields.map(field => this._packable(field)), - err => this._handleFatalError(err)); + this._protocol + .packer() + .packStruct( + message.signature, + message.fields.map(field => this._packable(field)), + err => this._handleFatalError(err) + ) - this._chunker.messageBoundary(); + this._chunker.messageBoundary() if (flush) { - this._chunker.flush(); + this._chunker.flush() } } } @@ -214,81 +235,94 @@ export default class Connection { * * @param error an error object, forwarded to all current and future subscribers */ - _handleFatalError(error) { - this._isBroken = true; - this._error = this._errorHandler.handleAndTransformError(error, this.address); + _handleFatalError (error) { + this._isBroken = true + this._error = this._errorHandler.handleAndTransformError( + error, + this.address + ) if (this._log.isErrorEnabled()) { - this._log.error(`${this} experienced a fatal error ${JSON.stringify(this._error)}`); + this._log.error( + `${this} experienced a fatal error ${JSON.stringify(this._error)}` + ) } if (this._currentObserver && this._currentObserver.onError) { - this._currentObserver.onError(this._error); + this._currentObserver.onError(this._error) } while (this._pendingObservers.length > 0) { - let observer = this._pendingObservers.shift(); + let observer = this._pendingObservers.shift() if (observer && observer.onError) { - observer.onError(this._error); + observer.onError(this._error) } } } - _handleMessage( msg ) { + _handleMessage (msg) { if (this._isBroken) { // ignore all incoming messages when this connection is broken. all previously pending observers failed // with the fatal error. all future observers will fail with same fatal error. - return; + return } - const payload = msg.fields[0]; + const payload = msg.fields[0] - switch( msg.signature ) { + switch (msg.signature) { case RECORD: if (this._log.isDebugEnabled()) { - this._log.debug(`${this} S: RECORD ${JSON.stringify(msg)}`); + this._log.debug(`${this} S: RECORD ${JSON.stringify(msg)}`) } - this._currentObserver.onNext( payload ); - break; + this._currentObserver.onNext(payload) + break case SUCCESS: if (this._log.isDebugEnabled()) { - this._log.debug(`${this} S: SUCCESS ${JSON.stringify(msg)}`); + this._log.debug(`${this} S: SUCCESS ${JSON.stringify(msg)}`) } try { - const metadata = this._protocol.transformMetadata(payload); - this._currentObserver.onCompleted(metadata); + const metadata = this._protocol.transformMetadata(payload) + this._currentObserver.onCompleted(metadata) } finally { - this._updateCurrentObserver(); + this._updateCurrentObserver() } - break; + break case FAILURE: if (this._log.isDebugEnabled()) { - this._log.debug(`${this} S: FAILURE ${JSON.stringify(msg)}`); + this._log.debug(`${this} S: FAILURE ${JSON.stringify(msg)}`) } try { - const error = newError(payload.message, payload.code); - this._currentFailure = this._errorHandler.handleAndTransformError(error, this.address); - this._currentObserver.onError( this._currentFailure ); + const error = newError(payload.message, payload.code) + this._currentFailure = this._errorHandler.handleAndTransformError( + error, + this.address + ) + this._currentObserver.onError(this._currentFailure) } finally { - this._updateCurrentObserver(); + this._updateCurrentObserver() // Things are now broken. Pending observers will get FAILURE messages routed until we are done handling this failure. - this._resetOnFailure(); + this._resetOnFailure() } - break; + break case IGNORED: if (this._log.isDebugEnabled()) { - this._log.debug(`${this} S: IGNORED ${JSON.stringify(msg)}`); + this._log.debug(`${this} S: IGNORED ${JSON.stringify(msg)}`) } try { - if (this._currentFailure && this._currentObserver.onError) - this._currentObserver.onError(this._currentFailure); - else if(this._currentObserver.onError) - this._currentObserver.onError(newError('Ignored either because of an error or RESET')); + if (this._currentFailure && this._currentObserver.onError) { + this._currentObserver.onError(this._currentFailure) + } else if (this._currentObserver.onError) { + this._currentObserver.onError( + newError('Ignored either because of an error or RESET') + ) + } } finally { - this._updateCurrentObserver(); + this._updateCurrentObserver() } - break; + break default: - this._handleFatalError(newError("Unknown Bolt protocol message: " + msg)); + this._handleFatalError( + newError('Unknown Bolt protocol message: ' + msg) + ) } } @@ -296,155 +330,167 @@ export default class Connection { * Send a RESET-message to the database. Message is immediately flushed to the network. * @return {Promise} promise resolved when SUCCESS-message response arrives, or failed when other response messages arrives. */ - resetAndFlush() { + resetAndFlush () { return new Promise((resolve, reject) => { this._protocol.reset({ onNext: record => { - const neo4jError = this._handleProtocolError('Received RECORD as a response for RESET: ' + JSON.stringify(record)); - reject(neo4jError); + const neo4jError = this._handleProtocolError( + 'Received RECORD as a response for RESET: ' + JSON.stringify(record) + ) + reject(neo4jError) }, onError: error => { if (this._isBroken) { // handling a fatal error, no need to raise a protocol violation - reject(error); + reject(error) } else { - const neo4jError = this._handleProtocolError('Received FAILURE as a response for RESET: ' + error); - reject(neo4jError); + const neo4jError = this._handleProtocolError( + 'Received FAILURE as a response for RESET: ' + error + ) + reject(neo4jError) } }, onCompleted: () => { - resolve(); + resolve() } - }); - }); + }) + }) } - _resetOnFailure() { + _resetOnFailure () { this._protocol.reset({ onNext: record => { - this._handleProtocolError('Received RECORD as a response for RESET: ' + JSON.stringify(record)); + this._handleProtocolError( + 'Received RECORD as a response for RESET: ' + JSON.stringify(record) + ) }, // clear the current failure when response for RESET is received onError: () => { - this._currentFailure = null; + this._currentFailure = null }, onCompleted: () => { - this._currentFailure = null; + this._currentFailure = null } - }); + }) } - _queueObserver(observer) { - if( this._isBroken ) { - if( observer && observer.onError ) { - observer.onError(this._error); + _queueObserver (observer) { + if (this._isBroken) { + if (observer && observer.onError) { + observer.onError(this._error) } - return false; + return false } - observer = observer || NO_OP_OBSERVER; - observer.onCompleted = observer.onCompleted || NO_OP; - observer.onError = observer.onError || NO_OP; - observer.onNext = observer.onNext || NO_OP; - if( this._currentObserver === undefined ) { - this._currentObserver = observer; + observer = observer || NO_OP_OBSERVER + observer.onCompleted = observer.onCompleted || NO_OP + observer.onError = observer.onError || NO_OP + observer.onNext = observer.onNext || NO_OP + if (this._currentObserver === undefined) { + this._currentObserver = observer } else { - this._pendingObservers.push( observer ); + this._pendingObservers.push(observer) } - return true; + return true } /* * Pop next pending observer form the list of observers and make it current observer. * @protected */ - _updateCurrentObserver() { - this._currentObserver = this._pendingObservers.shift(); + _updateCurrentObserver () { + this._currentObserver = this._pendingObservers.shift() } /** Check if this connection is in working condition */ - isOpen() { - return !this._isBroken && this._ch._open; + isOpen () { + return !this._isBroken && this._ch._open } /** * Call close on the channel. * @param {function} cb - Function to call on close. */ - close(cb = (() => null)) { + close (cb = () => null) { if (this._log.isDebugEnabled()) { - this._log.debug(`${this} closing`); + this._log.debug(`${this} closing`) } if (this._protocol && this.isOpen()) { // protocol has been initialized and this connection is healthy // notify the database about the upcoming close of the connection - this._protocol.prepareToClose(NO_OP_OBSERVER); + this._protocol.prepareToClose(NO_OP_OBSERVER) } this._ch.close(() => { if (this._log.isDebugEnabled()) { - this._log.debug(`${this} closed`); + this._log.debug(`${this} closed`) } - cb(); - }); + cb() + }) } - toString() { - const dbConnectionId = this._dbConnectionId || ''; - return `Connection [${this.id}][${dbConnectionId}]`; + toString () { + const dbConnectionId = this._dbConnectionId || '' + return `Connection [${this.id}][${dbConnectionId}]` } - _packable(value) { - return this._protocol.packer().packable(value, (err) => this._handleFatalError(err)); + _packable (value) { + return this._protocol + .packer() + .packable(value, err => this._handleFatalError(err)) } - _handleProtocolError(message) { - this._currentFailure = null; - this._updateCurrentObserver(); - const error = newError(message, PROTOCOL_ERROR); - this._handleFatalError(error); - return error; + _handleProtocolError (message) { + this._currentFailure = null + this._updateCurrentObserver() + const error = newError(message, PROTOCOL_ERROR) + this._handleFatalError(error) + return error } } class InitializationObserver { - - constructor(connection, onSuccess, onError) { - this._connection = connection; - this._onSuccess = onSuccess; - this._onError = onError; + constructor (connection, onSuccess, onError) { + this._connection = connection + this._onSuccess = onSuccess + this._onError = onError } - onNext(record) { - this.onError(newError('Received RECORD when initializing ' + JSON.stringify(record))); + onNext (record) { + this.onError( + newError('Received RECORD when initializing ' + JSON.stringify(record)) + ) } - onError(error) { - this._connection._updateCurrentObserver(); // make sure this exact observer will not be called again - this._connection._handleFatalError(error); // initialization errors are fatal + onError (error) { + this._connection._updateCurrentObserver() // make sure this exact observer will not be called again + this._connection._handleFatalError(error) // initialization errors are fatal - this._onError(error); + this._onError(error) } - onCompleted(metadata) { + onCompleted (metadata) { if (metadata) { // read server version from the response metadata, if it is available - const serverVersion = metadata.server; + const serverVersion = metadata.server if (!this._connection.server.version) { - this._connection.server.version = serverVersion; - const version = ServerVersion.fromString(serverVersion); + this._connection.server.version = serverVersion + const version = ServerVersion.fromString(serverVersion) if (version.compareTo(VERSION_3_2_0) < 0) { - this._connection.protocol().packer().disableByteArrays(); + this._connection + .protocol() + .packer() + .disableByteArrays() } } // read database connection id from the response metadata, if it is available - const dbConnectionId = metadata.connection_id; + const dbConnectionId = metadata.connection_id if (!this._connection._dbConnectionId) { - this._connection._dbConnectionId = dbConnectionId; + this._connection._dbConnectionId = dbConnectionId } } - this._onSuccess(this._connection); + this._onSuccess(this._connection) } } diff --git a/src/v1/internal/connectivity-verifier.js b/src/v1/internal/connectivity-verifier.js index 6d0b45c96..d862f6166 100644 --- a/src/v1/internal/connectivity-verifier.js +++ b/src/v1/internal/connectivity-verifier.js @@ -17,32 +17,32 @@ * limitations under the License. */ -import ConnectionHolder from './connection-holder'; -import {READ} from '../driver'; -import StreamObserver from './stream-observer'; +import ConnectionHolder from './connection-holder' +import { READ } from '../driver' +import StreamObserver from './stream-observer' /** * Verifies connectivity using the given connection provider. */ export default class ConnectivityVerifier { - /** * @constructor * @param {ConnectionProvider} connectionProvider the provider to obtain connections from. * @param {function} successCallback a callback to invoke when verification succeeds. */ - constructor(connectionProvider, successCallback) { - this._connectionProvider = connectionProvider; - this._successCallback = successCallback; + constructor (connectionProvider, successCallback) { + this._connectionProvider = connectionProvider + this._successCallback = successCallback } - verify() { - acquireAndReleaseDummyConnection(this._connectionProvider).then(serverInfo => { - if (this._successCallback) { - this._successCallback(serverInfo); - } - }).catch(ignoredError => { - }); + verify () { + acquireAndReleaseDummyConnection(this._connectionProvider) + .then(serverInfo => { + if (this._successCallback) { + this._successCallback(serverInfo) + } + }) + .catch(ignoredError => {}) } } @@ -51,21 +51,26 @@ export default class ConnectivityVerifier { * @param {ConnectionProvider} connectionProvider the provider to obtain connections from. * @return {Promise} promise resolved with server info or rejected with error. */ -function acquireAndReleaseDummyConnection(connectionProvider) { - const connectionHolder = new ConnectionHolder(READ, connectionProvider); - connectionHolder.initializeConnection(); - const dummyObserver = new StreamObserver(); - const connectionPromise = connectionHolder.getConnection(dummyObserver); +function acquireAndReleaseDummyConnection (connectionProvider) { + const connectionHolder = new ConnectionHolder(READ, connectionProvider) + connectionHolder.initializeConnection() + const dummyObserver = new StreamObserver() + const connectionPromise = connectionHolder.getConnection(dummyObserver) - return connectionPromise.then(connection => { - // able to establish a connection - return connectionHolder.close().then(() => connection.server); - }).catch(error => { - // failed to establish a connection - return connectionHolder.close().catch(ignoredError => { - // ignore connection release error - }).then(() => { - return Promise.reject(error); - }); - }); + return connectionPromise + .then(connection => { + // able to establish a connection + return connectionHolder.close().then(() => connection.server) + }) + .catch(error => { + // failed to establish a connection + return connectionHolder + .close() + .catch(ignoredError => { + // ignore connection release error + }) + .then(() => { + return Promise.reject(error) + }) + }) } diff --git a/src/v1/internal/constants.js b/src/v1/internal/constants.js index f60099caa..4dade13df 100644 --- a/src/v1/internal/constants.js +++ b/src/v1/internal/constants.js @@ -17,10 +17,7 @@ * limitations under the License. */ -const ACCESS_MODE_READ = 'READ'; -const ACCESS_MODE_WRITE = 'WRITE'; +const ACCESS_MODE_READ = 'READ' +const ACCESS_MODE_WRITE = 'WRITE' -export { - ACCESS_MODE_READ, - ACCESS_MODE_WRITE -} +export { ACCESS_MODE_READ, ACCESS_MODE_WRITE } diff --git a/src/v1/internal/http/http-driver.js b/src/v1/internal/http/http-driver.js index 434cd7795..faafc9f04 100644 --- a/src/v1/internal/http/http-driver.js +++ b/src/v1/internal/http/http-driver.js @@ -17,24 +17,28 @@ * limitations under the License. */ -import Driver from '../../driver'; -import HttpSession from './http-session'; -import HttpSessionTracker from './http-session-tracker'; -import ServerAddress from '../server-address'; +import Driver from '../../driver' +import HttpSession from './http-session' +import HttpSessionTracker from './http-session-tracker' +import ServerAddress from '../server-address' export default class HttpDriver extends Driver { - - constructor(url, userAgent, token, config) { - super(ServerAddress.fromUrl(url.hostAndPort), userAgent, token, config); - this._url = url; - this._sessionTracker = new HttpSessionTracker(); + constructor (url, userAgent, token, config) { + super(ServerAddress.fromUrl(url.hostAndPort), userAgent, token, config) + this._url = url + this._sessionTracker = new HttpSessionTracker() } - session() { - return new HttpSession(this._url, this._authToken, this._config, this._sessionTracker); + session () { + return new HttpSession( + this._url, + this._authToken, + this._config, + this._sessionTracker + ) } - close() { - return this._sessionTracker.close(); + close () { + return this._sessionTracker.close() } } diff --git a/src/v1/internal/http/http-request-runner.js b/src/v1/internal/http/http-request-runner.js index e7ce0ff9b..6eb5153b3 100644 --- a/src/v1/internal/http/http-request-runner.js +++ b/src/v1/internal/http/http-request-runner.js @@ -17,31 +17,32 @@ * limitations under the License. */ -import StreamObserver from '../stream-observer'; -import HttpResponseConverter from './http-response-converter'; -import {Neo4jError, SERVICE_UNAVAILABLE} from '../../error'; +import StreamObserver from '../stream-observer' +import HttpResponseConverter from './http-response-converter' +import { Neo4jError, SERVICE_UNAVAILABLE } from '../../error' export default class HttpRequestRunner { - - constructor(url, authToken) { - this._url = url; - this._authToken = authToken; - this._converter = new HttpResponseConverter(); + constructor (url, authToken) { + this._url = url + this._authToken = authToken + this._converter = new HttpResponseConverter() } /** * Send a HTTP request to begin a transaction. * @return {Promise} promise resolved with the transaction id or rejected with an error. */ - beginTransaction() { - const url = beginTransactionUrl(this._url); - return sendRequest('POST', url, null, this._authToken).then(responseJson => { - const neo4jError = this._converter.extractError(responseJson); - if (neo4jError) { - throw neo4jError; + beginTransaction () { + const url = beginTransactionUrl(this._url) + return sendRequest('POST', url, null, this._authToken).then( + responseJson => { + const neo4jError = this._converter.extractError(responseJson) + if (neo4jError) { + throw neo4jError + } + return this._converter.extractTransactionId(responseJson) } - return this._converter.extractTransactionId(responseJson); - }); + ) } /** @@ -49,14 +50,16 @@ export default class HttpRequestRunner { * @param {number} transactionId id of the transaction to commit. * @return {Promise} promise resolved if transaction got committed or rejected when commit failed. */ - commitTransaction(transactionId) { - const url = commitTransactionUrl(this._url, transactionId); - return sendRequest('POST', url, null, this._authToken).then(responseJson => { - const neo4jError = this._converter.extractError(responseJson); - if (neo4jError) { - throw neo4jError; + commitTransaction (transactionId) { + const url = commitTransactionUrl(this._url, transactionId) + return sendRequest('POST', url, null, this._authToken).then( + responseJson => { + const neo4jError = this._converter.extractError(responseJson) + if (neo4jError) { + throw neo4jError + } } - }); + ) } /** @@ -64,14 +67,16 @@ export default class HttpRequestRunner { * @param {number} transactionId id of the transaction to rollback. * @return {Promise} promise resolved if transaction got rolled back or rejected when rollback failed. */ - rollbackTransaction(transactionId) { - const url = transactionUrl(this._url, transactionId); - return sendRequest('DELETE', url, null, this._authToken).then(responseJson => { - const neo4jError = this._converter.extractError(responseJson); - if (neo4jError) { - throw neo4jError; + rollbackTransaction (transactionId) { + const url = transactionUrl(this._url, transactionId) + return sendRequest('DELETE', url, null, this._authToken).then( + responseJson => { + const neo4jError = this._converter.extractError(responseJson) + if (neo4jError) { + throw neo4jError + } } - }); + ) } /** @@ -81,114 +86,129 @@ export default class HttpRequestRunner { * @param {object} parameters the cypher query parameters. * @return {Promise} a promise resolved with {@link StreamObserver} containing either records or error. */ - runQuery(transactionId, statement, parameters) { - const streamObserver = new StreamObserver(); - const url = transactionUrl(this._url, transactionId); - const body = createStatementJson(statement, parameters, this._converter, streamObserver); + runQuery (transactionId, statement, parameters) { + const streamObserver = new StreamObserver() + const url = transactionUrl(this._url, transactionId) + const body = createStatementJson( + statement, + parameters, + this._converter, + streamObserver + ) if (!body) { // unable to encode given statement and parameters, return a failed stream observer - return Promise.resolve(streamObserver); + return Promise.resolve(streamObserver) } - return sendRequest('POST', url, body, this._authToken).then(responseJson => { - processResponseJson(responseJson, this._converter, streamObserver); - }).catch(error => { - streamObserver.onError(error); - }).then(() => { - return streamObserver; - }); + return sendRequest('POST', url, body, this._authToken) + .then(responseJson => { + processResponseJson(responseJson, this._converter, streamObserver) + }) + .catch(error => { + streamObserver.onError(error) + }) + .then(() => { + return streamObserver + }) } } -function sendRequest(method, url, bodyString, authToken) { +function sendRequest (method, url, bodyString, authToken) { try { const options = { method: method, headers: createHttpHeaders(authToken), body: bodyString - }; + } return new Promise((resolve, reject) => { fetch(url, options) .then(response => response.json()) .then(responseJson => resolve(responseJson)) - .catch(error => reject(new Neo4jError(error.message, SERVICE_UNAVAILABLE))); - }); + .catch(error => + reject(new Neo4jError(error.message, SERVICE_UNAVAILABLE)) + ) + }) } catch (e) { - return Promise.reject(e); + return Promise.reject(e) } } -function createHttpHeaders(authToken) { - const headers = new Headers(); - headers.append('Accept', 'application/json; charset=UTF-8'); - headers.append('Content-Type', 'application/json'); - headers.append('Authorization', 'Basic ' + btoa(authToken.principal + ':' + authToken.credentials)); - return headers; +function createHttpHeaders (authToken) { + const headers = new Headers() + headers.append('Accept', 'application/json; charset=UTF-8') + headers.append('Content-Type', 'application/json') + headers.append( + 'Authorization', + 'Basic ' + btoa(authToken.principal + ':' + authToken.credentials) + ) + return headers } -function createStatementJson(statement, parameters, converter, streamObserver) { +function createStatementJson (statement, parameters, converter, streamObserver) { try { - return createStatementJsonOrThrow(statement, parameters, converter); + return createStatementJsonOrThrow(statement, parameters, converter) } catch (e) { - streamObserver.onError(e); - return null; + streamObserver.onError(e) + return null } } -function createStatementJsonOrThrow(statement, parameters, converter) { - const encodedParameters = converter.encodeStatementParameters(parameters); +function createStatementJsonOrThrow (statement, parameters, converter) { + const encodedParameters = converter.encodeStatementParameters(parameters) return JSON.stringify({ - statements: [{ - statement: statement, - parameters: encodedParameters, - resultDataContents: ['row', 'graph'], - includeStats: true - }] - }); + statements: [ + { + statement: statement, + parameters: encodedParameters, + resultDataContents: ['row', 'graph'], + includeStats: true + } + ] + }) } -function processResponseJson(responseJson, converter, streamObserver) { +function processResponseJson (responseJson, converter, streamObserver) { if (!responseJson) { // request failed and there is no response - return; + return } try { - processResponseJsonOrThrow(responseJson, converter, streamObserver); + processResponseJsonOrThrow(responseJson, converter, streamObserver) } catch (e) { - streamObserver.onError(e); + streamObserver.onError(e) } } -function processResponseJsonOrThrow(responseJson, converter, streamObserver) { - const neo4jError = converter.extractError(responseJson); +function processResponseJsonOrThrow (responseJson, converter, streamObserver) { + const neo4jError = converter.extractError(responseJson) if (neo4jError) { - streamObserver.onError(neo4jError); + streamObserver.onError(neo4jError) } else { - const recordMetadata = converter.extractRecordMetadata(responseJson); - streamObserver.onCompleted(recordMetadata); + const recordMetadata = converter.extractRecordMetadata(responseJson) + streamObserver.onCompleted(recordMetadata) - const rawRecords = converter.extractRawRecords(responseJson); - rawRecords.forEach(rawRecord => streamObserver.onNext(rawRecord)); + const rawRecords = converter.extractRawRecords(responseJson) + rawRecords.forEach(rawRecord => streamObserver.onNext(rawRecord)) - const statementMetadata = converter.extractStatementMetadata(responseJson); - streamObserver.onCompleted(statementMetadata); + const statementMetadata = converter.extractStatementMetadata(responseJson) + streamObserver.onCompleted(statementMetadata) } } -function beginTransactionUrl(baseUrl) { - return createUrl(baseUrl, '/db/data/transaction'); +function beginTransactionUrl (baseUrl) { + return createUrl(baseUrl, '/db/data/transaction') } -function commitTransactionUrl(baseUrl, transactionId) { - return transactionUrl(baseUrl, transactionId) + '/commit'; +function commitTransactionUrl (baseUrl, transactionId) { + return transactionUrl(baseUrl, transactionId) + '/commit' } -function transactionUrl(baseUrl, transactionId) { - return beginTransactionUrl(baseUrl) + '/' + transactionId; +function transactionUrl (baseUrl, transactionId) { + return beginTransactionUrl(baseUrl) + '/' + transactionId } -function createUrl(baseUrl, path) { - return `${baseUrl.scheme}://${baseUrl.host}:${baseUrl.port}${path}`; +function createUrl (baseUrl, path) { + return `${baseUrl.scheme}://${baseUrl.host}:${baseUrl.port}${path}` } diff --git a/src/v1/internal/http/http-response-converter.js b/src/v1/internal/http/http-response-converter.js index 04e923d2b..f919ae542 100644 --- a/src/v1/internal/http/http-response-converter.js +++ b/src/v1/internal/http/http-response-converter.js @@ -17,18 +17,24 @@ * limitations under the License. */ -import {isInt} from '../../integer'; -import {Node, Path, PathSegment, Relationship} from '../../graph-types'; -import {Neo4jError, PROTOCOL_ERROR} from '../../error'; -import {isPoint, Point} from '../../spatial-types'; -import {isDate, isDateTime, isDuration, isLocalDateTime, isLocalTime, isTime} from '../../temporal-types'; - -const CREDENTIALS_EXPIRED_CODE = 'Neo.ClientError.Security.CredentialsExpired'; +import { isInt } from '../../integer' +import { Node, Path, PathSegment, Relationship } from '../../graph-types' +import { Neo4jError, PROTOCOL_ERROR } from '../../error' +import { isPoint, Point } from '../../spatial-types' +import { + isDate, + isDateTime, + isDuration, + isLocalDateTime, + isLocalTime, + isTime +} from '../../temporal-types' + +const CREDENTIALS_EXPIRED_CODE = 'Neo.ClientError.Security.CredentialsExpired' export default class HttpResponseConverter { - - encodeStatementParameters(parameters) { - return encodeQueryParameters(parameters); + encodeStatementParameters (parameters) { + return encodeQueryParameters(parameters) } /** @@ -36,20 +42,22 @@ export default class HttpResponseConverter { * @param {object} response the response. * @return {Neo4jError|null} new driver friendly error, if exists. */ - extractError(response) { - const errors = response.errors; + extractError (response) { + const errors = response.errors if (errors) { - const error = errors[0]; + const error = errors[0] if (error) { // endpoint returns 'Neo.ClientError.Security.Forbidden' code and 'password_change' that points to another endpoint // this is different from code returned via Bolt and less descriptive // make code same as in Bolt, if password change is required - const code = response.password_change ? CREDENTIALS_EXPIRED_CODE : error.code; - const message = error.message; - return new Neo4jError(message, code); + const code = response.password_change + ? CREDENTIALS_EXPIRED_CODE + : error.code + const message = error.message + return new Neo4jError(message, code) } } - return null; + return null } /** @@ -57,18 +65,22 @@ export default class HttpResponseConverter { * @param {object} response the response. * @return {number} the transaction id. */ - extractTransactionId(response) { - const commitUrl = response.commit; + extractTransactionId (response) { + const commitUrl = response.commit if (commitUrl) { // extract id 42 from commit url like 'http://localhost:7474/db/data/transaction/42/commit' - const url = commitUrl.replace('/commit', ''); - const transactionIdString = url.substring(url.lastIndexOf('/') + 1); - const transactionId = parseInt(transactionIdString, 10); + const url = commitUrl.replace('/commit', '') + const transactionIdString = url.substring(url.lastIndexOf('/') + 1) + const transactionId = parseInt(transactionIdString, 10) if (transactionId || transactionId === 0) { - return transactionId; + return transactionId } } - throw new Neo4jError(`Unable to extract transaction id from the response JSON: ${JSON.stringify(response)}`); + throw new Neo4jError( + `Unable to extract transaction id from the response JSON: ${JSON.stringify( + response + )}` + ) } /** @@ -76,10 +88,10 @@ export default class HttpResponseConverter { * @param {object} response the response. * @return {object} new metadata object. */ - extractRecordMetadata(response) { - const result = extractResult(response); - const fields = result ? result.columns : []; - return {fields: fields}; + extractRecordMetadata (response) { + const result = extractResult(response) + const fields = result ? result.columns : [] + return { fields: fields } } /** @@ -87,15 +99,15 @@ export default class HttpResponseConverter { * @param {object} response the response. * @return {object[][]} raw records from the response. */ - extractRawRecords(response) { - const result = extractResult(response); + extractRawRecords (response) { + const result = extractResult(response) if (result) { - const data = result.data; + const data = result.data if (data) { - return data.map(element => extractRawRecord(element)); + return data.map(element => extractRawRecord(element)) } } - return []; + return [] } /** @@ -103,294 +115,360 @@ export default class HttpResponseConverter { * @param {object} response the response. * @return {object} metadata as object. */ - extractStatementMetadata(response) { - const result = extractResult(response); + extractStatementMetadata (response) { + const result = extractResult(response) if (result) { - const stats = result.stats; + const stats = result.stats if (stats) { const convertedStats = Object.keys(stats).reduce((newStats, key) => { if (key === 'contains_updates') { // skip because such key does not exist in bolt - return newStats; + return newStats } // fix key name for future parsing by StatementStatistics class - const newKey = (key === 'relationship_deleted' ? 'relationships_deleted' : key).replace('_', '-'); - newStats[newKey] = stats[key]; - return newStats; - }, {}); - - return {stats: convertedStats}; + const newKey = (key === 'relationship_deleted' + ? 'relationships_deleted' + : key + ).replace('_', '-') + newStats[newKey] = stats[key] + return newStats + }, {}) + + return { stats: convertedStats } } } - return {}; + return {} } } -function encodeQueryParameters(parameters) { +function encodeQueryParameters (parameters) { if (parameters && typeof parameters === 'object') { return Object.keys(parameters).reduce((result, key) => { - result[key] = encodeQueryParameter(parameters[key]); - return result; - }, {}); + result[key] = encodeQueryParameter(parameters[key]) + return result + }, {}) } - return parameters; + return parameters } -function encodeQueryParameter(value) { +function encodeQueryParameter (value) { if (value instanceof Node) { - throw new Neo4jError('It is not allowed to pass nodes in query parameters', PROTOCOL_ERROR); + throw new Neo4jError( + 'It is not allowed to pass nodes in query parameters', + PROTOCOL_ERROR + ) } else if (value instanceof Relationship) { - throw new Neo4jError('It is not allowed to pass relationships in query parameters', PROTOCOL_ERROR); + throw new Neo4jError( + 'It is not allowed to pass relationships in query parameters', + PROTOCOL_ERROR + ) } else if (value instanceof Path) { - throw new Neo4jError('It is not allowed to pass paths in query parameters', PROTOCOL_ERROR); + throw new Neo4jError( + 'It is not allowed to pass paths in query parameters', + PROTOCOL_ERROR + ) } else if (isPoint(value)) { - throw newUnsupportedParameterError('points'); + throw newUnsupportedParameterError('points') } else if (isDate(value)) { - throw newUnsupportedParameterError('dates'); + throw newUnsupportedParameterError('dates') } else if (isDateTime(value)) { - throw newUnsupportedParameterError('date-time'); + throw newUnsupportedParameterError('date-time') } else if (isDuration(value)) { - throw newUnsupportedParameterError('durations'); + throw newUnsupportedParameterError('durations') } else if (isLocalDateTime(value)) { - throw newUnsupportedParameterError('local date-time'); + throw newUnsupportedParameterError('local date-time') } else if (isLocalTime(value)) { - throw newUnsupportedParameterError('local time'); + throw newUnsupportedParameterError('local time') } else if (isTime(value)) { - throw newUnsupportedParameterError('time'); + throw newUnsupportedParameterError('time') } else if (isInt(value)) { - return value.toNumber(); + return value.toNumber() } else if (Array.isArray(value)) { - return value.map(element => encodeQueryParameter(element)); + return value.map(element => encodeQueryParameter(element)) } else if (typeof value === 'object') { - return encodeQueryParameters(value); + return encodeQueryParameters(value) } else { - return value; + return value } } -function newUnsupportedParameterError(name) { - return new Neo4jError(`It is not allowed to pass ${name} in query parameters when using HTTP endpoint. ` + - `Please consider using Cypher functions to create ${name} so that query parameters are plain objects.`, PROTOCOL_ERROR); +function newUnsupportedParameterError (name) { + return new Neo4jError( + `It is not allowed to pass ${name} in query parameters when using HTTP endpoint. ` + + `Please consider using Cypher functions to create ${name} so that query parameters are plain objects.`, + PROTOCOL_ERROR + ) } -function extractResult(response) { - const results = response.results; +function extractResult (response) { + const results = response.results if (results) { - const result = results[0]; + const result = results[0] if (result) { - return result; + return result } } - return null; + return null } -function extractRawRecord(data) { - const row = data.row; +function extractRawRecord (data) { + const row = data.row - const nodesById = indexNodesById(data); - const relationshipsById = indexRelationshipsById(data); + const nodesById = indexNodesById(data) + const relationshipsById = indexRelationshipsById(data) if (row) { - return row.map((ignore, index) => extractRawRecordElement(index, data, nodesById, relationshipsById)); + return row.map((ignore, index) => + extractRawRecordElement(index, data, nodesById, relationshipsById) + ) } - return []; + return [] } -function indexNodesById(data) { - const graph = data.graph; +function indexNodesById (data) { + const graph = data.graph if (graph) { - const nodes = graph.nodes; + const nodes = graph.nodes if (nodes) { return nodes.reduce((result, node) => { + const identity = convertNumber(node.id) + const labels = node.labels + const properties = convertPrimitiveValue(node.properties) + result[node.id] = new Node(identity, labels, properties) - const identity = convertNumber(node.id); - const labels = node.labels; - const properties = convertPrimitiveValue(node.properties); - result[node.id] = new Node(identity, labels, properties); - - return result; - }, {}); + return result + }, {}) } } - return {}; + return {} } -function indexRelationshipsById(data) { - const graph = data.graph; +function indexRelationshipsById (data) { + const graph = data.graph if (graph) { - const relationships = graph.relationships; + const relationships = graph.relationships if (relationships) { return relationships.reduce((result, relationship) => { - - const identity = convertNumber(relationship.id); - const startNode = convertNumber(relationship.startNode); - const endNode = convertNumber(relationship.endNode); - const type = relationship.type; - const properties = convertPrimitiveValue(relationship.properties); - result[relationship.id] = new Relationship(identity, startNode, endNode, type, properties); - - return result; - - }, {}); + const identity = convertNumber(relationship.id) + const startNode = convertNumber(relationship.startNode) + const endNode = convertNumber(relationship.endNode) + const type = relationship.type + const properties = convertPrimitiveValue(relationship.properties) + result[relationship.id] = new Relationship( + identity, + startNode, + endNode, + type, + properties + ) + + return result + }, {}) } } - return {}; + return {} } -function extractRawRecordElement(index, data, nodesById, relationshipsById) { - const element = data.row ? data.row[index] : null; - const elementMetadata = data.meta ? data.meta[index] : null; +function extractRawRecordElement (index, data, nodesById, relationshipsById) { + const element = data.row ? data.row[index] : null + const elementMetadata = data.meta ? data.meta[index] : null if (elementMetadata) { // element is either a graph, spatial or temporal type - return convertComplexValue(element, elementMetadata, nodesById, relationshipsById); + return convertComplexValue( + element, + elementMetadata, + nodesById, + relationshipsById + ) } else { // element is a primitive, like number, string, array or object - return convertPrimitiveValue(element); + return convertPrimitiveValue(element) } } -function convertComplexValue(element, elementMetadata, nodesById, relationshipsById) { +function convertComplexValue ( + element, + elementMetadata, + nodesById, + relationshipsById +) { if (isNodeMetadata(elementMetadata)) { - return nodesById[elementMetadata.id]; + return nodesById[elementMetadata.id] } else if (isRelationshipMetadata(elementMetadata)) { - return relationshipsById[elementMetadata.id]; + return relationshipsById[elementMetadata.id] } else if (isPathMetadata(elementMetadata)) { - return convertPath(elementMetadata, nodesById, relationshipsById); + return convertPath(elementMetadata, nodesById, relationshipsById) } else if (isPointMetadata(elementMetadata)) { - return convertPoint(element); + return convertPoint(element) } else { - return element; + return element } } -function convertPath(metadata, nodesById, relationshipsById) { - let startNode = null; - let relationship = null; - const pathSegments = []; +function convertPath (metadata, nodesById, relationshipsById) { + let startNode = null + let relationship = null + const pathSegments = [] for (let i = 0; i < metadata.length; i++) { - const element = metadata[i]; - const elementId = element.id; - const elementType = element.type; + const element = metadata[i] + const elementId = element.id + const elementType = element.type - const nodeExpected = (startNode === null && relationship === null) || (startNode !== null && relationship !== null); + const nodeExpected = + (startNode === null && relationship === null) || + (startNode !== null && relationship !== null) if (nodeExpected && elementType !== 'node') { - throw new Neo4jError(`Unable to parse path, node expected but got: ${JSON.stringify(element)} in ${JSON.stringify(metadata)}`); + throw new Neo4jError( + `Unable to parse path, node expected but got: ${JSON.stringify( + element + )} in ${JSON.stringify(metadata)}` + ) } if (!nodeExpected && elementType === 'node') { - throw new Neo4jError(`Unable to parse path, relationship expected but got: ${JSON.stringify(element)} in ${JSON.stringify(metadata)}`); + throw new Neo4jError( + `Unable to parse path, relationship expected but got: ${JSON.stringify( + element + )} in ${JSON.stringify(metadata)}` + ) } if (nodeExpected) { - const node = nodesById[elementId]; + const node = nodesById[elementId] if (startNode === null) { - startNode = node; + startNode = node } else if (startNode !== null && relationship !== null) { - const pathSegment = new PathSegment(startNode, relationship, node); - pathSegments.push(pathSegment); - startNode = node; - relationship = null; + const pathSegment = new PathSegment(startNode, relationship, node) + pathSegments.push(pathSegment) + startNode = node + relationship = null } else { - throw new Neo4jError(`Unable to parse path, illegal node configuration: ${JSON.stringify(metadata)}`); + throw new Neo4jError( + `Unable to parse path, illegal node configuration: ${JSON.stringify( + metadata + )}` + ) } } else { if (relationship === null) { - relationship = relationshipsById[elementId]; + relationship = relationshipsById[elementId] } else { - throw new Neo4jError(`Unable to parse path, illegal relationship configuration: ${JSON.stringify(metadata)}`); + throw new Neo4jError( + `Unable to parse path, illegal relationship configuration: ${JSON.stringify( + metadata + )}` + ) } } } - const lastPathSegment = pathSegments[pathSegments.length - 1]; - if ((lastPathSegment && lastPathSegment.end !== startNode) || relationship !== null) { - throw new Neo4jError(`Unable to parse path: ${JSON.stringify(metadata)}`); + const lastPathSegment = pathSegments[pathSegments.length - 1] + if ( + (lastPathSegment && lastPathSegment.end !== startNode) || + relationship !== null + ) { + throw new Neo4jError(`Unable to parse path: ${JSON.stringify(metadata)}`) } - return createPath(pathSegments); + return createPath(pathSegments) } -function createPath(pathSegments) { - const pathStartNode = pathSegments[0].start; - const pathEndNode = pathSegments[pathSegments.length - 1].end; - return new Path(pathStartNode, pathEndNode, pathSegments); +function createPath (pathSegments) { + const pathStartNode = pathSegments[0].start + const pathEndNode = pathSegments[pathSegments.length - 1].end + return new Path(pathStartNode, pathEndNode, pathSegments) } -function convertPoint(element) { - const type = element.type; +function convertPoint (element) { + const type = element.type if (type !== 'Point') { - throw new Neo4jError(`Unexpected Point type received: ${JSON.stringify(element)}`); + throw new Neo4jError( + `Unexpected Point type received: ${JSON.stringify(element)}` + ) } - const coordinates = element.coordinates; - if (!Array.isArray(coordinates) && (coordinates.length !== 2 || coordinates.length !== 3)) { - throw new Neo4jError(`Unexpected Point coordinates received: ${JSON.stringify(element)}`); + const coordinates = element.coordinates + if ( + !Array.isArray(coordinates) && + (coordinates.length !== 2 || coordinates.length !== 3) + ) { + throw new Neo4jError( + `Unexpected Point coordinates received: ${JSON.stringify(element)}` + ) } - const srid = convertCrsToId(element); + const srid = convertCrsToId(element) - return new Point(srid, ...coordinates); + return new Point(srid, ...coordinates) } -function convertCrsToId(element) { - const crs = element.crs; +function convertCrsToId (element) { + const crs = element.crs if (!crs || !crs.name) { - throw new Neo4jError(`Unexpected Point crs received: ${JSON.stringify(element)}`); + throw new Neo4jError( + `Unexpected Point crs received: ${JSON.stringify(element)}` + ) } - const name = crs.name.toLowerCase(); + const name = crs.name.toLowerCase() if (name === 'wgs-84') { - return 4326; + return 4326 } else if (name === 'wgs-84-3d') { - return 4979; + return 4979 } else if (name === 'cartesian') { - return 7203; + return 7203 } else if (name === 'cartesian-3d') { - return 9157; + return 9157 } else { - throw new Neo4jError(`Unexpected Point crs received: ${JSON.stringify(element)}`); + throw new Neo4jError( + `Unexpected Point crs received: ${JSON.stringify(element)}` + ) } } -function convertPrimitiveValue(element) { +function convertPrimitiveValue (element) { if (element == null || element === undefined) { - return null; + return null } else if (typeof element === 'number') { - return convertNumber(element); + return convertNumber(element) } else if (Array.isArray(element)) { - return element.map(element => convertPrimitiveValue(element)); + return element.map(element => convertPrimitiveValue(element)) } else if (typeof element === 'object') { return Object.keys(element).reduce((result, key) => { - result[key] = convertPrimitiveValue(element[key]); - return result; - }, {}); + result[key] = convertPrimitiveValue(element[key]) + return result + }, {}) } else { - return element; + return element } } -function convertNumber(value) { - return typeof value === 'number' ? value : Number(value); +function convertNumber (value) { + return typeof value === 'number' ? value : Number(value) } -function isNodeMetadata(metadata) { - return isMetadataForType('node', metadata); +function isNodeMetadata (metadata) { + return isMetadataForType('node', metadata) } -function isRelationshipMetadata(metadata) { - return isMetadataForType('relationship', metadata); +function isRelationshipMetadata (metadata) { + return isMetadataForType('relationship', metadata) } -function isPointMetadata(metadata) { - return isMetadataForType('point', metadata); +function isPointMetadata (metadata) { + return isMetadataForType('point', metadata) } -function isMetadataForType(name, metadata) { - return !Array.isArray(metadata) && typeof metadata === 'object' && metadata.type === name; +function isMetadataForType (name, metadata) { + return ( + !Array.isArray(metadata) && + typeof metadata === 'object' && + metadata.type === name + ) } -function isPathMetadata(metadata) { - return Array.isArray(metadata); +function isPathMetadata (metadata) { + return Array.isArray(metadata) } diff --git a/src/v1/internal/http/http-session-tracker.js b/src/v1/internal/http/http-session-tracker.js index acd6cfc59..e66196e07 100644 --- a/src/v1/internal/http/http-session-tracker.js +++ b/src/v1/internal/http/http-session-tracker.js @@ -18,34 +18,33 @@ */ export default class HttpSessionTracker { - - constructor() { - this._openSessions = new Set(); + constructor () { + this._openSessions = new Set() } /** * Record given session as open. * @param {HttpSession} session the newly open session. */ - sessionOpened(session) { - this._openSessions.add(session); + sessionOpened (session) { + this._openSessions.add(session) } /** * Record given session as close. * @param {HttpSession} session the just closed session. */ - sessionClosed(session) { - this._openSessions.delete(session); + sessionClosed (session) { + this._openSessions.delete(session) } /** * Close this tracker and all open sessions. */ - close() { - const sessions = Array.from(this._openSessions); - this._openSessions.clear(); - return Promise.all(sessions.map(session => closeSession(session))); + close () { + const sessions = Array.from(this._openSessions) + this._openSessions.clear() + return Promise.all(sessions.map(session => closeSession(session))) } } @@ -54,10 +53,10 @@ export default class HttpSessionTracker { * @param {HttpSession} session the session to close. * @return {Promise} promise resolved when session is closed. */ -function closeSession(session) { +function closeSession (session) { return new Promise(resolve => { session.close(() => { - resolve(); - }); - }); + resolve() + }) + }) } diff --git a/src/v1/internal/http/http-session.js b/src/v1/internal/http/http-session.js index 587901ea7..37e0e17ee 100644 --- a/src/v1/internal/http/http-session.js +++ b/src/v1/internal/http/http-session.js @@ -17,98 +17,137 @@ * limitations under the License. */ -import {WRITE} from '../../driver'; -import Session from '../../session'; -import {validateStatementAndParameters} from '../util'; -import {Neo4jError} from '../../error'; -import HttpRequestRunner from './http-request-runner'; -import {EMPTY_CONNECTION_HOLDER} from '../connection-holder'; -import Result from '../../result'; +import { WRITE } from '../../driver' +import Session from '../../session' +import { validateStatementAndParameters } from '../util' +import { Neo4jError } from '../../error' +import HttpRequestRunner from './http-request-runner' +import { EMPTY_CONNECTION_HOLDER } from '../connection-holder' +import Result from '../../result' export default class HttpSession extends Session { - - constructor(url, authToken, config, sessionTracker) { - super(WRITE, null, null, config); - this._ongoingTransactionIds = []; - this._serverInfoSupplier = createServerInfoSupplier(url); - this._requestRunner = new HttpRequestRunner(url, authToken); - this._sessionTracker = sessionTracker; - this._sessionTracker.sessionOpened(this); + constructor (url, authToken, config, sessionTracker) { + super(WRITE, null, null, config) + this._ongoingTransactionIds = [] + this._serverInfoSupplier = createServerInfoSupplier(url) + this._requestRunner = new HttpRequestRunner(url, authToken) + this._sessionTracker = sessionTracker + this._sessionTracker.sessionOpened(this) } - run(statement, parameters = {}) { - const {query, params} = validateStatementAndParameters(statement, parameters); + run (statement, parameters = {}) { + const { query, params } = validateStatementAndParameters( + statement, + parameters + ) return this._requestRunner.beginTransaction().then(transactionId => { - this._ongoingTransactionIds.push(transactionId); - const queryPromise = this._requestRunner.runQuery(transactionId, query, params); - - return queryPromise.then(streamObserver => { - if (streamObserver.hasFailed()) { - return rollbackTransactionAfterQueryFailure(transactionId, streamObserver, this._requestRunner); - } else { - return commitTransactionAfterQuerySuccess(transactionId, streamObserver, this._requestRunner); - } - }).then(streamObserver => { - this._ongoingTransactionIds = this._ongoingTransactionIds.filter(id => id !== transactionId); - return new Result(streamObserver, query, params, this._serverInfoSupplier, EMPTY_CONNECTION_HOLDER); - }); - }); + this._ongoingTransactionIds.push(transactionId) + const queryPromise = this._requestRunner.runQuery( + transactionId, + query, + params + ) + + return queryPromise + .then(streamObserver => { + if (streamObserver.hasFailed()) { + return rollbackTransactionAfterQueryFailure( + transactionId, + streamObserver, + this._requestRunner + ) + } else { + return commitTransactionAfterQuerySuccess( + transactionId, + streamObserver, + this._requestRunner + ) + } + }) + .then(streamObserver => { + this._ongoingTransactionIds = this._ongoingTransactionIds.filter( + id => id !== transactionId + ) + return new Result( + streamObserver, + query, + params, + this._serverInfoSupplier, + EMPTY_CONNECTION_HOLDER + ) + }) + }) } - beginTransaction() { - throwTransactionsNotSupported(); + beginTransaction () { + throwTransactionsNotSupported() } - readTransaction() { - throwTransactionsNotSupported(); + readTransaction () { + throwTransactionsNotSupported() } - writeTransaction() { - throwTransactionsNotSupported(); + writeTransaction () { + throwTransactionsNotSupported() } - lastBookmark() { - throw new Neo4jError('Experimental HTTP driver does not support bookmarks and routing'); + lastBookmark () { + throw new Neo4jError( + 'Experimental HTTP driver does not support bookmarks and routing' + ) } - close(callback = (() => null)) { - const rollbackAllOngoingTransactions = this._ongoingTransactionIds.map(transactionId => - rollbackTransactionSilently(transactionId, this._requestRunner) - ); + close (callback = () => null) { + const rollbackAllOngoingTransactions = this._ongoingTransactionIds.map( + transactionId => + rollbackTransactionSilently(transactionId, this._requestRunner) + ) - Promise.all(rollbackAllOngoingTransactions) - .then(() => { - this._sessionTracker.sessionClosed(this); - callback(); - }); + Promise.all(rollbackAllOngoingTransactions).then(() => { + this._sessionTracker.sessionClosed(this) + callback() + }) } } -function rollbackTransactionAfterQueryFailure(transactionId, streamObserver, requestRunner) { - return rollbackTransactionSilently(transactionId, requestRunner).then(() => streamObserver); +function rollbackTransactionAfterQueryFailure ( + transactionId, + streamObserver, + requestRunner +) { + return rollbackTransactionSilently(transactionId, requestRunner).then( + () => streamObserver + ) } -function commitTransactionAfterQuerySuccess(transactionId, streamObserver, requestRunner) { - return requestRunner.commitTransaction(transactionId).catch(error => { - streamObserver.onError(error); - }).then(() => { - return streamObserver; - }); +function commitTransactionAfterQuerySuccess ( + transactionId, + streamObserver, + requestRunner +) { + return requestRunner + .commitTransaction(transactionId) + .catch(error => { + streamObserver.onError(error) + }) + .then(() => { + return streamObserver + }) } -function rollbackTransactionSilently(transactionId, requestRunner) { - return requestRunner.rollbackTransaction(transactionId).catch(error => { +function rollbackTransactionSilently (transactionId, requestRunner) { + return requestRunner.rollbackTransaction(transactionId).catch(() => { // ignore all rollback errors - }); + }) } -function createServerInfoSupplier(url) { +function createServerInfoSupplier (url) { return () => { - return {server: {address: url.hostAndPort}}; - }; + return { server: { address: url.hostAndPort } } + } } -function throwTransactionsNotSupported() { - throw new Neo4jError('Experimental HTTP driver does not support transactions'); +function throwTransactionsNotSupported () { + throw new Neo4jError('Experimental HTTP driver does not support transactions') } diff --git a/src/v1/internal/least-connected-load-balancing-strategy.js b/src/v1/internal/least-connected-load-balancing-strategy.js index abde58e19..0391b6056 100644 --- a/src/v1/internal/least-connected-load-balancing-strategy.js +++ b/src/v1/internal/least-connected-load-balancing-strategy.js @@ -16,70 +16,70 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import RoundRobinArrayIndex from './round-robin-array-index'; -import LoadBalancingStrategy from './load-balancing-strategy'; +import RoundRobinArrayIndex from './round-robin-array-index' +import LoadBalancingStrategy from './load-balancing-strategy' -export const LEAST_CONNECTED_STRATEGY_NAME = 'least_connected'; +export const LEAST_CONNECTED_STRATEGY_NAME = 'least_connected' export default class LeastConnectedLoadBalancingStrategy extends LoadBalancingStrategy { - /** * @constructor * @param {Pool} connectionPool the connection pool of this driver. */ - constructor(connectionPool) { - super(); - this._readersIndex = new RoundRobinArrayIndex(); - this._writersIndex = new RoundRobinArrayIndex(); - this._connectionPool = connectionPool; + constructor (connectionPool) { + super() + this._readersIndex = new RoundRobinArrayIndex() + this._writersIndex = new RoundRobinArrayIndex() + this._connectionPool = connectionPool } /** * @inheritDoc */ - selectReader(knownReaders) { - return this._select(knownReaders, this._readersIndex); + selectReader (knownReaders) { + return this._select(knownReaders, this._readersIndex) } /** * @inheritDoc */ - selectWriter(knownWriters) { - return this._select(knownWriters, this._writersIndex); + selectWriter (knownWriters) { + return this._select(knownWriters, this._writersIndex) } - _select(addresses, roundRobinIndex) { - const length = addresses.length; + _select (addresses, roundRobinIndex) { + const length = addresses.length if (length === 0) { - return null; + return null } // choose start index for iteration in round-robin fashion - const startIndex = roundRobinIndex.next(length); - let index = startIndex; + const startIndex = roundRobinIndex.next(length) + let index = startIndex - let leastConnectedAddress = null; - let leastActiveConnections = Number.MAX_SAFE_INTEGER; + let leastConnectedAddress = null + let leastActiveConnections = Number.MAX_SAFE_INTEGER // iterate over the array to find least connected address do { - const address = addresses[index]; - const activeConnections = this._connectionPool.activeResourceCount(address); + const address = addresses[index] + const activeConnections = this._connectionPool.activeResourceCount( + address + ) if (activeConnections < leastActiveConnections) { - leastConnectedAddress = address; - leastActiveConnections = activeConnections; + leastConnectedAddress = address + leastActiveConnections = activeConnections } // loop over to the start of the array when end is reached if (index === length - 1) { - index = 0; + index = 0 } else { - index++; + index++ } - } - while (index !== startIndex); + } while (index !== startIndex) - return leastConnectedAddress; + return leastConnectedAddress } } diff --git a/src/v1/internal/load-balancing-strategy.js b/src/v1/internal/load-balancing-strategy.js index 8fd328980..650a0e08b 100644 --- a/src/v1/internal/load-balancing-strategy.js +++ b/src/v1/internal/load-balancing-strategy.js @@ -21,14 +21,13 @@ * A facility to select most appropriate reader or writer among the given addresses for request processing. */ export default class LoadBalancingStrategy { - /** * Select next most appropriate reader from the list of given readers. * @param {string[]} knownReaders an array of currently known readers to select from. * @return {string} most appropriate reader or `null` if given array is empty. */ - selectReader(knownReaders) { - throw new Error('Abstract function'); + selectReader (knownReaders) { + throw new Error('Abstract function') } /** @@ -36,7 +35,7 @@ export default class LoadBalancingStrategy { * @param {string[]} knownWriters an array of currently known writers to select from. * @return {string} most appropriate writer or `null` if given array is empty. */ - selectWriter(knownWriters) { - throw new Error('Abstract function'); + selectWriter (knownWriters) { + throw new Error('Abstract function') } } diff --git a/src/v1/internal/logger.js b/src/v1/internal/logger.js index a42d63428..be6b47d49 100644 --- a/src/v1/internal/logger.js +++ b/src/v1/internal/logger.js @@ -16,35 +16,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {newError} from '../error'; +import { newError } from '../error' -const ERROR = 'error'; -const WARN = 'warn'; -const INFO = 'info'; -const DEBUG = 'debug'; +const ERROR = 'error' +const WARN = 'warn' +const INFO = 'info' +const DEBUG = 'debug' -const DEFAULT_LEVEL = INFO; +const DEFAULT_LEVEL = INFO const levels = { [ERROR]: 0, [WARN]: 1, [INFO]: 2, [DEBUG]: 3 -}; +} /** * Logger used by the driver to notify about various internal events. Single logger should be used per driver. */ class Logger { - /** * @constructor * @param {string} level the enabled logging level. * @param {function(level: string, message: string)} loggerFunction the function to write the log level and message. */ - constructor(level, loggerFunction) { - this._level = level; - this._loggerFunction = loggerFunction; + constructor (level, loggerFunction) { + this._level = level + this._loggerFunction = loggerFunction } /** @@ -52,39 +51,39 @@ class Logger { * @param {object} driverConfig the driver configuration as supplied by the user. * @return {Logger} a new logger instance or a no-op logger when not configured. */ - static create(driverConfig) { + static create (driverConfig) { if (driverConfig && driverConfig.logging) { - const loggingConfig = driverConfig.logging; - const level = extractConfiguredLevel(loggingConfig); - const loggerFunction = extractConfiguredLogger(loggingConfig); - return new Logger(level, loggerFunction); + const loggingConfig = driverConfig.logging + const level = extractConfiguredLevel(loggingConfig) + const loggerFunction = extractConfiguredLogger(loggingConfig) + return new Logger(level, loggerFunction) } - return this.noOp(); + return this.noOp() } /** * Create a no-op logger implementation. * @return {Logger} the no-op logger implementation. */ - static noOp() { - return noOpLogger; + static noOp () { + return noOpLogger } /** * Check if error logging is enabled, i.e. it is not a no-op implementation. * @return {boolean} `true` when enabled, `false` otherwise. */ - isErrorEnabled() { - return isLevelEnabled(this._level, ERROR); + isErrorEnabled () { + return isLevelEnabled(this._level, ERROR) } /** * Log an error message. * @param {string} message the message to log. */ - error(message) { + error (message) { if (this.isErrorEnabled()) { - this._loggerFunction(ERROR, message); + this._loggerFunction(ERROR, message) } } @@ -92,17 +91,17 @@ class Logger { * Check if warn logging is enabled, i.e. it is not a no-op implementation. * @return {boolean} `true` when enabled, `false` otherwise. */ - isWarnEnabled() { - return isLevelEnabled(this._level, WARN); + isWarnEnabled () { + return isLevelEnabled(this._level, WARN) } /** * Log an warning message. * @param {string} message the message to log. */ - warn(message) { + warn (message) { if (this.isWarnEnabled()) { - this._loggerFunction(WARN, message); + this._loggerFunction(WARN, message) } } @@ -110,17 +109,17 @@ class Logger { * Check if info logging is enabled, i.e. it is not a no-op implementation. * @return {boolean} `true` when enabled, `false` otherwise. */ - isInfoEnabled() { - return isLevelEnabled(this._level, INFO); + isInfoEnabled () { + return isLevelEnabled(this._level, INFO) } /** * Log an info message. * @param {string} message the message to log. */ - info(message) { + info (message) { if (this.isInfoEnabled()) { - this._loggerFunction(INFO, message); + this._loggerFunction(INFO, message) } } @@ -128,57 +127,52 @@ class Logger { * Check if debug logging is enabled, i.e. it is not a no-op implementation. * @return {boolean} `true` when enabled, `false` otherwise. */ - isDebugEnabled() { - return isLevelEnabled(this._level, DEBUG); + isDebugEnabled () { + return isLevelEnabled(this._level, DEBUG) } /** * Log a debug message. * @param {string} message the message to log. */ - debug(message) { + debug (message) { if (this.isDebugEnabled()) { - this._loggerFunction(DEBUG, message); + this._loggerFunction(DEBUG, message) } } } class NoOpLogger extends Logger { - - constructor() { - super(null, null); + constructor () { + super(null, null) } - isErrorEnabled() { - return false; + isErrorEnabled () { + return false } - error(message) { - } + error (message) {} - isWarnEnabled() { - return false; + isWarnEnabled () { + return false } - warn(message) { - } + warn (message) {} - isInfoEnabled() { - return false; + isInfoEnabled () { + return false } - info(message) { - } + info (message) {} - isDebugEnabled() { - return false; + isDebugEnabled () { + return false } - debug(message) { - } + debug (message) {} } -const noOpLogger = new NoOpLogger(); +const noOpLogger = new NoOpLogger() /** * Check if the given logging level is enabled. @@ -186,8 +180,8 @@ const noOpLogger = new NoOpLogger(); * @param {string} targetLevel the level to check. * @return {boolean} value of `true` when enabled, `false` otherwise. */ -function isLevelEnabled(configuredLevel, targetLevel) { - return levels[configuredLevel] >= levels[targetLevel]; +function isLevelEnabled (configuredLevel, targetLevel) { + return levels[configuredLevel] >= levels[targetLevel] } /** @@ -195,16 +189,20 @@ function isLevelEnabled(configuredLevel, targetLevel) { * @param {object} loggingConfig the logging configuration. * @return {string} the configured log level or default when none configured. */ -function extractConfiguredLevel(loggingConfig) { +function extractConfiguredLevel (loggingConfig) { if (loggingConfig && loggingConfig.level) { - const configuredLevel = loggingConfig.level; - const value = levels[configuredLevel]; + const configuredLevel = loggingConfig.level + const value = levels[configuredLevel] if (!value && value !== 0) { - throw newError(`Illegal logging level: ${configuredLevel}. Supported levels are: ${Object.keys(levels)}`); + throw newError( + `Illegal logging level: ${configuredLevel}. Supported levels are: ${Object.keys( + levels + )}` + ) } - return configuredLevel; + return configuredLevel } - return DEFAULT_LEVEL; + return DEFAULT_LEVEL } /** @@ -212,14 +210,14 @@ function extractConfiguredLevel(loggingConfig) { * @param {object} loggingConfig the logging configuration. * @return {function(level: string, message: string)} the configured logging function. */ -function extractConfiguredLogger(loggingConfig) { +function extractConfiguredLogger (loggingConfig) { if (loggingConfig && loggingConfig.logger) { - const configuredLogger = loggingConfig.logger; + const configuredLogger = loggingConfig.logger if (configuredLogger && typeof configuredLogger === 'function') { - return configuredLogger; + return configuredLogger } } - throw newError(`Illegal logger function: ${loggingConfig.logger}`); + throw newError(`Illegal logger function: ${loggingConfig.logger}`) } -export default Logger; +export default Logger diff --git a/src/v1/internal/node/index.js b/src/v1/internal/node/index.js index 87e43422b..82e15fc8b 100644 --- a/src/v1/internal/node/index.js +++ b/src/v1/internal/node/index.js @@ -17,10 +17,10 @@ * limitations under the License. */ -import NodeBuffer from './node-buf'; -import NodeChannel from './node-channel'; -import NodeHostNameResolver from './node-host-name-resolver'; -import utf8Codec from './node-utf8'; +import NodeBuffer from './node-buf' +import NodeChannel from './node-channel' +import NodeHostNameResolver from './node-host-name-resolver' +import utf8Codec from './node-utf8' /* @@ -33,7 +33,7 @@ NOTE: exports in this module should have exactly the same names/structure as exp */ -export const alloc = arg => new NodeBuffer(arg); -export const Channel = NodeChannel; -export const HostNameResolver = NodeHostNameResolver; -export const utf8 = utf8Codec; +export const alloc = arg => new NodeBuffer(arg) +export const Channel = NodeChannel +export const HostNameResolver = NodeHostNameResolver +export const utf8 = utf8Codec diff --git a/src/v1/internal/node/node-buf.js b/src/v1/internal/node/node-buf.js index 50b1e2609..bbc3be430 100644 --- a/src/v1/internal/node/node-buf.js +++ b/src/v1/internal/node/node-buf.js @@ -17,68 +17,75 @@ * limitations under the License. */ -import node from 'buffer'; -import BaseBuffer from '../buf/base-buf'; +import node from 'buffer' +import BaseBuffer from '../buf/base-buf' export default class NodeBuffer extends BaseBuffer { - - constructor(arg) { - const buffer = newNodeJSBuffer(arg); - super(buffer.length); - this._buffer = buffer; + constructor (arg) { + const buffer = newNodeJSBuffer(arg) + super(buffer.length) + this._buffer = buffer } - getUInt8(position) { - return this._buffer.readUInt8(position); + getUInt8 (position) { + return this._buffer.readUInt8(position) } - getInt8(position) { - return this._buffer.readInt8(position); + getInt8 (position) { + return this._buffer.readInt8(position) } - getFloat64(position) { - return this._buffer.readDoubleBE(position); + getFloat64 (position) { + return this._buffer.readDoubleBE(position) } - putUInt8(position, val) { - this._buffer.writeUInt8(val, position); + putUInt8 (position, val) { + this._buffer.writeUInt8(val, position) } - putInt8(position, val) { - this._buffer.writeInt8(val, position); + putInt8 (position, val) { + this._buffer.writeInt8(val, position) } - putFloat64(position, val) { - this._buffer.writeDoubleBE(val, position); + putFloat64 (position, val) { + this._buffer.writeDoubleBE(val, position) } - putBytes(position, val) { + putBytes (position, val) { if (val instanceof NodeBuffer) { - const bytesToCopy = Math.min(val.length - val.position, this.length - position); + const bytesToCopy = Math.min( + val.length - val.position, + this.length - position + ) val._buffer.copy( this._buffer, position, val.position, - val.position + bytesToCopy); - val.position += bytesToCopy; + val.position + bytesToCopy + ) + val.position += bytesToCopy } else { - super.putBytes(position, val); + super.putBytes(position, val) } - }; + } - getSlice(start, length) { - return new NodeBuffer(this._buffer.slice(start, start + length)); + getSlice (start, length) { + return new NodeBuffer(this._buffer.slice(start, start + length)) } } -function newNodeJSBuffer(arg) { +function newNodeJSBuffer (arg) { if (arg instanceof node.Buffer) { - return arg; - } else if (typeof arg === 'number' && typeof node.Buffer.alloc === 'function') { + return arg + } else if ( + typeof arg === 'number' && + typeof node.Buffer.alloc === 'function' + ) { // use static factory function present in newer NodeJS versions to allocate new buffer with specified size - return node.Buffer.alloc(arg); + return node.Buffer.alloc(arg) } else { // fallback to the old, potentially deprecated constructor - return new node.Buffer(arg); + // eslint-disable-next-line node/no-deprecated-api + return new node.Buffer(arg) } } diff --git a/src/v1/internal/node/node-channel.js b/src/v1/internal/node/node-channel.js index 3b5c7360b..c48bfec32 100644 --- a/src/v1/internal/node/node-channel.js +++ b/src/v1/internal/node/node-channel.js @@ -16,223 +16,322 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import net from 'net'; -import tls from 'tls'; -import fs from 'fs'; -import path from 'path'; -import readline from 'readline'; -import crypto from 'crypto'; -import {EOL} from 'os'; -import NodeBuffer from './node-buf'; -import {ENCRYPTION_OFF, ENCRYPTION_ON, isEmptyObjectOrNull} from '../util'; -import {newError} from '../../error'; - -let _CONNECTION_IDGEN = 0; - -function userHome() { +import net from 'net' +import tls from 'tls' +import fs from 'fs' +import path from 'path' +import readline from 'readline' +import crypto from 'crypto' +import { EOL } from 'os' +import NodeBuffer from './node-buf' +import { ENCRYPTION_OFF, ENCRYPTION_ON, isEmptyObjectOrNull } from '../util' +import { newError } from '../../error' + +let _CONNECTION_IDGEN = 0 + +function userHome () { // For some reason, Browserify chokes on shimming `process`. This code // will never get executed on the browser anyway, to just hack around it - let getOutOfHereBrowserifyYoureDrunk = require; - let process = getOutOfHereBrowserifyYoureDrunk('process'); + let getOutOfHereBrowserifyYoureDrunk = require + let process = getOutOfHereBrowserifyYoureDrunk('process') - return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; + return process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME'] } -function mkFullPath(pathToCreate) { +function mkFullPath (pathToCreate) { try { - fs.mkdirSync( pathToCreate ); + fs.mkdirSync(pathToCreate) } catch (e) { - if(e.code === 'ENOENT') { + if (e.code === 'ENOENT') { // Create parent dir - mkFullPath(path.dirname( pathToCreate )); + mkFullPath(path.dirname(pathToCreate)) // And now try again - mkFullPath( pathToCreate ); - return; + mkFullPath(pathToCreate) + return } if (e.code === 'EEXIST') { - return; + return } - throw e; + throw e } } -function loadFingerprint( serverId, knownHostsPath, cb ) { +function loadFingerprint (serverId, knownHostsPath, cb) { try { - fs.accessSync( knownHostsPath ); - } catch(e) { + fs.accessSync(knownHostsPath) + } catch (e) { return cb(null) } - let found = false; - readline.createInterface({ - input: fs.createReadStream(knownHostsPath) - }).on('line', (line) => { - if( !found && line.startsWith( serverId )) { - found = true; - cb( line.split(" ")[1] ); - } - }).on('close', () => { - if(!found) { - cb(null); - } - }); + let found = false + readline + .createInterface({ + input: fs.createReadStream(knownHostsPath) + }) + .on('line', line => { + if (!found && line.startsWith(serverId)) { + found = true + cb(line.split(' ')[1]) + } + }) + .on('close', () => { + if (!found) { + cb(null) + } + }) } -const _lockFingerprintFromAppending = {}; -function storeFingerprint( serverId, knownHostsPath, fingerprint, cb ) { +const _lockFingerprintFromAppending = {} +function storeFingerprint (serverId, knownHostsPath, fingerprint, cb) { // we check if the serverId has been appended - if(!!_lockFingerprintFromAppending[serverId]){ + if (_lockFingerprintFromAppending[serverId]) { // if it has, we ignore it - return cb(null); + return cb(null) } // we make the line as appended // ( 1 is more efficient to store than true because true is an oddball ) - _lockFingerprintFromAppending[serverId] = 1; + _lockFingerprintFromAppending[serverId] = 1 // If file doesn't exist, create full path to it try { - fs.accessSync(knownHostsPath); + fs.accessSync(knownHostsPath) } catch (_) { - mkFullPath(path.dirname(knownHostsPath)); + mkFullPath(path.dirname(knownHostsPath)) } - fs.appendFile(knownHostsPath, serverId + " " + fingerprint + EOL, "utf8", (err) => { - delete _lockFingerprintFromAppending[serverId]; - if (err) { - console.log(err); + fs.appendFile( + knownHostsPath, + serverId + ' ' + fingerprint + EOL, + 'utf8', + err => { + delete _lockFingerprintFromAppending[serverId] + if (err) { + console.log(err) + } + return cb(err) } - return cb(err); - }); + ) } const TrustStrategy = { /** * @deprecated Since version 1.0. Will be deleted in a future version. {@link #TRUST_CUSTOM_CA_SIGNED_CERTIFICATES}. */ - TRUST_SIGNED_CERTIFICATES: function( config, onSuccess, onFailure ) { - console.warn('`TRUST_SIGNED_CERTIFICATES` has been deprecated as option and will be removed in a future version of ' + - "the driver. Please use `TRUST_CUSTOM_CA_SIGNED_CERTIFICATES` instead."); - return TrustStrategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES(config, onSuccess, onFailure); + TRUST_SIGNED_CERTIFICATES: function (config, onSuccess, onFailure) { + console.warn( + '`TRUST_SIGNED_CERTIFICATES` has been deprecated as option and will be removed in a future version of ' + + 'the driver. Please use `TRUST_CUSTOM_CA_SIGNED_CERTIFICATES` instead.' + ) + return TrustStrategy.TRUST_CUSTOM_CA_SIGNED_CERTIFICATES( + config, + onSuccess, + onFailure + ) }, - TRUST_CUSTOM_CA_SIGNED_CERTIFICATES : function( config, onSuccess, onFailure ) { - if( !config.trustedCertificates || config.trustedCertificates.length === 0 ) { - onFailure(newError("You are using TRUST_CUSTOM_CA_SIGNED_CERTIFICATES as the method " + - "to verify trust for encrypted connections, but have not configured any " + - "trustedCertificates. You must specify the path to at least one trusted " + - "X.509 certificate for this to work. Two other alternatives is to use " + - "TRUST_ALL_CERTIFICATES or to disable encryption by setting encrypted=\"" + ENCRYPTION_OFF + "\"" + - "in your driver configuration.")); - return; + TRUST_CUSTOM_CA_SIGNED_CERTIFICATES: function (config, onSuccess, onFailure) { + if ( + !config.trustedCertificates || + config.trustedCertificates.length === 0 + ) { + onFailure( + newError( + 'You are using TRUST_CUSTOM_CA_SIGNED_CERTIFICATES as the method ' + + 'to verify trust for encrypted connections, but have not configured any ' + + 'trustedCertificates. You must specify the path to at least one trusted ' + + 'X.509 certificate for this to work. Two other alternatives is to use ' + + 'TRUST_ALL_CERTIFICATES or to disable encryption by setting encrypted="' + + ENCRYPTION_OFF + + '"' + + 'in your driver configuration.' + ) + ) + return } - const tlsOpts = newTlsOptions(config.address.host(), config.trustedCertificates.map((f) => fs.readFileSync(f))); - const socket = tls.connect(config.address.port(), config.address.resolvedHost(), tlsOpts, function () { - if (!socket.authorized) { - onFailure(newError("Server certificate is not trusted. If you trust the database you are connecting to, add" + - " the signing certificate, or the server certificate, to the list of certificates trusted by this driver" + - " using `neo4j.v1.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This " + - " is a security measure to protect against man-in-the-middle attacks. If you are just trying " + - " Neo4j out and are not concerned about encryption, simply disable it using `encrypted=\"" + ENCRYPTION_OFF + "\"`" + - " in the driver options. Socket responded with: " + socket.authorizationError)); - } else { - onSuccess(); + const tlsOpts = newTlsOptions( + config.address.host(), + config.trustedCertificates.map(f => fs.readFileSync(f)) + ) + const socket = tls.connect( + config.address.port(), + config.address.resolvedHost(), + tlsOpts, + function () { + if (!socket.authorized) { + onFailure( + newError( + 'Server certificate is not trusted. If you trust the database you are connecting to, add' + + ' the signing certificate, or the server certificate, to the list of certificates trusted by this driver' + + " using `neo4j.v1.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This " + + ' is a security measure to protect against man-in-the-middle attacks. If you are just trying ' + + ' Neo4j out and are not concerned about encryption, simply disable it using `encrypted="' + + ENCRYPTION_OFF + + '"`' + + ' in the driver options. Socket responded with: ' + + socket.authorizationError + ) + ) + } else { + onSuccess() + } } - }); - socket.on('error', onFailure); - return configureSocket(socket); + ) + socket.on('error', onFailure) + return configureSocket(socket) }, - TRUST_SYSTEM_CA_SIGNED_CERTIFICATES : function( config, onSuccess, onFailure ) { - const tlsOpts = newTlsOptions(config.address.host()); - const socket = tls.connect(config.address.port(), config.address.resolvedHost(), tlsOpts, function () { - if (!socket.authorized) { - onFailure(newError("Server certificate is not trusted. If you trust the database you are connecting to, use " + - "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES and add" + - " the signing certificate, or the server certificate, to the list of certificates trusted by this driver" + - " using `neo4j.v1.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This " + - " is a security measure to protect against man-in-the-middle attacks. If you are just trying " + - " Neo4j out and are not concerned about encryption, simply disable it using `encrypted=\"" + ENCRYPTION_OFF + "\"`" + - " in the driver options. Socket responded with: " + socket.authorizationError)); - } else { - onSuccess(); + TRUST_SYSTEM_CA_SIGNED_CERTIFICATES: function (config, onSuccess, onFailure) { + const tlsOpts = newTlsOptions(config.address.host()) + const socket = tls.connect( + config.address.port(), + config.address.resolvedHost(), + tlsOpts, + function () { + if (!socket.authorized) { + onFailure( + newError( + 'Server certificate is not trusted. If you trust the database you are connecting to, use ' + + 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES and add' + + ' the signing certificate, or the server certificate, to the list of certificates trusted by this driver' + + " using `neo4j.v1.driver(.., { trustedCertificates:['path/to/certificate.crt']}). This " + + ' is a security measure to protect against man-in-the-middle attacks. If you are just trying ' + + ' Neo4j out and are not concerned about encryption, simply disable it using `encrypted="' + + ENCRYPTION_OFF + + '"`' + + ' in the driver options. Socket responded with: ' + + socket.authorizationError + ) + ) + } else { + onSuccess() + } } - }); - socket.on('error', onFailure); - return configureSocket(socket); + ) + socket.on('error', onFailure) + return configureSocket(socket) }, /** * @deprecated in 1.1 in favour of {@link #TRUST_ALL_CERTIFICATES}. Will be deleted in a future version. */ - TRUST_ON_FIRST_USE : function( config, onSuccess, onFailure ) { - console.warn('`TRUST_ON_FIRST_USE` has been deprecated as option and will be removed in a future version of ' + - "the driver. Please use `TRUST_ALL_CERTIFICATES` instead."); - - const tlsOpts = newTlsOptions(config.address.host()); - const socket = tls.connect(config.address.port(), config.address.resolvedHost(), tlsOpts, function () { - const serverCert = socket.getPeerCertificate(/*raw=*/true); - - if( !serverCert.raw ) { - // If `raw` is not available, we're on an old version of NodeJS, and - // the raw cert cannot be accessed (or, at least I couldn't find a way to) - // therefore, we can't generate a SHA512 fingerprint, meaning we can't - // do TOFU, and the safe approach is to fail. - onFailure(newError("You are using a version of NodeJS that does not " + - "support trust-on-first use encryption. You can either upgrade NodeJS to " + - "a newer version, use `trust:TRUST_CUSTOM_CA_SIGNED_CERTIFICATES` in your driver " + - "config instead, or disable encryption using `encrypted:\"" + ENCRYPTION_OFF+ "\"`.")); - return; - } - - const serverFingerprint = crypto.createHash('sha512').update(serverCert.raw).digest('hex'); - const knownHostsPath = config.knownHostsPath || path.join(userHome(), ".neo4j", "known_hosts"); - const serverId = config.address.asHostPort(); - - loadFingerprint(serverId, knownHostsPath, (knownFingerprint) => { - if( knownFingerprint === serverFingerprint ) { - onSuccess(); - } else if( knownFingerprint == null ) { - storeFingerprint( serverId, knownHostsPath, serverFingerprint, (err) => { - if (err) { - return onFailure(err); - } - return onSuccess(); - }); - } else { - onFailure(newError("Database encryption certificate has changed, and no longer " + - "matches the certificate stored for " + serverId + " in `" + knownHostsPath + - "`. As a security precaution, this driver will not automatically trust the new " + - "certificate, because doing so would allow an attacker to pretend to be the Neo4j " + - "instance we want to connect to. The certificate provided by the server looks like: " + - serverCert + ". If you trust that this certificate is valid, simply remove the line " + - "starting with " + serverId + " in `" + knownHostsPath + "`, and the driver will " + - "update the file with the new certificate. You can configure which file the driver " + - "should use to store this information by setting `knownHosts` to another path in " + - "your driver configuration - and you can disable encryption there as well using " + - "`encrypted:\"" + ENCRYPTION_OFF + "\"`.")) + TRUST_ON_FIRST_USE: function (config, onSuccess, onFailure) { + console.warn( + '`TRUST_ON_FIRST_USE` has been deprecated as option and will be removed in a future version of ' + + 'the driver. Please use `TRUST_ALL_CERTIFICATES` instead.' + ) + + const tlsOpts = newTlsOptions(config.address.host()) + const socket = tls.connect( + config.address.port(), + config.address.resolvedHost(), + tlsOpts, + function () { + const serverCert = socket.getPeerCertificate(/* raw= */ true) + + if (!serverCert.raw) { + // If `raw` is not available, we're on an old version of NodeJS, and + // the raw cert cannot be accessed (or, at least I couldn't find a way to) + // therefore, we can't generate a SHA512 fingerprint, meaning we can't + // do TOFU, and the safe approach is to fail. + onFailure( + newError( + 'You are using a version of NodeJS that does not ' + + 'support trust-on-first use encryption. You can either upgrade NodeJS to ' + + 'a newer version, use `trust:TRUST_CUSTOM_CA_SIGNED_CERTIFICATES` in your driver ' + + 'config instead, or disable encryption using `encrypted:"' + + ENCRYPTION_OFF + + '"`.' + ) + ) + return } - }); - }); - socket.on('error', onFailure); - return configureSocket(socket); + + const serverFingerprint = crypto + .createHash('sha512') + .update(serverCert.raw) + .digest('hex') + const knownHostsPath = + config.knownHostsPath || + path.join(userHome(), '.neo4j', 'known_hosts') + const serverId = config.address.asHostPort() + + loadFingerprint(serverId, knownHostsPath, knownFingerprint => { + if (knownFingerprint === serverFingerprint) { + onSuccess() + } else if (knownFingerprint == null) { + storeFingerprint( + serverId, + knownHostsPath, + serverFingerprint, + err => { + if (err) { + return onFailure(err) + } + return onSuccess() + } + ) + } else { + onFailure( + newError( + 'Database encryption certificate has changed, and no longer ' + + 'matches the certificate stored for ' + + serverId + + ' in `' + + knownHostsPath + + '`. As a security precaution, this driver will not automatically trust the new ' + + 'certificate, because doing so would allow an attacker to pretend to be the Neo4j ' + + 'instance we want to connect to. The certificate provided by the server looks like: ' + + serverCert + + '. If you trust that this certificate is valid, simply remove the line ' + + 'starting with ' + + serverId + + ' in `' + + knownHostsPath + + '`, and the driver will ' + + 'update the file with the new certificate. You can configure which file the driver ' + + 'should use to store this information by setting `knownHosts` to another path in ' + + 'your driver configuration - and you can disable encryption there as well using ' + + '`encrypted:"' + + ENCRYPTION_OFF + + '"`.' + ) + ) + } + }) + } + ) + socket.on('error', onFailure) + return configureSocket(socket) }, TRUST_ALL_CERTIFICATES: function (config, onSuccess, onFailure) { - const tlsOpts = newTlsOptions(config.address.host()); - const socket = tls.connect(config.address.port(), config.address.resolvedHost(), tlsOpts, function () { - const certificate = socket.getPeerCertificate(); - if (isEmptyObjectOrNull(certificate)) { - onFailure(newError("Secure connection was successful but server did not return any valid " + - "certificates. Such connection can not be trusted. If you are just trying " + - " Neo4j out and are not concerned about encryption, simply disable it using " + - "`encrypted=\"" + ENCRYPTION_OFF + "\"` in the driver options. " + - "Socket responded with: " + socket.authorizationError)); - } else { - onSuccess(); + const tlsOpts = newTlsOptions(config.address.host()) + const socket = tls.connect( + config.address.port(), + config.address.resolvedHost(), + tlsOpts, + function () { + const certificate = socket.getPeerCertificate() + if (isEmptyObjectOrNull(certificate)) { + onFailure( + newError( + 'Secure connection was successful but server did not return any valid ' + + 'certificates. Such connection can not be trusted. If you are just trying ' + + ' Neo4j out and are not concerned about encryption, simply disable it using ' + + '`encrypted="' + + ENCRYPTION_OFF + + '"` in the driver options. ' + + 'Socket responded with: ' + + socket.authorizationError + ) + ) + } else { + onSuccess() + } } - }); - socket.on('error', onFailure); - return configureSocket(socket); + ) + socket.on('error', onFailure) + return configureSocket(socket) } -}; +} /** * Connect using node socket. @@ -241,39 +340,52 @@ const TrustStrategy = { * @param {function} onFailure - callback to execute on connection failure. * @return {*} socket connection. */ -function connect( config, onSuccess, onFailure=(()=>null) ) { - const trustStrategy = trustStrategyName(config); +function connect (config, onSuccess, onFailure = () => null) { + const trustStrategy = trustStrategyName(config) if (!isEncrypted(config)) { - const socket = net.connect(config.address.port(), config.address.resolvedHost(), onSuccess); - socket.on('error', onFailure); - return configureSocket(socket); + const socket = net.connect( + config.address.port(), + config.address.resolvedHost(), + onSuccess + ) + socket.on('error', onFailure) + return configureSocket(socket) } else if (TrustStrategy[trustStrategy]) { - return TrustStrategy[trustStrategy](config, onSuccess, onFailure); + return TrustStrategy[trustStrategy](config, onSuccess, onFailure) } else { - onFailure(newError("Unknown trust strategy: " + config.trust + ". Please use either " + - "trust:'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' or trust:'TRUST_ALL_CERTIFICATES' in your driver " + - "configuration. Alternatively, you can disable encryption by setting " + - "`encrypted:\"" + ENCRYPTION_OFF + "\"`. There is no mechanism to use encryption without trust verification, " + - "because this incurs the overhead of encryption without improving security. If " + - "the driver does not verify that the peer it is connected to is really Neo4j, it " + - "is very easy for an attacker to bypass the encryption by pretending to be Neo4j.")); + onFailure( + newError( + 'Unknown trust strategy: ' + + config.trust + + '. Please use either ' + + "trust:'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' or trust:'TRUST_ALL_CERTIFICATES' in your driver " + + 'configuration. Alternatively, you can disable encryption by setting ' + + '`encrypted:"' + + ENCRYPTION_OFF + + '"`. There is no mechanism to use encryption without trust verification, ' + + 'because this incurs the overhead of encryption without improving security. If ' + + 'the driver does not verify that the peer it is connected to is really Neo4j, it ' + + 'is very easy for an attacker to bypass the encryption by pretending to be Neo4j.' + ) + ) } } -function isEncrypted(config) { - const encryptionNotConfigured = config.encrypted == null || config.encrypted === undefined; +function isEncrypted (config) { + const encryptionNotConfigured = + config.encrypted == null || config.encrypted === undefined if (encryptionNotConfigured) { // default to using encryption if trust-all-certificates is available - return true; + return true } - return config.encrypted === true || config.encrypted === ENCRYPTION_ON; + return config.encrypted === true || config.encrypted === ENCRYPTION_ON } -function trustStrategyName(config) { +function trustStrategyName (config) { if (config.trust) { - return config.trust; + return config.trust } - return 'TRUST_ALL_CERTIFICATES'; + return 'TRUST_ALL_CERTIFICATES' } /** @@ -282,12 +394,12 @@ function trustStrategyName(config) { * @param {string|undefined} ca an optional CA. * @return {object} a new options object. */ -function newTlsOptions(hostname, ca = undefined) { +function newTlsOptions (hostname, ca = undefined) { return { rejectUnauthorized: false, // we manually check for this in the connect callback, to give a more helpful error to the user servername: hostname, // server name for the SNI (Server Name Indication) TLS extension - ca: ca, // optional CA useful for TRUST_CUSTOM_CA_SIGNED_CERTIFICATES trust mode - }; + ca: ca // optional CA useful for TRUST_CUSTOM_CA_SIGNED_CERTIFICATES trust mode + } } /** @@ -295,9 +407,9 @@ function newTlsOptions(hostname, ca = undefined) { * @param {net.Socket} socket the socket to configure. * @return {net.Socket} the given socket. */ -function configureSocket(socket) { - socket.setKeepAlive(true); - return socket; +function configureSocket (socket) { + socket.setKeepAlive(true) + return socket } /** @@ -306,60 +418,68 @@ function configureSocket(socket) { * @access private */ export default class NodeChannel { - /** * Create new instance * @param {ChannelConfig} config - configuration for this channel. */ constructor (config) { - let self = this; - - this.id = _CONNECTION_IDGEN++; - this._pending = []; - this._open = true; - this._error = null; - this._handleConnectionError = this._handleConnectionError.bind(this); - this._handleConnectionTerminated = this._handleConnectionTerminated.bind(this); - this._connectionErrorCode = config.connectionErrorCode; - - this._conn = connect(config, () => { - if(!self._open) { - return; - } - - self._conn.on('data', ( buffer ) => { - if( self.onmessage ) { - self.onmessage( new NodeBuffer( buffer ) ); + let self = this + + this.id = _CONNECTION_IDGEN++ + this._pending = [] + this._open = true + this._error = null + this._handleConnectionError = this._handleConnectionError.bind(this) + this._handleConnectionTerminated = this._handleConnectionTerminated.bind( + this + ) + this._connectionErrorCode = config.connectionErrorCode + + this._conn = connect( + config, + () => { + if (!self._open) { + return } - }); - self._conn.on('error', self._handleConnectionError); - self._conn.on('end', self._handleConnectionTerminated); + self._conn.on('data', buffer => { + if (self.onmessage) { + self.onmessage(new NodeBuffer(buffer)) + } + }) - // Drain all pending messages - let pending = self._pending; - self._pending = null; - for (let i = 0; i < pending.length; i++) { - self.write( pending[i] ); - } - }, this._handleConnectionError); + self._conn.on('error', self._handleConnectionError) + self._conn.on('end', self._handleConnectionTerminated) + + // Drain all pending messages + let pending = self._pending + self._pending = null + for (let i = 0; i < pending.length; i++) { + self.write(pending[i]) + } + }, + this._handleConnectionError + ) - this._setupConnectionTimeout(config, this._conn); + this._setupConnectionTimeout(config, this._conn) } - _handleConnectionError( err ) { - let msg = err.message || 'Failed to connect to server'; - this._error = newError(msg, this._connectionErrorCode); - if( this.onerror ) { - this.onerror(this._error); + _handleConnectionError (err) { + let msg = err.message || 'Failed to connect to server' + this._error = newError(msg, this._connectionErrorCode) + if (this.onerror) { + this.onerror(this._error) } } - _handleConnectionTerminated() { - this._error = newError('Connection was closed by server', this._connectionErrorCode); - if( this.onerror ) { - this.onerror(this._error); - } + _handleConnectionTerminated () { + this._error = newError( + 'Connection was closed by server', + this._connectionErrorCode + ) + if (this.onerror) { + this.onerror(this._error) + } } /** @@ -368,21 +488,26 @@ export default class NodeChannel { * @param {object} socket - `net.Socket` or `tls.TLSSocket` object. * @private */ - _setupConnectionTimeout(config, socket) { - const timeout = config.connectionTimeout; + _setupConnectionTimeout (config, socket) { + const timeout = config.connectionTimeout if (timeout) { socket.on('connect', () => { // connected - clear connection timeout - socket.setTimeout(0); - }); + socket.setTimeout(0) + }) socket.on('timeout', () => { // timeout fired - not connected within configured time. cancel timeout and destroy socket - socket.setTimeout(0); - socket.destroy(newError(`Failed to establish connection in ${timeout}ms`, config.connectionErrorCode)); - }); - - socket.setTimeout(timeout); + socket.setTimeout(0) + socket.destroy( + newError( + `Failed to establish connection in ${timeout}ms`, + config.connectionErrorCode + ) + ) + }) + + socket.setTimeout(timeout) } } @@ -390,15 +515,15 @@ export default class NodeChannel { * Write the passed in buffer to connection * @param {NodeBuffer} buffer - Buffer to write */ - write ( buffer ) { + write (buffer) { // If there is a pending queue, push this on that queue. This means // we are not yet connected, so we queue things locally. - if( this._pending !== null ) { - this._pending.push( buffer ); - } else if( buffer instanceof NodeBuffer ) { - this._conn.write( buffer._buffer ); + if (this._pending !== null) { + this._pending.push(buffer) + } else if (buffer instanceof NodeBuffer) { + this._conn.write(buffer._buffer) } else { - throw newError( "Don't know how to write: " + buffer ); + throw newError("Don't know how to write: " + buffer) } } @@ -406,14 +531,14 @@ export default class NodeChannel { * Close the connection * @param {function} cb - Function to call on close. */ - close(cb = (() => null)) { - this._open = false; - if( this._conn ) { - this._conn.end(); - this._conn.removeListener('end', this._handleConnectionTerminated); - this._conn.on('end', cb); + close (cb = () => null) { + this._open = false + if (this._conn) { + this._conn.end() + this._conn.removeListener('end', this._handleConnectionTerminated) + this._conn.on('end', cb) } else { - cb(); + cb() } } } diff --git a/src/v1/internal/node/node-host-name-resolver.js b/src/v1/internal/node/node-host-name-resolver.js index 3eb4e4e89..ea6731fb9 100644 --- a/src/v1/internal/node/node-host-name-resolver.js +++ b/src/v1/internal/node/node-host-name-resolver.js @@ -17,22 +17,22 @@ * limitations under the License. */ -import BaseHostNameResolver from '../resolver/base-host-name-resolver'; -import urlUtil from '../url-util'; -import nodeDns from 'dns'; +import BaseHostNameResolver from '../resolver/base-host-name-resolver' +import nodeDns from 'dns' export default class NodeHostNameResolver extends BaseHostNameResolver { - - resolve(address) { - return new Promise((resolve) => { + resolve (address) { + return new Promise(resolve => { nodeDns.lookup(address.host(), { all: true }, (error, resolvedTo) => { if (error) { - resolve([address]); + resolve([address]) } else { - const resolvedAddresses = resolvedTo.map(a => address.resolveWith(a.address)); - resolve(resolvedAddresses); + const resolvedAddresses = resolvedTo.map(a => + address.resolveWith(a.address) + ) + resolve(resolvedAddresses) } - }); - }); + }) + }) } } diff --git a/src/v1/internal/node/node-utf8.js b/src/v1/internal/node/node-utf8.js index 7aadbb253..6f3e390f6 100644 --- a/src/v1/internal/node/node-utf8.js +++ b/src/v1/internal/node/node-utf8.js @@ -17,76 +17,89 @@ * limitations under the License. */ -import CombinedBuffer from '../buf/combined-buf'; -import NodeBuffer from '../node/node-buf'; -import {newError} from '../../error'; -import node from 'buffer'; -import {StringDecoder} from 'string_decoder'; +import CombinedBuffer from '../buf/combined-buf' +import NodeBuffer from '../node/node-buf' +import { newError } from '../../error' +import node from 'buffer' +import { StringDecoder } from 'string_decoder' -const decoder = new StringDecoder('utf8'); +const decoder = new StringDecoder('utf8') -function encode(str) { - return new NodeBuffer(newNodeJSBuffer(str)); +function encode (str) { + return new NodeBuffer(newNodeJSBuffer(str)) } -function decode(buffer, length) { +function decode (buffer, length) { if (buffer instanceof NodeBuffer) { - return decodeNodeBuffer(buffer, length); + return decodeNodeBuffer(buffer, length) } else if (buffer instanceof CombinedBuffer) { - return decodeCombinedBuffer(buffer, length); + return decodeCombinedBuffer(buffer, length) } else { - throw newError(`Don't know how to decode strings from '${buffer}'`); + throw newError(`Don't know how to decode strings from '${buffer}'`) } } -function decodeNodeBuffer(buffer, length) { - const start = buffer.position; - const end = start + length; - buffer.position = Math.min(end, buffer.length); - return buffer._buffer.toString('utf8', start, end); +function decodeNodeBuffer (buffer, length) { + const start = buffer.position + const end = start + length + buffer.position = Math.min(end, buffer.length) + return buffer._buffer.toString('utf8', start, end) } -function decodeCombinedBuffer(buffer, length) { - return streamDecodeCombinedBuffer(buffer, length, +function decodeCombinedBuffer (buffer, length) { + return streamDecodeCombinedBuffer( + buffer, + length, partBuffer => decoder.write(partBuffer._buffer), () => decoder.end() - ); + ) } -function streamDecodeCombinedBuffer(combinedBuffers, length, decodeFn, endFn) { - let remainingBytesToRead = length; - let position = combinedBuffers.position; - combinedBuffers._updatePos(Math.min(length, combinedBuffers.length - position)); +function streamDecodeCombinedBuffer (combinedBuffers, length, decodeFn, endFn) { + let remainingBytesToRead = length + let position = combinedBuffers.position + combinedBuffers._updatePos( + Math.min(length, combinedBuffers.length - position) + ) // Reduce CombinedBuffers to a decoded string const out = combinedBuffers._buffers.reduce(function (last, partBuffer) { if (remainingBytesToRead <= 0) { - return last; + return last } else if (position >= partBuffer.length) { - position -= partBuffer.length; - return ''; + position -= partBuffer.length + return '' } else { - partBuffer._updatePos(position - partBuffer.position); - let bytesToRead = Math.min(partBuffer.length - position, remainingBytesToRead); - let lastSlice = partBuffer.readSlice(bytesToRead); - partBuffer._updatePos(bytesToRead); - remainingBytesToRead = Math.max(remainingBytesToRead - lastSlice.length, 0); - position = 0; - return last + decodeFn(lastSlice); + partBuffer._updatePos(position - partBuffer.position) + let bytesToRead = Math.min( + partBuffer.length - position, + remainingBytesToRead + ) + let lastSlice = partBuffer.readSlice(bytesToRead) + partBuffer._updatePos(bytesToRead) + remainingBytesToRead = Math.max( + remainingBytesToRead - lastSlice.length, + 0 + ) + position = 0 + return last + decodeFn(lastSlice) } - }, ''); - return out + endFn(); + }, '') + return out + endFn() } -function newNodeJSBuffer(str) { +function newNodeJSBuffer (str) { // use static factory function present in newer NodeJS versions to create a buffer containing the given string // or fallback to the old, potentially deprecated constructor - return typeof node.Buffer.from === 'function' - ? node.Buffer.from(str, 'utf8') - : new node.Buffer(str, 'utf8'); + if (typeof node.Buffer.from === 'function') { + return node.Buffer.from(str, 'utf8') + } else { + // eslint-disable-next-line node/no-deprecated-api + return new node.Buffer(str, 'utf8') + } } export default { encode, decode -}; +} diff --git a/src/v1/internal/packstream-v1.js b/src/v1/internal/packstream-v1.js index c55b3183c..966ac7522 100644 --- a/src/v1/internal/packstream-v1.js +++ b/src/v1/internal/packstream-v1.js @@ -16,87 +16,93 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {utf8} from './node'; -import Integer, {int, isInt} from '../integer'; -import {newError, PROTOCOL_ERROR} from './../error'; -import {Chunker} from './chunking'; -import {Node, Path, PathSegment, Relationship, UnboundRelationship} from '../graph-types'; - -const TINY_STRING = 0x80; -const TINY_LIST = 0x90; -const TINY_MAP = 0xA0; -const TINY_STRUCT = 0xB0; -const NULL = 0xC0; -const FLOAT_64 = 0xC1; -const FALSE = 0xC2; -const TRUE = 0xC3; -const INT_8 = 0xC8; -const INT_16 = 0xC9; -const INT_32 = 0xCA; -const INT_64 = 0xCB; -const STRING_8 = 0xD0; -const STRING_16 = 0xD1; -const STRING_32 = 0xD2; -const LIST_8 = 0xD4; -const LIST_16 = 0xD5; -const LIST_32 = 0xD6; -const BYTES_8 = 0xCC; -const BYTES_16 = 0xCD; -const BYTES_32 = 0xCE; -const MAP_8 = 0xD8; -const MAP_16 = 0xD9; -const MAP_32 = 0xDA; -const STRUCT_8 = 0xDC; -const STRUCT_16 = 0xDD; - -const NODE = 0x4E; -const NODE_STRUCT_SIZE = 3; - -const RELATIONSHIP = 0x52; -const RELATIONSHIP_STRUCT_SIZE = 5; - -const UNBOUND_RELATIONSHIP = 0x72; -const UNBOUND_RELATIONSHIP_STRUCT_SIZE = 3; - -const PATH = 0x50; -const PATH_STRUCT_SIZE = 3; +import { utf8 } from './node' +import Integer, { int, isInt } from '../integer' +import { newError, PROTOCOL_ERROR } from './../error' +import { + Node, + Path, + PathSegment, + Relationship, + UnboundRelationship +} from '../graph-types' + +const TINY_STRING = 0x80 +const TINY_LIST = 0x90 +const TINY_MAP = 0xa0 +const TINY_STRUCT = 0xb0 +const NULL = 0xc0 +const FLOAT_64 = 0xc1 +const FALSE = 0xc2 +const TRUE = 0xc3 +const INT_8 = 0xc8 +const INT_16 = 0xc9 +const INT_32 = 0xca +const INT_64 = 0xcb +const STRING_8 = 0xd0 +const STRING_16 = 0xd1 +const STRING_32 = 0xd2 +const LIST_8 = 0xd4 +const LIST_16 = 0xd5 +const LIST_32 = 0xd6 +const BYTES_8 = 0xcc +const BYTES_16 = 0xcd +const BYTES_32 = 0xce +const MAP_8 = 0xd8 +const MAP_16 = 0xd9 +const MAP_32 = 0xda +const STRUCT_8 = 0xdc +const STRUCT_16 = 0xdd + +const NODE = 0x4e +const NODE_STRUCT_SIZE = 3 + +const RELATIONSHIP = 0x52 +const RELATIONSHIP_STRUCT_SIZE = 5 + +const UNBOUND_RELATIONSHIP = 0x72 +const UNBOUND_RELATIONSHIP_STRUCT_SIZE = 3 + +const PATH = 0x50 +const PATH_STRUCT_SIZE = 3 /** - * A Structure have a signature and fields. - * @access private - */ + * A Structure have a signature and fields. + * @access private + */ class Structure { /** * Create new instance */ - constructor( signature, fields ) { - this.signature = signature; - this.fields = fields; + constructor (signature, fields) { + this.signature = signature + this.fields = fields } - toString() { - let fieldStr = ""; + toString () { + let fieldStr = '' for (var i = 0; i < this.fields.length; i++) { - if(i > 0) { fieldStr+=", " } - fieldStr += this.fields[i]; + if (i > 0) { + fieldStr += ', ' + } + fieldStr += this.fields[i] } - return "Structure(" + this.signature + ", [" + this.fields + "])" + return 'Structure(' + this.signature + ', [' + fieldStr + '])' } } /** - * Class to pack - * @access private - */ + * Class to pack + * @access private + */ class Packer { - /** * @constructor * @param {Chunker} channel the chunker backed by a network channel. */ - constructor(channel) { - this._ch = channel; - this._byteArraysSupported = true; + constructor (channel) { + this._ch = channel + this._byteArraysSupported = true } /** @@ -107,71 +113,83 @@ class Packer { */ packable (x, onError) { if (x === null) { - return () => this._ch.writeUInt8( NULL ); + return () => this._ch.writeUInt8(NULL) } else if (x === true) { - return () => this._ch.writeUInt8( TRUE ); + return () => this._ch.writeUInt8(TRUE) } else if (x === false) { - return () => this._ch.writeUInt8( FALSE ); - } else if (typeof(x) == "number") { - return () => this.packFloat(x); - } else if (typeof(x) == "string") { - return () => this.packString(x, onError); + return () => this._ch.writeUInt8(FALSE) + } else if (typeof x === 'number') { + return () => this.packFloat(x) + } else if (typeof x === 'string') { + return () => this.packString(x, onError) } else if (isInt(x)) { - return () => this.packInteger(x); + return () => this.packInteger(x) } else if (x instanceof Int8Array) { - return () => this.packBytes(x, onError); + return () => this.packBytes(x, onError) } else if (x instanceof Array) { return () => { - this.packListHeader(x.length, onError); + this.packListHeader(x.length, onError) for (let i = 0; i < x.length; i++) { - this.packable(x[i] === undefined ? null : x[i], onError)(); + this.packable(x[i] === undefined ? null : x[i], onError)() } } } else if (isIterable(x)) { - return this.packableIterable(x, onError); + return this.packableIterable(x, onError) } else if (x instanceof Node) { - return this._nonPackableValue(`It is not allowed to pass nodes in query parameters, given: ${x}`, onError); + return this._nonPackableValue( + `It is not allowed to pass nodes in query parameters, given: ${x}`, + onError + ) } else if (x instanceof Relationship) { - return this._nonPackableValue(`It is not allowed to pass relationships in query parameters, given: ${x}`, onError); + return this._nonPackableValue( + `It is not allowed to pass relationships in query parameters, given: ${x}`, + onError + ) } else if (x instanceof Path) { - return this._nonPackableValue(`It is not allowed to pass paths in query parameters, given: ${x}`, onError); + return this._nonPackableValue( + `It is not allowed to pass paths in query parameters, given: ${x}`, + onError + ) } else if (x instanceof Structure) { - var packableFields = []; + var packableFields = [] for (var i = 0; i < x.fields.length; i++) { - packableFields[i] = this.packable(x.fields[i], onError); + packableFields[i] = this.packable(x.fields[i], onError) } - return () => this.packStruct( x.signature, packableFields ); - } else if (typeof(x) == "object") { + return () => this.packStruct(x.signature, packableFields) + } else if (typeof x === 'object') { return () => { - let keys = Object.keys(x); + let keys = Object.keys(x) - let count = 0; + let count = 0 for (let i = 0; i < keys.length; i++) { if (x[keys[i]] !== undefined) { - count++; + count++ } } - this.packMapHeader(count, onError); + this.packMapHeader(count, onError) for (let i = 0; i < keys.length; i++) { - let key = keys[i]; + let key = keys[i] if (x[key] !== undefined) { - this.packString(key); - this.packable(x[key], onError)(); + this.packString(key) + this.packable(x[key], onError)() } } - }; + } } else { - return this._nonPackableValue(`Unable to pack the given value: ${x}`, onError); + return this._nonPackableValue( + `Unable to pack the given value: ${x}`, + onError + ) } } - packableIterable(iterable, onError) { + packableIterable (iterable, onError) { try { - const array = Array.from(iterable); - return this.packable(array, onError); + const array = Array.from(iterable) + return this.packable(array, onError) } catch (e) { // handle errors from iterable to array conversion - onError(newError(`Cannot pack given iterable, ${e.message}: ${iterable}`)); + onError(newError(`Cannot pack given iterable, ${e.message}: ${iterable}`)) } } @@ -180,484 +198,494 @@ class Packer { * @param signature the signature of the struct * @param packableFields the fields of the struct, make sure you call `packable on all fields` */ - packStruct ( signature, packableFields, onError) { - packableFields = packableFields || []; - this.packStructHeader(packableFields.length, signature, onError); - for(let i = 0; i < packableFields.length; i++) { - packableFields[i](); + packStruct (signature, packableFields, onError) { + packableFields = packableFields || [] + this.packStructHeader(packableFields.length, signature, onError) + for (let i = 0; i < packableFields.length; i++) { + packableFields[i]() } } packInteger (x) { - var high = x.high, - low = x.low; + var high = x.high + var low = x.low if (x.greaterThanOrEqual(-0x10) && x.lessThan(0x80)) { - this._ch.writeInt8(low); - } - else if (x.greaterThanOrEqual(-0x80) && x.lessThan(-0x10)) { - this._ch.writeUInt8(INT_8); - this._ch.writeInt8(low); - } - else if (x.greaterThanOrEqual(-0x8000) && x.lessThan(0x8000)) { - this._ch.writeUInt8(INT_16); - this._ch.writeInt16(low); - } - else if (x.greaterThanOrEqual(-0x80000000) && x.lessThan(0x80000000)) { - this._ch.writeUInt8(INT_32); - this._ch.writeInt32(low); - } - else { - this._ch.writeUInt8(INT_64); - this._ch.writeInt32(high); - this._ch.writeInt32(low); + this._ch.writeInt8(low) + } else if (x.greaterThanOrEqual(-0x80) && x.lessThan(-0x10)) { + this._ch.writeUInt8(INT_8) + this._ch.writeInt8(low) + } else if (x.greaterThanOrEqual(-0x8000) && x.lessThan(0x8000)) { + this._ch.writeUInt8(INT_16) + this._ch.writeInt16(low) + } else if (x.greaterThanOrEqual(-0x80000000) && x.lessThan(0x80000000)) { + this._ch.writeUInt8(INT_32) + this._ch.writeInt32(low) + } else { + this._ch.writeUInt8(INT_64) + this._ch.writeInt32(high) + this._ch.writeInt32(low) } } - packFloat(x) { - this._ch.writeUInt8(FLOAT_64); - this._ch.writeFloat64(x); + packFloat (x) { + this._ch.writeUInt8(FLOAT_64) + this._ch.writeFloat64(x) } packString (x, onError) { - let bytes = utf8.encode(x); - let size = bytes.length; + let bytes = utf8.encode(x) + let size = bytes.length if (size < 0x10) { - this._ch.writeUInt8(TINY_STRING | size); - this._ch.writeBytes(bytes); + this._ch.writeUInt8(TINY_STRING | size) + this._ch.writeBytes(bytes) } else if (size < 0x100) { this._ch.writeUInt8(STRING_8) - this._ch.writeUInt8(size); - this._ch.writeBytes(bytes); + this._ch.writeUInt8(size) + this._ch.writeBytes(bytes) } else if (size < 0x10000) { - this._ch.writeUInt8(STRING_16); - this._ch.writeUInt8(size/256>>0); - this._ch.writeUInt8(size%256); - this._ch.writeBytes(bytes); + this._ch.writeUInt8(STRING_16) + this._ch.writeUInt8((size / 256) >> 0) + this._ch.writeUInt8(size % 256) + this._ch.writeBytes(bytes) } else if (size < 0x100000000) { - this._ch.writeUInt8(STRING_32); - this._ch.writeUInt8((size/16777216>>0)%256); - this._ch.writeUInt8((size/65536>>0)%256); - this._ch.writeUInt8((size/256>>0)%256); - this._ch.writeUInt8(size%256); - this._ch.writeBytes(bytes); + this._ch.writeUInt8(STRING_32) + this._ch.writeUInt8(((size / 16777216) >> 0) % 256) + this._ch.writeUInt8(((size / 65536) >> 0) % 256) + this._ch.writeUInt8(((size / 256) >> 0) % 256) + this._ch.writeUInt8(size % 256) + this._ch.writeBytes(bytes) } else { - onError(newError("UTF-8 strings of size " + size + " are not supported")); + onError(newError('UTF-8 strings of size ' + size + ' are not supported')) } } packListHeader (size, onError) { if (size < 0x10) { - this._ch.writeUInt8(TINY_LIST | size); + this._ch.writeUInt8(TINY_LIST | size) } else if (size < 0x100) { this._ch.writeUInt8(LIST_8) - this._ch.writeUInt8(size); + this._ch.writeUInt8(size) } else if (size < 0x10000) { - this._ch.writeUInt8(LIST_16); - this._ch.writeUInt8((size/256>>0)%256); - this._ch.writeUInt8(size%256); + this._ch.writeUInt8(LIST_16) + this._ch.writeUInt8(((size / 256) >> 0) % 256) + this._ch.writeUInt8(size % 256) } else if (size < 0x100000000) { - this._ch.writeUInt8(LIST_32); - this._ch.writeUInt8((size/16777216>>0)%256); - this._ch.writeUInt8((size/65536>>0)%256); - this._ch.writeUInt8((size/256>>0)%256); - this._ch.writeUInt8(size%256); + this._ch.writeUInt8(LIST_32) + this._ch.writeUInt8(((size / 16777216) >> 0) % 256) + this._ch.writeUInt8(((size / 65536) >> 0) % 256) + this._ch.writeUInt8(((size / 256) >> 0) % 256) + this._ch.writeUInt8(size % 256) } else { - onError(newError("Lists of size " + size + " are not supported")); + onError(newError('Lists of size ' + size + ' are not supported')) } } - packBytes(array, onError) { - if(this._byteArraysSupported) { - this.packBytesHeader(array.length, onError); + packBytes (array, onError) { + if (this._byteArraysSupported) { + this.packBytesHeader(array.length, onError) for (let i = 0; i < array.length; i++) { - this._ch.writeInt8(array[i]); + this._ch.writeInt8(array[i]) } - }else { - onError(newError("Byte arrays are not supported by the database this driver is connected to")); + } else { + onError( + newError( + 'Byte arrays are not supported by the database this driver is connected to' + ) + ) } } - packBytesHeader(size, onError) { + packBytesHeader (size, onError) { if (size < 0x100) { - this._ch.writeUInt8(BYTES_8); - this._ch.writeUInt8(size); + this._ch.writeUInt8(BYTES_8) + this._ch.writeUInt8(size) } else if (size < 0x10000) { - this._ch.writeUInt8(BYTES_16); - this._ch.writeUInt8((size / 256 >> 0) % 256); - this._ch.writeUInt8(size % 256); + this._ch.writeUInt8(BYTES_16) + this._ch.writeUInt8(((size / 256) >> 0) % 256) + this._ch.writeUInt8(size % 256) } else if (size < 0x100000000) { - this._ch.writeUInt8(BYTES_32); - this._ch.writeUInt8((size / 16777216 >> 0) % 256); - this._ch.writeUInt8((size / 65536 >> 0) % 256); - this._ch.writeUInt8((size / 256 >> 0) % 256); - this._ch.writeUInt8(size % 256); + this._ch.writeUInt8(BYTES_32) + this._ch.writeUInt8(((size / 16777216) >> 0) % 256) + this._ch.writeUInt8(((size / 65536) >> 0) % 256) + this._ch.writeUInt8(((size / 256) >> 0) % 256) + this._ch.writeUInt8(size % 256) } else { - onError(newError('Byte arrays of size ' + size + ' are not supported')); + onError(newError('Byte arrays of size ' + size + ' are not supported')) } } packMapHeader (size, onError) { if (size < 0x10) { - this._ch.writeUInt8(TINY_MAP | size); + this._ch.writeUInt8(TINY_MAP | size) } else if (size < 0x100) { - this._ch.writeUInt8(MAP_8); - this._ch.writeUInt8(size); + this._ch.writeUInt8(MAP_8) + this._ch.writeUInt8(size) } else if (size < 0x10000) { - this._ch.writeUInt8(MAP_16); - this._ch.writeUInt8(size/256>>0); - this._ch.writeUInt8(size%256); + this._ch.writeUInt8(MAP_16) + this._ch.writeUInt8((size / 256) >> 0) + this._ch.writeUInt8(size % 256) } else if (size < 0x100000000) { - this._ch.writeUInt8(MAP_32); - this._ch.writeUInt8((size/16777216>>0)%256); - this._ch.writeUInt8((size/65536>>0)%256); - this._ch.writeUInt8((size/256>>0)%256); - this._ch.writeUInt8(size%256); + this._ch.writeUInt8(MAP_32) + this._ch.writeUInt8(((size / 16777216) >> 0) % 256) + this._ch.writeUInt8(((size / 65536) >> 0) % 256) + this._ch.writeUInt8(((size / 256) >> 0) % 256) + this._ch.writeUInt8(size % 256) } else { - onError(newError("Maps of size " + size + " are not supported")); + onError(newError('Maps of size ' + size + ' are not supported')) } } packStructHeader (size, signature, onError) { if (size < 0x10) { - this._ch.writeUInt8(TINY_STRUCT | size); - this._ch.writeUInt8(signature); + this._ch.writeUInt8(TINY_STRUCT | size) + this._ch.writeUInt8(signature) } else if (size < 0x100) { - this._ch.writeUInt8(STRUCT_8); - this._ch.writeUInt8(size); - this._ch.writeUInt8(signature); + this._ch.writeUInt8(STRUCT_8) + this._ch.writeUInt8(size) + this._ch.writeUInt8(signature) } else if (size < 0x10000) { - this._ch.writeUInt8(STRUCT_16); - this._ch.writeUInt8(size/256>>0); - this._ch.writeUInt8(size%256); + this._ch.writeUInt8(STRUCT_16) + this._ch.writeUInt8((size / 256) >> 0) + this._ch.writeUInt8(size % 256) } else { - onError(newError("Structures of size " + size + " are not supported")); + onError(newError('Structures of size ' + size + ' are not supported')) } } - disableByteArrays() { - this._byteArraysSupported = false; + disableByteArrays () { + this._byteArraysSupported = false } - _nonPackableValue(message, onError) { + _nonPackableValue (message, onError) { if (onError) { - onError(newError(message, PROTOCOL_ERROR)); + onError(newError(message, PROTOCOL_ERROR)) } - return () => undefined; + return () => undefined } } /** - * Class to unpack - * @access private - */ + * Class to unpack + * @access private + */ class Unpacker { - /** * @constructor * @param {boolean} disableLosslessIntegers if this unpacker should convert all received integers to native JS numbers. */ - constructor(disableLosslessIntegers = false) { - this._disableLosslessIntegers = disableLosslessIntegers; + constructor (disableLosslessIntegers = false) { + this._disableLosslessIntegers = disableLosslessIntegers } - unpack(buffer) { - const marker = buffer.readUInt8(); - const markerHigh = marker & 0xF0; - const markerLow = marker & 0x0F; + unpack (buffer) { + const marker = buffer.readUInt8() + const markerHigh = marker & 0xf0 + const markerLow = marker & 0x0f - if (marker == NULL) { - return null; + if (marker === NULL) { + return null } - const boolean = this._unpackBoolean(marker); + const boolean = this._unpackBoolean(marker) if (boolean !== null) { - return boolean; + return boolean } - const numberOrInteger = this._unpackNumberOrInteger(marker, buffer); + const numberOrInteger = this._unpackNumberOrInteger(marker, buffer) if (numberOrInteger !== null) { if (this._disableLosslessIntegers && isInt(numberOrInteger)) { - return numberOrInteger.toNumberOrInfinity(); + return numberOrInteger.toNumberOrInfinity() } - return numberOrInteger; + return numberOrInteger } - const string = this._unpackString(marker, markerHigh, markerLow, buffer); + const string = this._unpackString(marker, markerHigh, markerLow, buffer) if (string !== null) { - return string; + return string } - const list = this._unpackList(marker, markerHigh, markerLow, buffer); + const list = this._unpackList(marker, markerHigh, markerLow, buffer) if (list !== null) { - return list; + return list } - const byteArray = this._unpackByteArray(marker, buffer); + const byteArray = this._unpackByteArray(marker, buffer) if (byteArray !== null) { - return byteArray; + return byteArray } - const map = this._unpackMap(marker, markerHigh, markerLow, buffer); + const map = this._unpackMap(marker, markerHigh, markerLow, buffer) if (map !== null) { - return map; + return map } - const struct = this._unpackStruct(marker, markerHigh, markerLow, buffer); + const struct = this._unpackStruct(marker, markerHigh, markerLow, buffer) if (struct !== null) { - return struct; + return struct } - throw newError('Unknown packed value with marker ' + marker.toString(16)); + throw newError('Unknown packed value with marker ' + marker.toString(16)) } - unpackInteger(buffer) { - const marker = buffer.readUInt8(); - const result = this._unpackInteger(marker, buffer); + unpackInteger (buffer) { + const marker = buffer.readUInt8() + const result = this._unpackInteger(marker, buffer) if (result == null) { - throw newError('Unable to unpack integer value with marker ' + marker.toString(16)); + throw newError( + 'Unable to unpack integer value with marker ' + marker.toString(16) + ) } - return result; + return result } - _unpackBoolean(marker) { - if (marker == TRUE) { - return true; - } else if (marker == FALSE) { - return false; + _unpackBoolean (marker) { + if (marker === TRUE) { + return true + } else if (marker === FALSE) { + return false } else { - return null; + return null } } - _unpackNumberOrInteger(marker, buffer) { - if (marker == FLOAT_64) { - return buffer.readFloat64(); + _unpackNumberOrInteger (marker, buffer) { + if (marker === FLOAT_64) { + return buffer.readFloat64() } else { - return this._unpackInteger(marker, buffer); + return this._unpackInteger(marker, buffer) } } - _unpackInteger(marker, buffer) { + _unpackInteger (marker, buffer) { if (marker >= 0 && marker < 128) { - return int(marker); + return int(marker) } else if (marker >= 240 && marker < 256) { - return int(marker - 256); - } else if (marker == INT_8) { - return int(buffer.readInt8()); - } else if (marker == INT_16) { - return int(buffer.readInt16()); - } else if (marker == INT_32) { - let b = buffer.readInt32(); - return int(b); - } else if (marker == INT_64) { - const high = buffer.readInt32(); - const low = buffer.readInt32(); - return new Integer(low, high); + return int(marker - 256) + } else if (marker === INT_8) { + return int(buffer.readInt8()) + } else if (marker === INT_16) { + return int(buffer.readInt16()) + } else if (marker === INT_32) { + let b = buffer.readInt32() + return int(b) + } else if (marker === INT_64) { + const high = buffer.readInt32() + const low = buffer.readInt32() + return new Integer(low, high) } else { - return null; + return null } } - _unpackString(marker, markerHigh, markerLow, buffer) { - if (markerHigh == TINY_STRING) { - return utf8.decode(buffer, markerLow); - } else if (marker == STRING_8) { - return utf8.decode(buffer, buffer.readUInt8()); - } else if (marker == STRING_16) { - return utf8.decode(buffer, buffer.readUInt16()); - } else if (marker == STRING_32) { - return utf8.decode(buffer, buffer.readUInt32()); + _unpackString (marker, markerHigh, markerLow, buffer) { + if (markerHigh === TINY_STRING) { + return utf8.decode(buffer, markerLow) + } else if (marker === STRING_8) { + return utf8.decode(buffer, buffer.readUInt8()) + } else if (marker === STRING_16) { + return utf8.decode(buffer, buffer.readUInt16()) + } else if (marker === STRING_32) { + return utf8.decode(buffer, buffer.readUInt32()) } else { - return null; + return null } } - _unpackList(marker, markerHigh, markerLow, buffer) { - if (markerHigh == TINY_LIST) { - return this._unpackListWithSize(markerLow, buffer); - } else if (marker == LIST_8) { - return this._unpackListWithSize(buffer.readUInt8(), buffer); - } else if (marker == LIST_16) { - return this._unpackListWithSize(buffer.readUInt16(), buffer); - } else if (marker == LIST_32) { - return this._unpackListWithSize(buffer.readUInt32(), buffer); + _unpackList (marker, markerHigh, markerLow, buffer) { + if (markerHigh === TINY_LIST) { + return this._unpackListWithSize(markerLow, buffer) + } else if (marker === LIST_8) { + return this._unpackListWithSize(buffer.readUInt8(), buffer) + } else if (marker === LIST_16) { + return this._unpackListWithSize(buffer.readUInt16(), buffer) + } else if (marker === LIST_32) { + return this._unpackListWithSize(buffer.readUInt32(), buffer) } else { - return null; + return null } } - _unpackListWithSize(size, buffer) { - let value = []; + _unpackListWithSize (size, buffer) { + let value = [] for (let i = 0; i < size; i++) { - value.push(this.unpack(buffer)); + value.push(this.unpack(buffer)) } - return value; + return value } - _unpackByteArray(marker, buffer) { - if (marker == BYTES_8) { - return this._unpackByteArrayWithSize(buffer.readUInt8(), buffer); - } else if (marker == BYTES_16) { - return this._unpackByteArrayWithSize(buffer.readUInt16(), buffer); - } else if (marker == BYTES_32) { - return this._unpackByteArrayWithSize(buffer.readUInt32(), buffer); + _unpackByteArray (marker, buffer) { + if (marker === BYTES_8) { + return this._unpackByteArrayWithSize(buffer.readUInt8(), buffer) + } else if (marker === BYTES_16) { + return this._unpackByteArrayWithSize(buffer.readUInt16(), buffer) + } else if (marker === BYTES_32) { + return this._unpackByteArrayWithSize(buffer.readUInt32(), buffer) } else { - return null; + return null } } - _unpackByteArrayWithSize(size, buffer) { - const value = new Int8Array(size); + _unpackByteArrayWithSize (size, buffer) { + const value = new Int8Array(size) for (let i = 0; i < size; i++) { - value[i] = buffer.readInt8(); + value[i] = buffer.readInt8() } - return value; + return value } - _unpackMap(marker, markerHigh, markerLow, buffer) { - if (markerHigh == TINY_MAP) { - return this._unpackMapWithSize(markerLow, buffer); - } else if (marker == MAP_8) { - return this._unpackMapWithSize(buffer.readUInt8(), buffer); - } else if (marker == MAP_16) { - return this._unpackMapWithSize(buffer.readUInt16(), buffer); - } else if (marker == MAP_32) { - return this._unpackMapWithSize(buffer.readUInt32(), buffer); + _unpackMap (marker, markerHigh, markerLow, buffer) { + if (markerHigh === TINY_MAP) { + return this._unpackMapWithSize(markerLow, buffer) + } else if (marker === MAP_8) { + return this._unpackMapWithSize(buffer.readUInt8(), buffer) + } else if (marker === MAP_16) { + return this._unpackMapWithSize(buffer.readUInt16(), buffer) + } else if (marker === MAP_32) { + return this._unpackMapWithSize(buffer.readUInt32(), buffer) } else { - return null; + return null } } - _unpackMapWithSize(size, buffer) { - let value = {}; + _unpackMapWithSize (size, buffer) { + let value = {} for (let i = 0; i < size; i++) { - let key = this.unpack(buffer); - value[key] = this.unpack(buffer); + let key = this.unpack(buffer) + value[key] = this.unpack(buffer) } - return value; + return value } - _unpackStruct(marker, markerHigh, markerLow, buffer) { - if (markerHigh == TINY_STRUCT) { - return this._unpackStructWithSize(markerLow, buffer); - } else if (marker == STRUCT_8) { - return this._unpackStructWithSize(buffer.readUInt8(), buffer); - } else if (marker == STRUCT_16) { - return this._unpackStructWithSize(buffer.readUInt16(), buffer); + _unpackStruct (marker, markerHigh, markerLow, buffer) { + if (markerHigh === TINY_STRUCT) { + return this._unpackStructWithSize(markerLow, buffer) + } else if (marker === STRUCT_8) { + return this._unpackStructWithSize(buffer.readUInt8(), buffer) + } else if (marker === STRUCT_16) { + return this._unpackStructWithSize(buffer.readUInt16(), buffer) } else { - return null; + return null } } - _unpackStructWithSize(structSize, buffer) { - const signature = buffer.readUInt8(); - if (signature == NODE) { - return this._unpackNode(structSize, buffer); - } else if (signature == RELATIONSHIP) { - return this._unpackRelationship(structSize, buffer); - } else if (signature == UNBOUND_RELATIONSHIP) { - return this._unpackUnboundRelationship(structSize, buffer); - } else if (signature == PATH) { - return this._unpackPath(structSize, buffer); + _unpackStructWithSize (structSize, buffer) { + const signature = buffer.readUInt8() + if (signature === NODE) { + return this._unpackNode(structSize, buffer) + } else if (signature === RELATIONSHIP) { + return this._unpackRelationship(structSize, buffer) + } else if (signature === UNBOUND_RELATIONSHIP) { + return this._unpackUnboundRelationship(structSize, buffer) + } else if (signature === PATH) { + return this._unpackPath(structSize, buffer) } else { - return this._unpackUnknownStruct(signature, structSize, buffer); + return this._unpackUnknownStruct(signature, structSize, buffer) } } - _unpackNode(structSize, buffer) { - this._verifyStructSize('Node', NODE_STRUCT_SIZE, structSize); + _unpackNode (structSize, buffer) { + this._verifyStructSize('Node', NODE_STRUCT_SIZE, structSize) return new Node( this.unpack(buffer), // Identity this.unpack(buffer), // Labels - this.unpack(buffer) // Properties - ); + this.unpack(buffer) // Properties + ) } - _unpackRelationship(structSize, buffer) { - this._verifyStructSize('Relationship', RELATIONSHIP_STRUCT_SIZE, structSize); + _unpackRelationship (structSize, buffer) { + this._verifyStructSize('Relationship', RELATIONSHIP_STRUCT_SIZE, structSize) return new Relationship( this.unpack(buffer), // Identity this.unpack(buffer), // Start Node Identity this.unpack(buffer), // End Node Identity this.unpack(buffer), // Type - this.unpack(buffer) // Properties - ); + this.unpack(buffer) // Properties + ) } - _unpackUnboundRelationship(structSize, buffer) { - this._verifyStructSize('UnboundRelationship', UNBOUND_RELATIONSHIP_STRUCT_SIZE, structSize); + _unpackUnboundRelationship (structSize, buffer) { + this._verifyStructSize( + 'UnboundRelationship', + UNBOUND_RELATIONSHIP_STRUCT_SIZE, + structSize + ) return new UnboundRelationship( this.unpack(buffer), // Identity this.unpack(buffer), // Type - this.unpack(buffer) // Properties - ); + this.unpack(buffer) // Properties + ) } - _unpackPath(structSize, buffer) { - this._verifyStructSize('Path', PATH_STRUCT_SIZE, structSize); + _unpackPath (structSize, buffer) { + this._verifyStructSize('Path', PATH_STRUCT_SIZE, structSize) - const nodes = this.unpack(buffer); - const rels = this.unpack(buffer); - const sequence = this.unpack(buffer); + const nodes = this.unpack(buffer) + const rels = this.unpack(buffer) + const sequence = this.unpack(buffer) - const segments = []; - let prevNode = nodes[0]; + const segments = [] + let prevNode = nodes[0] for (let i = 0; i < sequence.length; i += 2) { - const nextNode = nodes[sequence[i + 1]]; - let relIndex = sequence[i]; - let rel; + const nextNode = nodes[sequence[i + 1]] + let relIndex = sequence[i] + let rel if (relIndex > 0) { - rel = rels[relIndex - 1]; + rel = rels[relIndex - 1] if (rel instanceof UnboundRelationship) { // To avoid duplication, relationships in a path do not contain // information about their start and end nodes, that's instead // inferred from the path sequence. This is us inferring (and, // for performance reasons remembering) the start/end of a rel. - rels[relIndex - 1] = rel = rel.bind(prevNode.identity, nextNode.identity); + rels[relIndex - 1] = rel = rel.bind( + prevNode.identity, + nextNode.identity + ) } } else { - rel = rels[-relIndex - 1]; + rel = rels[-relIndex - 1] if (rel instanceof UnboundRelationship) { // See above - rels[-relIndex - 1] = rel = rel.bind(nextNode.identity, prevNode.identity); + rels[-relIndex - 1] = rel = rel.bind( + nextNode.identity, + prevNode.identity + ) } } // Done hydrating one path segment. - segments.push(new PathSegment(prevNode, rel, nextNode)); - prevNode = nextNode; + segments.push(new PathSegment(prevNode, rel, nextNode)) + prevNode = nextNode } - return new Path(nodes[0], nodes[nodes.length - 1], segments); + return new Path(nodes[0], nodes[nodes.length - 1], segments) } - _unpackUnknownStruct(signature, structSize, buffer) { - const result = new Structure(signature, []); + _unpackUnknownStruct (signature, structSize, buffer) { + const result = new Structure(signature, []) for (let i = 0; i < structSize; i++) { - result.fields.push(this.unpack(buffer)); + result.fields.push(this.unpack(buffer)) } - return result; + return result } - _verifyStructSize(structName, expectedSize, actualSize) { + _verifyStructSize (structName, expectedSize, actualSize) { if (expectedSize !== actualSize) { - throw newError(`Wrong struct size for ${structName}, expected ${expectedSize} but was ${actualSize}`, PROTOCOL_ERROR); + throw newError( + `Wrong struct size for ${structName}, expected ${expectedSize} but was ${actualSize}`, + PROTOCOL_ERROR + ) } } } -function isIterable(obj) { +function isIterable (obj) { if (obj == null) { - return false; + return false } - return typeof obj[Symbol.iterator] === 'function'; + return typeof obj[Symbol.iterator] === 'function' } -export { - Packer, - Unpacker, - Structure -}; +export { Packer, Unpacker, Structure } diff --git a/src/v1/internal/packstream-v2.js b/src/v1/internal/packstream-v2.js index 341927c59..fe1b61727 100644 --- a/src/v1/internal/packstream-v2.js +++ b/src/v1/internal/packstream-v2.js @@ -17,10 +17,20 @@ * limitations under the License. */ -import * as v1 from './packstream-v1'; -import {isPoint, Point} from '../spatial-types'; -import {Date, DateTime, Duration, isDate, isDateTime, isDuration, isLocalDateTime, isLocalTime, isTime, Time} from '../temporal-types'; -import {int, isInt} from '../integer'; +import * as v1 from './packstream-v1' +import { isPoint, Point } from '../spatial-types' +import { + DateTime, + Duration, + isDate, + isDateTime, + isDuration, + isLocalDateTime, + isLocalTime, + isTime, + Time +} from '../temporal-types' +import { int, isInt } from '../integer' import { dateToEpochDay, epochDayToDate, @@ -28,102 +38,116 @@ import { localDateTimeToEpochSecond, localTimeToNanoOfDay, nanoOfDayToLocalTime -} from '../internal/temporal-util'; +} from '../internal/temporal-util' -const POINT_2D = 0x58; -const POINT_2D_STRUCT_SIZE = 3; +const POINT_2D = 0x58 +const POINT_2D_STRUCT_SIZE = 3 -const POINT_3D = 0x59; -const POINT_3D_STRUCT_SIZE = 4; +const POINT_3D = 0x59 +const POINT_3D_STRUCT_SIZE = 4 -const DURATION = 0x45; -const DURATION_STRUCT_SIZE = 4; +const DURATION = 0x45 +const DURATION_STRUCT_SIZE = 4 -const LOCAL_TIME = 0x74; -const LOCAL_TIME_STRUCT_SIZE = 1; +const LOCAL_TIME = 0x74 +const LOCAL_TIME_STRUCT_SIZE = 1 -const TIME = 0x54; -const TIME_STRUCT_SIZE = 2; +const TIME = 0x54 +const TIME_STRUCT_SIZE = 2 -const DATE = 0x44; -const DATE_STRUCT_SIZE = 1; +const DATE = 0x44 +const DATE_STRUCT_SIZE = 1 -const LOCAL_DATE_TIME = 0x64; -const LOCAL_DATE_TIME_STRUCT_SIZE = 2; +const LOCAL_DATE_TIME = 0x64 +const LOCAL_DATE_TIME_STRUCT_SIZE = 2 -const DATE_TIME_WITH_ZONE_OFFSET = 0x46; -const DATE_TIME_WITH_ZONE_OFFSET_STRUCT_SIZE = 3; +const DATE_TIME_WITH_ZONE_OFFSET = 0x46 +const DATE_TIME_WITH_ZONE_OFFSET_STRUCT_SIZE = 3 -const DATE_TIME_WITH_ZONE_ID = 0x66; -const DATE_TIME_WITH_ZONE_ID_STRUCT_SIZE = 3; +const DATE_TIME_WITH_ZONE_ID = 0x66 +const DATE_TIME_WITH_ZONE_ID_STRUCT_SIZE = 3 export class Packer extends v1.Packer { - - /** - * @constructor - * @param {Chunker} chunker the chunker backed by a network channel. - */ - constructor(chunker) { - super(chunker); + disableByteArrays () { + throw new Error('Bolt V2 should always support byte arrays') } - disableByteArrays() { - throw new Error('Bolt V2 should always support byte arrays'); - } - - packable(obj, onError) { + packable (obj, onError) { if (isPoint(obj)) { - return () => packPoint(obj, this, onError); + return () => packPoint(obj, this, onError) } else if (isDuration(obj)) { - return () => packDuration(obj, this, onError); + return () => packDuration(obj, this, onError) } else if (isLocalTime(obj)) { - return () => packLocalTime(obj, this, onError); + return () => packLocalTime(obj, this, onError) } else if (isTime(obj)) { - return () => packTime(obj, this, onError); + return () => packTime(obj, this, onError) } else if (isDate(obj)) { - return () => packDate(obj, this, onError); + return () => packDate(obj, this, onError) } else if (isLocalDateTime(obj)) { - return () => packLocalDateTime(obj, this, onError); + return () => packLocalDateTime(obj, this, onError) } else if (isDateTime(obj)) { - return () => packDateTime(obj, this, onError); + return () => packDateTime(obj, this, onError) } else { - return super.packable(obj, onError); + return super.packable(obj, onError) } } } export class Unpacker extends v1.Unpacker { - /** * @constructor * @param {boolean} disableLosslessIntegers if this unpacker should convert all received integers to native JS numbers. */ - constructor(disableLosslessIntegers = false) { - super(disableLosslessIntegers); + constructor (disableLosslessIntegers = false) { + super(disableLosslessIntegers) } - - _unpackUnknownStruct(signature, structSize, buffer) { - if (signature == POINT_2D) { - return unpackPoint2D(this, structSize, buffer); - } else if (signature == POINT_3D) { - return unpackPoint3D(this, structSize, buffer); - } else if (signature == DURATION) { - return unpackDuration(this, structSize, buffer); - } else if (signature == LOCAL_TIME) { - return unpackLocalTime(this, structSize, buffer, this._disableLosslessIntegers); - } else if (signature == TIME) { - return unpackTime(this, structSize, buffer, this._disableLosslessIntegers); - } else if (signature == DATE) { - return unpackDate(this, structSize, buffer, this._disableLosslessIntegers); - } else if (signature == LOCAL_DATE_TIME) { - return unpackLocalDateTime(this, structSize, buffer, this._disableLosslessIntegers); - } else if (signature == DATE_TIME_WITH_ZONE_OFFSET) { - return unpackDateTimeWithZoneOffset(this, structSize, buffer, this._disableLosslessIntegers); - } else if (signature == DATE_TIME_WITH_ZONE_ID) { - return unpackDateTimeWithZoneId(this, structSize, buffer, this._disableLosslessIntegers); + _unpackUnknownStruct (signature, structSize, buffer) { + if (signature === POINT_2D) { + return unpackPoint2D(this, structSize, buffer) + } else if (signature === POINT_3D) { + return unpackPoint3D(this, structSize, buffer) + } else if (signature === DURATION) { + return unpackDuration(this, structSize, buffer) + } else if (signature === LOCAL_TIME) { + return unpackLocalTime( + this, + structSize, + buffer, + this._disableLosslessIntegers + ) + } else if (signature === TIME) { + return unpackTime(this, structSize, buffer, this._disableLosslessIntegers) + } else if (signature === DATE) { + return unpackDate(this, structSize, buffer, this._disableLosslessIntegers) + } else if (signature === LOCAL_DATE_TIME) { + return unpackLocalDateTime( + this, + structSize, + buffer, + this._disableLosslessIntegers + ) + } else if (signature === DATE_TIME_WITH_ZONE_OFFSET) { + return unpackDateTimeWithZoneOffset( + this, + structSize, + buffer, + this._disableLosslessIntegers + ) + } else if (signature === DATE_TIME_WITH_ZONE_ID) { + return unpackDateTimeWithZoneId( + this, + structSize, + buffer, + this._disableLosslessIntegers + ) } else { - return super._unpackUnknownStruct(signature, structSize, buffer, this._disableLosslessIntegers); + return super._unpackUnknownStruct( + signature, + structSize, + buffer, + this._disableLosslessIntegers + ) } } } @@ -134,12 +158,12 @@ export class Unpacker extends v1.Unpacker { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packPoint(point, packer, onError) { - const is2DPoint = point.z === null || point.z === undefined; +function packPoint (point, packer, onError) { + const is2DPoint = point.z === null || point.z === undefined if (is2DPoint) { - packPoint2D(point, packer, onError); + packPoint2D(point, packer, onError) } else { - packPoint3D(point, packer, onError); + packPoint3D(point, packer, onError) } } @@ -149,13 +173,13 @@ function packPoint(point, packer, onError) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packPoint2D(point, packer, onError) { +function packPoint2D (point, packer, onError) { const packableStructFields = [ packer.packable(int(point.srid), onError), packer.packable(point.x, onError), packer.packable(point.y, onError) - ]; - packer.packStruct(POINT_2D, packableStructFields, onError); + ] + packer.packStruct(POINT_2D, packableStructFields, onError) } /** @@ -164,14 +188,14 @@ function packPoint2D(point, packer, onError) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packPoint3D(point, packer, onError) { +function packPoint3D (point, packer, onError) { const packableStructFields = [ packer.packable(int(point.srid), onError), packer.packable(point.x, onError), packer.packable(point.y, onError), packer.packable(point.z, onError) - ]; - packer.packStruct(POINT_3D, packableStructFields, onError); + ] + packer.packStruct(POINT_3D, packableStructFields, onError) } /** @@ -181,15 +205,15 @@ function packPoint3D(point, packer, onError) { * @param {BaseBuffer} buffer the buffer to unpack from. * @return {Point} the unpacked 2D point value. */ -function unpackPoint2D(unpacker, structSize, buffer) { - unpacker._verifyStructSize('Point2D', POINT_2D_STRUCT_SIZE, structSize); +function unpackPoint2D (unpacker, structSize, buffer) { + unpacker._verifyStructSize('Point2D', POINT_2D_STRUCT_SIZE, structSize) return new Point( unpacker.unpack(buffer), // srid unpacker.unpack(buffer), // x unpacker.unpack(buffer), // y - undefined // z - ); + undefined // z + ) } /** @@ -199,15 +223,15 @@ function unpackPoint2D(unpacker, structSize, buffer) { * @param {BaseBuffer} buffer the buffer to unpack from. * @return {Point} the unpacked 3D point value. */ -function unpackPoint3D(unpacker, structSize, buffer) { - unpacker._verifyStructSize('Point3D', POINT_3D_STRUCT_SIZE, structSize); +function unpackPoint3D (unpacker, structSize, buffer) { + unpacker._verifyStructSize('Point3D', POINT_3D_STRUCT_SIZE, structSize) return new Point( unpacker.unpack(buffer), // srid unpacker.unpack(buffer), // x unpacker.unpack(buffer), // y - unpacker.unpack(buffer) // z - ); + unpacker.unpack(buffer) // z + ) } /** @@ -216,19 +240,19 @@ function unpackPoint3D(unpacker, structSize, buffer) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packDuration(value, packer, onError) { - const months = int(value.months); - const days = int(value.days); - const seconds = int(value.seconds); - const nanoseconds = int(value.nanoseconds); +function packDuration (value, packer, onError) { + const months = int(value.months) + const days = int(value.days) + const seconds = int(value.seconds) + const nanoseconds = int(value.nanoseconds) const packableStructFields = [ packer.packable(months, onError), packer.packable(days, onError), packer.packable(seconds, onError), - packer.packable(nanoseconds, onError), - ]; - packer.packStruct(DURATION, packableStructFields, onError); + packer.packable(nanoseconds, onError) + ] + packer.packStruct(DURATION, packableStructFields, onError) } /** @@ -238,15 +262,15 @@ function packDuration(value, packer, onError) { * @param {BaseBuffer} buffer the buffer to unpack from. * @return {Duration} the unpacked duration value. */ -function unpackDuration(unpacker, structSize, buffer) { - unpacker._verifyStructSize('Duration', DURATION_STRUCT_SIZE, structSize); +function unpackDuration (unpacker, structSize, buffer) { + unpacker._verifyStructSize('Duration', DURATION_STRUCT_SIZE, structSize) - const months = unpacker.unpack(buffer); - const days = unpacker.unpack(buffer); - const seconds = unpacker.unpack(buffer); - const nanoseconds = unpacker.unpack(buffer); + const months = unpacker.unpack(buffer) + const days = unpacker.unpack(buffer) + const seconds = unpacker.unpack(buffer) + const nanoseconds = unpacker.unpack(buffer) - return new Duration(months, days, seconds, nanoseconds); + return new Duration(months, days, seconds, nanoseconds) } /** @@ -255,13 +279,16 @@ function unpackDuration(unpacker, structSize, buffer) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packLocalTime(value, packer, onError) { - const nanoOfDay = localTimeToNanoOfDay(value.hour, value.minute, value.second, value.nanosecond); - - const packableStructFields = [ - packer.packable(nanoOfDay, onError) - ]; - packer.packStruct(LOCAL_TIME, packableStructFields, onError); +function packLocalTime (value, packer, onError) { + const nanoOfDay = localTimeToNanoOfDay( + value.hour, + value.minute, + value.second, + value.nanosecond + ) + + const packableStructFields = [packer.packable(nanoOfDay, onError)] + packer.packStruct(LOCAL_TIME, packableStructFields, onError) } /** @@ -272,12 +299,17 @@ function packLocalTime(value, packer, onError) { * @param {boolean} disableLosslessIntegers if integer properties in the result local time should be native JS numbers. * @return {LocalTime} the unpacked local time value. */ -function unpackLocalTime(unpacker, structSize, buffer, disableLosslessIntegers) { - unpacker._verifyStructSize('LocalTime', LOCAL_TIME_STRUCT_SIZE, structSize); - - const nanoOfDay = unpacker.unpackInteger(buffer); - const result = nanoOfDayToLocalTime(nanoOfDay); - return convertIntegerPropsIfNeeded(result, disableLosslessIntegers); +function unpackLocalTime ( + unpacker, + structSize, + buffer, + disableLosslessIntegers +) { + unpacker._verifyStructSize('LocalTime', LOCAL_TIME_STRUCT_SIZE, structSize) + + const nanoOfDay = unpacker.unpackInteger(buffer) + const result = nanoOfDayToLocalTime(nanoOfDay) + return convertIntegerPropsIfNeeded(result, disableLosslessIntegers) } /** @@ -286,15 +318,20 @@ function unpackLocalTime(unpacker, structSize, buffer, disableLosslessIntegers) * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packTime(value, packer, onError) { - const nanoOfDay = localTimeToNanoOfDay(value.hour, value.minute, value.second, value.nanosecond); - const offsetSeconds = int(value.timeZoneOffsetSeconds); +function packTime (value, packer, onError) { + const nanoOfDay = localTimeToNanoOfDay( + value.hour, + value.minute, + value.second, + value.nanosecond + ) + const offsetSeconds = int(value.timeZoneOffsetSeconds) const packableStructFields = [ packer.packable(nanoOfDay, onError), packer.packable(offsetSeconds, onError) - ]; - packer.packStruct(TIME, packableStructFields, onError); + ] + packer.packStruct(TIME, packableStructFields, onError) } /** @@ -305,15 +342,21 @@ function packTime(value, packer, onError) { * @param {boolean} disableLosslessIntegers if integer properties in the result time should be native JS numbers. * @return {Time} the unpacked time value. */ -function unpackTime(unpacker, structSize, buffer, disableLosslessIntegers) { - unpacker._verifyStructSize('Time', TIME_STRUCT_SIZE, structSize); - - const nanoOfDay = unpacker.unpackInteger(buffer); - const offsetSeconds = unpacker.unpackInteger(buffer); - - const localTime = nanoOfDayToLocalTime(nanoOfDay); - const result = new Time(localTime.hour, localTime.minute, localTime.second, localTime.nanosecond, offsetSeconds); - return convertIntegerPropsIfNeeded(result, disableLosslessIntegers); +function unpackTime (unpacker, structSize, buffer, disableLosslessIntegers) { + unpacker._verifyStructSize('Time', TIME_STRUCT_SIZE, structSize) + + const nanoOfDay = unpacker.unpackInteger(buffer) + const offsetSeconds = unpacker.unpackInteger(buffer) + + const localTime = nanoOfDayToLocalTime(nanoOfDay) + const result = new Time( + localTime.hour, + localTime.minute, + localTime.second, + localTime.nanosecond, + offsetSeconds + ) + return convertIntegerPropsIfNeeded(result, disableLosslessIntegers) } /** @@ -322,13 +365,11 @@ function unpackTime(unpacker, structSize, buffer, disableLosslessIntegers) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packDate(value, packer, onError) { - const epochDay = dateToEpochDay(value.year, value.month, value.day); +function packDate (value, packer, onError) { + const epochDay = dateToEpochDay(value.year, value.month, value.day) - const packableStructFields = [ - packer.packable(epochDay, onError) - ]; - packer.packStruct(DATE, packableStructFields, onError); + const packableStructFields = [packer.packable(epochDay, onError)] + packer.packStruct(DATE, packableStructFields, onError) } /** @@ -339,12 +380,12 @@ function packDate(value, packer, onError) { * @param {boolean} disableLosslessIntegers if integer properties in the result date should be native JS numbers. * @return {Date} the unpacked neo4j date value. */ -function unpackDate(unpacker, structSize, buffer, disableLosslessIntegers) { - unpacker._verifyStructSize('Date', DATE_STRUCT_SIZE, structSize); +function unpackDate (unpacker, structSize, buffer, disableLosslessIntegers) { + unpacker._verifyStructSize('Date', DATE_STRUCT_SIZE, structSize) - const epochDay = unpacker.unpackInteger(buffer); - const result = epochDayToDate(epochDay); - return convertIntegerPropsIfNeeded(result, disableLosslessIntegers); + const epochDay = unpacker.unpackInteger(buffer) + const result = epochDayToDate(epochDay) + return convertIntegerPropsIfNeeded(result, disableLosslessIntegers) } /** @@ -353,15 +394,23 @@ function unpackDate(unpacker, structSize, buffer, disableLosslessIntegers) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packLocalDateTime(value, packer, onError) { - const epochSecond = localDateTimeToEpochSecond(value.year, value.month, value.day, value.hour, value.minute, value.second, value.nanosecond); - const nano = int(value.nanosecond); +function packLocalDateTime (value, packer, onError) { + const epochSecond = localDateTimeToEpochSecond( + value.year, + value.month, + value.day, + value.hour, + value.minute, + value.second, + value.nanosecond + ) + const nano = int(value.nanosecond) const packableStructFields = [ packer.packable(epochSecond, onError), packer.packable(nano, onError) - ]; - packer.packStruct(LOCAL_DATE_TIME, packableStructFields, onError); + ] + packer.packStruct(LOCAL_DATE_TIME, packableStructFields, onError) } /** @@ -372,13 +421,22 @@ function packLocalDateTime(value, packer, onError) { * @param {boolean} disableLosslessIntegers if integer properties in the result local date-time should be native JS numbers. * @return {LocalDateTime} the unpacked local date time value. */ -function unpackLocalDateTime(unpacker, structSize, buffer, disableLosslessIntegers) { - unpacker._verifyStructSize('LocalDateTime', LOCAL_DATE_TIME_STRUCT_SIZE, structSize); - - const epochSecond = unpacker.unpackInteger(buffer); - const nano = unpacker.unpackInteger(buffer); - const result = epochSecondAndNanoToLocalDateTime(epochSecond, nano); - return convertIntegerPropsIfNeeded(result, disableLosslessIntegers); +function unpackLocalDateTime ( + unpacker, + structSize, + buffer, + disableLosslessIntegers +) { + unpacker._verifyStructSize( + 'LocalDateTime', + LOCAL_DATE_TIME_STRUCT_SIZE, + structSize + ) + + const epochSecond = unpacker.unpackInteger(buffer) + const nano = unpacker.unpackInteger(buffer) + const result = epochSecondAndNanoToLocalDateTime(epochSecond, nano) + return convertIntegerPropsIfNeeded(result, disableLosslessIntegers) } /** @@ -387,11 +445,11 @@ function unpackLocalDateTime(unpacker, structSize, buffer, disableLosslessIntege * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packDateTime(value, packer, onError) { +function packDateTime (value, packer, onError) { if (value.timeZoneId) { - packDateTimeWithZoneId(value, packer, onError); + packDateTimeWithZoneId(value, packer, onError) } else { - packDateTimeWithZoneOffset(value, packer, onError); + packDateTimeWithZoneOffset(value, packer, onError) } } @@ -401,17 +459,25 @@ function packDateTime(value, packer, onError) { * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packDateTimeWithZoneOffset(value, packer, onError) { - const epochSecond = localDateTimeToEpochSecond(value.year, value.month, value.day, value.hour, value.minute, value.second, value.nanosecond); - const nano = int(value.nanosecond); - const timeZoneOffsetSeconds = int(value.timeZoneOffsetSeconds); +function packDateTimeWithZoneOffset (value, packer, onError) { + const epochSecond = localDateTimeToEpochSecond( + value.year, + value.month, + value.day, + value.hour, + value.minute, + value.second, + value.nanosecond + ) + const nano = int(value.nanosecond) + const timeZoneOffsetSeconds = int(value.timeZoneOffsetSeconds) const packableStructFields = [ packer.packable(epochSecond, onError), packer.packable(nano, onError), packer.packable(timeZoneOffsetSeconds, onError) - ]; - packer.packStruct(DATE_TIME_WITH_ZONE_OFFSET, packableStructFields, onError); + ] + packer.packStruct(DATE_TIME_WITH_ZONE_OFFSET, packableStructFields, onError) } /** @@ -422,17 +488,35 @@ function packDateTimeWithZoneOffset(value, packer, onError) { * @param {boolean} disableLosslessIntegers if integer properties in the result date-time should be native JS numbers. * @return {DateTime} the unpacked date time with zone offset value. */ -function unpackDateTimeWithZoneOffset(unpacker, structSize, buffer, disableLosslessIntegers) { - unpacker._verifyStructSize('DateTimeWithZoneOffset', DATE_TIME_WITH_ZONE_OFFSET_STRUCT_SIZE, structSize); - - const epochSecond = unpacker.unpackInteger(buffer); - const nano = unpacker.unpackInteger(buffer); - const timeZoneOffsetSeconds = unpacker.unpackInteger(buffer); - - const localDateTime = epochSecondAndNanoToLocalDateTime(epochSecond, nano); - const result = new DateTime(localDateTime.year, localDateTime.month, localDateTime.day, - localDateTime.hour, localDateTime.minute, localDateTime.second, localDateTime.nanosecond, timeZoneOffsetSeconds, null); - return convertIntegerPropsIfNeeded(result, disableLosslessIntegers); +function unpackDateTimeWithZoneOffset ( + unpacker, + structSize, + buffer, + disableLosslessIntegers +) { + unpacker._verifyStructSize( + 'DateTimeWithZoneOffset', + DATE_TIME_WITH_ZONE_OFFSET_STRUCT_SIZE, + structSize + ) + + const epochSecond = unpacker.unpackInteger(buffer) + const nano = unpacker.unpackInteger(buffer) + const timeZoneOffsetSeconds = unpacker.unpackInteger(buffer) + + const localDateTime = epochSecondAndNanoToLocalDateTime(epochSecond, nano) + const result = new DateTime( + localDateTime.year, + localDateTime.month, + localDateTime.day, + localDateTime.hour, + localDateTime.minute, + localDateTime.second, + localDateTime.nanosecond, + timeZoneOffsetSeconds, + null + ) + return convertIntegerPropsIfNeeded(result, disableLosslessIntegers) } /** @@ -441,17 +525,25 @@ function unpackDateTimeWithZoneOffset(unpacker, structSize, buffer, disableLossl * @param {Packer} packer the packer to use. * @param {function} onError the error callback. */ -function packDateTimeWithZoneId(value, packer, onError) { - const epochSecond = localDateTimeToEpochSecond(value.year, value.month, value.day, value.hour, value.minute, value.second, value.nanosecond); - const nano = int(value.nanosecond); - const timeZoneId = value.timeZoneId; +function packDateTimeWithZoneId (value, packer, onError) { + const epochSecond = localDateTimeToEpochSecond( + value.year, + value.month, + value.day, + value.hour, + value.minute, + value.second, + value.nanosecond + ) + const nano = int(value.nanosecond) + const timeZoneId = value.timeZoneId const packableStructFields = [ packer.packable(epochSecond, onError), packer.packable(nano, onError), packer.packable(timeZoneId, onError) - ]; - packer.packStruct(DATE_TIME_WITH_ZONE_ID, packableStructFields, onError); + ] + packer.packStruct(DATE_TIME_WITH_ZONE_ID, packableStructFields, onError) } /** @@ -462,31 +554,49 @@ function packDateTimeWithZoneId(value, packer, onError) { * @param {boolean} disableLosslessIntegers if integer properties in the result date-time should be native JS numbers. * @return {DateTime} the unpacked date time with zone id value. */ -function unpackDateTimeWithZoneId(unpacker, structSize, buffer, disableLosslessIntegers) { - unpacker._verifyStructSize('DateTimeWithZoneId', DATE_TIME_WITH_ZONE_ID_STRUCT_SIZE, structSize); - - const epochSecond = unpacker.unpackInteger(buffer); - const nano = unpacker.unpackInteger(buffer); - const timeZoneId = unpacker.unpack(buffer); - - const localDateTime = epochSecondAndNanoToLocalDateTime(epochSecond, nano); - const result = new DateTime(localDateTime.year, localDateTime.month, localDateTime.day, - localDateTime.hour, localDateTime.minute, localDateTime.second, localDateTime.nanosecond, null, timeZoneId); - return convertIntegerPropsIfNeeded(result, disableLosslessIntegers); +function unpackDateTimeWithZoneId ( + unpacker, + structSize, + buffer, + disableLosslessIntegers +) { + unpacker._verifyStructSize( + 'DateTimeWithZoneId', + DATE_TIME_WITH_ZONE_ID_STRUCT_SIZE, + structSize + ) + + const epochSecond = unpacker.unpackInteger(buffer) + const nano = unpacker.unpackInteger(buffer) + const timeZoneId = unpacker.unpack(buffer) + + const localDateTime = epochSecondAndNanoToLocalDateTime(epochSecond, nano) + const result = new DateTime( + localDateTime.year, + localDateTime.month, + localDateTime.day, + localDateTime.hour, + localDateTime.minute, + localDateTime.second, + localDateTime.nanosecond, + null, + timeZoneId + ) + return convertIntegerPropsIfNeeded(result, disableLosslessIntegers) } -function convertIntegerPropsIfNeeded(obj, disableLosslessIntegers) { +function convertIntegerPropsIfNeeded (obj, disableLosslessIntegers) { if (!disableLosslessIntegers) { - return obj; + return obj } - const clone = Object.create(Object.getPrototypeOf(obj)); + const clone = Object.create(Object.getPrototypeOf(obj)) for (let prop in obj) { if (obj.hasOwnProperty(prop)) { - const value = obj[prop]; - clone[prop] = isInt(value) ? value.toNumberOrInfinity() : value; + const value = obj[prop] + clone[prop] = isInt(value) ? value.toNumberOrInfinity() : value } } - Object.freeze(clone); - return clone; + Object.freeze(clone) + return clone } diff --git a/src/v1/internal/pool-config.js b/src/v1/internal/pool-config.js index 568f0831a..8ef4461f2 100644 --- a/src/v1/internal/pool-config.js +++ b/src/v1/internal/pool-config.js @@ -17,53 +17,58 @@ * limitations under the License. */ -const DEFAULT_MAX_SIZE = 100; -const DEFAULT_ACQUISITION_TIMEOUT = 60 * 1000; // 60 seconds +const DEFAULT_MAX_SIZE = 100 +const DEFAULT_ACQUISITION_TIMEOUT = 60 * 1000 // 60 seconds export default class PoolConfig { - - constructor(maxSize, acquisitionTimeout) { - this.maxSize = valueOrDefault(maxSize, DEFAULT_MAX_SIZE); - this.acquisitionTimeout = valueOrDefault(acquisitionTimeout, DEFAULT_ACQUISITION_TIMEOUT); + constructor (maxSize, acquisitionTimeout) { + this.maxSize = valueOrDefault(maxSize, DEFAULT_MAX_SIZE) + this.acquisitionTimeout = valueOrDefault( + acquisitionTimeout, + DEFAULT_ACQUISITION_TIMEOUT + ) } - static defaultConfig() { - return new PoolConfig(DEFAULT_MAX_SIZE, DEFAULT_ACQUISITION_TIMEOUT); + static defaultConfig () { + return new PoolConfig(DEFAULT_MAX_SIZE, DEFAULT_ACQUISITION_TIMEOUT) } - static fromDriverConfig(config) { - const maxIdleSizeConfigured = isConfigured(config.connectionPoolSize); - const maxSizeConfigured = isConfigured(config.maxConnectionPoolSize); + static fromDriverConfig (config) { + const maxIdleSizeConfigured = isConfigured(config.connectionPoolSize) + const maxSizeConfigured = isConfigured(config.maxConnectionPoolSize) - let maxSize; + let maxSize if (maxSizeConfigured) { // correct size setting is set - use it's value - maxSize = config.maxConnectionPoolSize; + maxSize = config.maxConnectionPoolSize } else if (maxIdleSizeConfigured) { // deprecated size setting is set - use it's value - console.warn('WARNING: neo4j-driver setting "connectionPoolSize" is deprecated, please use "maxConnectionPoolSize" instead'); - maxSize = config.connectionPoolSize; + console.warn( + 'WARNING: neo4j-driver setting "connectionPoolSize" is deprecated, please use "maxConnectionPoolSize" instead' + ) + maxSize = config.connectionPoolSize } else { - maxSize = DEFAULT_MAX_SIZE; + maxSize = DEFAULT_MAX_SIZE } - const acquisitionTimeoutConfigured = isConfigured(config.connectionAcquisitionTimeout); - const acquisitionTimeout = acquisitionTimeoutConfigured ? config.connectionAcquisitionTimeout : DEFAULT_ACQUISITION_TIMEOUT; + const acquisitionTimeoutConfigured = isConfigured( + config.connectionAcquisitionTimeout + ) + const acquisitionTimeout = acquisitionTimeoutConfigured + ? config.connectionAcquisitionTimeout + : DEFAULT_ACQUISITION_TIMEOUT - return new PoolConfig(maxSize, acquisitionTimeout); + return new PoolConfig(maxSize, acquisitionTimeout) } } -function valueOrDefault(value, defaultValue) { - return value === 0 || value ? value : defaultValue; +function valueOrDefault (value, defaultValue) { + return value === 0 || value ? value : defaultValue } -function isConfigured(value) { - return value === 0 || value; +function isConfigured (value) { + return value === 0 || value } -export { - DEFAULT_MAX_SIZE, - DEFAULT_ACQUISITION_TIMEOUT -}; +export { DEFAULT_MAX_SIZE, DEFAULT_ACQUISITION_TIMEOUT } diff --git a/src/v1/internal/pool.js b/src/v1/internal/pool.js index ee9295542..53bf5edbf 100644 --- a/src/v1/internal/pool.js +++ b/src/v1/internal/pool.js @@ -17,12 +17,11 @@ * limitations under the License. */ -import PoolConfig from './pool-config'; -import {newError} from '../error'; -import Logger from './logger'; +import PoolConfig from './pool-config' +import { newError } from '../error' +import Logger from './logger' class Pool { - /** * @param {function(function): Promise} create an allocation function that creates a promise with a new resource. It's given * a single argument, a function that will return the resource to @@ -35,18 +34,23 @@ class Pool { * @param {PoolConfig} config configuration for the new driver. * @param {Logger} log the driver logger. */ - constructor(create, destroy = (() => true), validate = (() => true), config = PoolConfig.defaultConfig(), - log = Logger.noOp()) { - this._create = create; - this._destroy = destroy; - this._validate = validate; - this._maxSize = config.maxSize; - this._acquisitionTimeout = config.acquisitionTimeout; - this._pools = {}; - this._acquireRequests = {}; - this._activeResourceCounts = {}; - this._release = this._release.bind(this); - this._log = log; + constructor ( + create, + destroy = () => true, + validate = () => true, + config = PoolConfig.defaultConfig(), + log = Logger.noOp() + ) { + this._create = create + this._destroy = destroy + this._validate = validate + this._maxSize = config.maxSize + this._acquisitionTimeout = config.acquisitionTimeout + this._pools = {} + this._acquireRequests = {} + this._activeResourceCounts = {} + this._release = this._release.bind(this) + this._log = log } /** @@ -54,76 +58,82 @@ class Pool { * @param {ServerAddress} address the address for which we're acquiring. * @return {object} resource that is ready to use. */ - acquire(address) { + acquire (address) { return this._acquire(address).then(resource => { - const key = address.asKey(); + const key = address.asKey() if (resource) { - resourceAcquired(key, this._activeResourceCounts); + resourceAcquired(key, this._activeResourceCounts) if (this._log.isDebugEnabled()) { - this._log.debug(`${resource} acquired from the pool ${key}`); + this._log.debug(`${resource} acquired from the pool ${key}`) } - return resource; + return resource } // We're out of resources and will try to acquire later on when an existing resource is released. - const allRequests = this._acquireRequests; - const requests = allRequests[key]; + const allRequests = this._acquireRequests + const requests = allRequests[key] if (!requests) { - allRequests[key] = []; + allRequests[key] = [] } return new Promise((resolve, reject) => { - let request; + let request const timeoutId = setTimeout(() => { // acquisition timeout fired // remove request from the queue of pending requests, if it's still there // request might've been taken out by the release operation - const pendingRequests = allRequests[key]; + const pendingRequests = allRequests[key] if (pendingRequests) { - allRequests[key] = pendingRequests.filter(item => item !== request); + allRequests[key] = pendingRequests.filter(item => item !== request) } if (request.isCompleted()) { // request already resolved/rejected by the release operation; nothing to do } else { // request is still pending and needs to be failed - request.reject(newError(`Connection acquisition timed out in ${this._acquisitionTimeout} ms.`)); + request.reject( + newError( + `Connection acquisition timed out in ${ + this._acquisitionTimeout + } ms.` + ) + ) } - }, this._acquisitionTimeout); + }, this._acquisitionTimeout) - request = new PendingRequest(key, resolve, reject, timeoutId, this._log); - allRequests[key].push(request); - }); - }); + request = new PendingRequest(key, resolve, reject, timeoutId, this._log) + allRequests[key].push(request) + }) + }) } /** * Destroy all idle resources for the given address. * @param {ServerAddress} address the address of the server to purge its pool. */ - purge(address) { + purge (address) { this._purgeKey(address.asKey()) } /** * Destroy all idle resources in this pool. */ - purgeAll() { - Object.keys(this._pools).forEach(key => this._purgeKey(key)); + purgeAll () { + Object.keys(this._pools).forEach(key => this._purgeKey(key)) } /** * Keep the idle resources for the provided addresses and purge the rest. */ - keepAll(addresses) { - const keysToKeep = addresses.map(a => a.asKey()); - const keysPresent = Object.keys(this._pools); - const keysToPurge = keysPresent.filter(k => keysToKeep.indexOf(k) == -1); + keepAll (addresses) { + const keysToKeep = addresses.map(a => a.asKey()) + const keysPresent = Object.keys(this._pools) + const keysToPurge = keysPresent.filter(k => keysToKeep.indexOf(k) === -1) - keysToPurge.forEach(key => this._purgeKey(key)); + keysToPurge.forEach(key => this._purgeKey(key)) } /** @@ -131,8 +141,8 @@ class Pool { * @param {ServerAddress} address the address of the server to check. * @return {boolean} `true` when pool contains entries for the given key, false otherwise. */ - has(address) { - return (address.asKey() in this._pools); + has (address) { + return address.asKey() in this._pools } /** @@ -140,87 +150,91 @@ class Pool { * @param {ServerAddress} address the address of the server to check. * @return {number} count of resources acquired by clients. */ - activeResourceCount(address) { - return this._activeResourceCounts[address.asKey()] || 0; + activeResourceCount (address) { + return this._activeResourceCounts[address.asKey()] || 0 } - _acquire(address) { - const key = address.asKey(); - let pool = this._pools[key]; + _acquire (address) { + const key = address.asKey() + let pool = this._pools[key] if (!pool) { - pool = []; - this._pools[key] = pool; + pool = [] + this._pools[key] = pool } while (pool.length) { - const resource = pool.pop(); + const resource = pool.pop() if (this._validate(resource)) { // idle resource is valid and can be acquired - return Promise.resolve(resource); + return Promise.resolve(resource) } else { - this._destroy(resource); + this._destroy(resource) } } if (this._maxSize && this.activeResourceCount(address) >= this._maxSize) { - return Promise.resolve(null); + return Promise.resolve(null) } // there exist no idle valid resources, create a new one for acquisition - return this._create(address, this._release); + return this._create(address, this._release) } - _release(address, resource) { - const key = address.asKey(); - const pool = this._pools[key]; + _release (address, resource) { + const key = address.asKey() + const pool = this._pools[key] if (pool) { // there exist idle connections for the given key if (!this._validate(resource)) { if (this._log.isDebugEnabled()) { - this._log.debug(`${resource} destroyed and can't be released to the pool ${key} because it is not functional`); + this._log.debug( + `${resource} destroyed and can't be released to the pool ${key} because it is not functional` + ) } - this._destroy(resource); + this._destroy(resource) } else { if (this._log.isDebugEnabled()) { - this._log.debug(`${resource} released to the pool ${key}`); + this._log.debug(`${resource} released to the pool ${key}`) } - pool.push(resource); + pool.push(resource) } } else { // key has been purged, don't put it back, just destroy the resource if (this._log.isDebugEnabled()) { - this._log.debug(`${resource} destroyed and can't be released to the pool ${key} because pool has been purged`); + this._log.debug( + `${resource} destroyed and can't be released to the pool ${key} because pool has been purged` + ) } - this._destroy(resource); + this._destroy(resource) } - resourceReleased(key, this._activeResourceCounts); + resourceReleased(key, this._activeResourceCounts) - this._processPendingAcquireRequests(address); + this._processPendingAcquireRequests(address) } - _purgeKey(key) { - const pool = this._pools[key] || []; + _purgeKey (key) { + const pool = this._pools[key] || [] while (pool.length) { - const resource = pool.pop(); - this._destroy(resource); + const resource = pool.pop() + this._destroy(resource) } - delete this._pools[key]; + delete this._pools[key] } - _processPendingAcquireRequests(address) { - const key = address.asKey(); - const requests = this._acquireRequests[key]; + _processPendingAcquireRequests (address) { + const key = address.asKey() + const requests = this._acquireRequests[key] if (requests) { - const pendingRequest = requests.shift(); // pop a pending acquire request + const pendingRequest = requests.shift() // pop a pending acquire request if (pendingRequest) { this._acquire(address) .catch(error => { // failed to acquire/create a new connection to resolve the pending acquire request // propagate the error by failing the pending request - pendingRequest.reject(error); - return null; + pendingRequest.reject(error) + return null }) .then(resource => { if (resource) { @@ -229,16 +243,16 @@ class Pool { if (pendingRequest.isCompleted()) { // request has been completed, most likely failed by a timeout // return the acquired resource back to the pool - this._release(address, resource); + this._release(address, resource) } else { // request is still pending and can be resolved with the newly acquired resource - resourceAcquired(key, this._activeResourceCounts); // increment the active counter - pendingRequest.resolve(resource); // resolve the pending request with the acquired resource + resourceAcquired(key, this._activeResourceCounts) // increment the active counter + pendingRequest.resolve(resource) // resolve the pending request with the acquired resource } } - }); + }) } else { - delete this._acquireRequests[key]; + delete this._acquireRequests[key] } } } @@ -249,9 +263,9 @@ class Pool { * @param {string} key the resource group identifier (server address for connections). * @param {Object.} activeResourceCounts the object holding active counts per key. */ -function resourceAcquired(key, activeResourceCounts) { - const currentCount = activeResourceCounts[key] || 0; - activeResourceCounts[key] = currentCount + 1; +function resourceAcquired (key, activeResourceCounts) { + const currentCount = activeResourceCounts[key] || 0 + activeResourceCounts[key] = currentCount + 1 } /** @@ -259,53 +273,52 @@ function resourceAcquired(key, activeResourceCounts) { * @param {string} key the resource group identifier (server address for connections). * @param {Object.} activeResourceCounts the object holding active counts per key. */ -function resourceReleased(key, activeResourceCounts) { - const currentCount = activeResourceCounts[key] || 0; - const nextCount = currentCount - 1; +function resourceReleased (key, activeResourceCounts) { + const currentCount = activeResourceCounts[key] || 0 + const nextCount = currentCount - 1 if (nextCount > 0) { - activeResourceCounts[key] = nextCount; + activeResourceCounts[key] = nextCount } else { - delete activeResourceCounts[key]; + delete activeResourceCounts[key] } } class PendingRequest { - - constructor(key, resolve, reject, timeoutId, log) { - this._key = key; - this._resolve = resolve; - this._reject = reject; - this._timeoutId = timeoutId; - this._log = log; - this._completed = false; + constructor (key, resolve, reject, timeoutId, log) { + this._key = key + this._resolve = resolve + this._reject = reject + this._timeoutId = timeoutId + this._log = log + this._completed = false } - isCompleted() { - return this._completed; + isCompleted () { + return this._completed } - resolve(resource) { + resolve (resource) { if (this._completed) { - return; + return } - this._completed = true; + this._completed = true - clearTimeout(this._timeoutId); + clearTimeout(this._timeoutId) if (this._log.isDebugEnabled()) { - this._log.debug(`${resource} acquired from the pool ${this._key}`); + this._log.debug(`${resource} acquired from the pool ${this._key}`) } - this._resolve(resource); + this._resolve(resource) } - reject(error) { + reject (error) { if (this._completed) { - return; + return } - this._completed = true; + this._completed = true - clearTimeout(this._timeoutId); - this._reject(error); + clearTimeout(this._timeoutId) + this._reject(error) } } diff --git a/src/v1/internal/protocol-handshaker.js b/src/v1/internal/protocol-handshaker.js index 734e896d7..7de182301 100644 --- a/src/v1/internal/protocol-handshaker.js +++ b/src/v1/internal/protocol-handshaker.js @@ -17,17 +17,16 @@ * limitations under the License. */ -import {alloc} from './node'; -import {newError} from '../error'; -import BoltProtocolV1 from './bolt-protocol-v1'; -import BoltProtocolV2 from './bolt-protocol-v2'; -import BoltProtocolV3 from './bolt-protocol-v3'; +import { alloc } from './node' +import { newError } from '../error' +import BoltProtocolV1 from './bolt-protocol-v1' +import BoltProtocolV2 from './bolt-protocol-v2' +import BoltProtocolV3 from './bolt-protocol-v3' -const HTTP_MAGIC_PREAMBLE = 1213486160; // == 0x48545450 == "HTTP" -const BOLT_MAGIC_PREAMBLE = 0x6060B017; +const HTTP_MAGIC_PREAMBLE = 1213486160 // == 0x48545450 == "HTTP" +const BOLT_MAGIC_PREAMBLE = 0x6060b017 export default class ProtocolHandshaker { - /** * @constructor * @param {Connection} connection the connection owning this protocol. @@ -36,19 +35,19 @@ export default class ProtocolHandshaker { * @param {boolean} disableLosslessIntegers flag to use native JS numbers. * @param {Logger} log the logger. */ - constructor(connection, channel, chunker, disableLosslessIntegers, log) { - this._connection = connection; - this._channel = channel; - this._chunker = chunker; - this._disableLosslessIntegers = disableLosslessIntegers; - this._log = log; + constructor (connection, channel, chunker, disableLosslessIntegers, log) { + this._connection = connection + this._channel = channel + this._chunker = chunker + this._disableLosslessIntegers = disableLosslessIntegers + this._log = log } /** * Write a Bolt handshake into the underlying network channel. */ - writeHandshakeRequest() { - this._channel.write(newHandshakeBuffer()); + writeHandshakeRequest () { + this._channel.write(newHandshakeBuffer()) } /** @@ -57,31 +56,47 @@ export default class ProtocolHandshaker { * @return {BoltProtocol} bolt protocol corresponding to the version suggested by the database. * @throws {Neo4jError} when bolt protocol can't be instantiated. */ - createNegotiatedProtocol(buffer) { - const negotiatedVersion = buffer.readInt32(); + createNegotiatedProtocol (buffer) { + const negotiatedVersion = buffer.readInt32() if (this._log.isDebugEnabled()) { - this._log.debug(`${this._connection} negotiated protocol version ${negotiatedVersion}`); + this._log.debug( + `${this._connection} negotiated protocol version ${negotiatedVersion}` + ) } - return this._createProtocolWithVersion(negotiatedVersion); + return this._createProtocolWithVersion(negotiatedVersion) } /** * @return {BoltProtocol} * @private */ - _createProtocolWithVersion(version) { + _createProtocolWithVersion (version) { switch (version) { case 1: - return new BoltProtocolV1(this._connection, this._chunker, this._disableLosslessIntegers); + return new BoltProtocolV1( + this._connection, + this._chunker, + this._disableLosslessIntegers + ) case 2: - return new BoltProtocolV2(this._connection, this._chunker, this._disableLosslessIntegers); + return new BoltProtocolV2( + this._connection, + this._chunker, + this._disableLosslessIntegers + ) case 3: - return new BoltProtocolV3(this._connection, this._chunker, this._disableLosslessIntegers); + return new BoltProtocolV3( + this._connection, + this._chunker, + this._disableLosslessIntegers + ) case HTTP_MAGIC_PREAMBLE: - throw newError('Server responded HTTP. Make sure you are not trying to connect to the http endpoint ' + - '(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)'); + throw newError( + 'Server responded HTTP. Make sure you are not trying to connect to the http endpoint ' + + '(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)' + ) default: - throw newError('Unknown Bolt protocol version: ' + version); + throw newError('Unknown Bolt protocol version: ' + version) } } } @@ -90,20 +105,20 @@ export default class ProtocolHandshaker { * @return {BaseBuffer} * @private */ -function newHandshakeBuffer() { - const handshakeBuffer = alloc(5 * 4); +function newHandshakeBuffer () { + const handshakeBuffer = alloc(5 * 4) - //magic preamble - handshakeBuffer.writeInt32(BOLT_MAGIC_PREAMBLE); + // magic preamble + handshakeBuffer.writeInt32(BOLT_MAGIC_PREAMBLE) - //proposed versions - handshakeBuffer.writeInt32(3); - handshakeBuffer.writeInt32(2); - handshakeBuffer.writeInt32(1); - handshakeBuffer.writeInt32(0); + // proposed versions + handshakeBuffer.writeInt32(3) + handshakeBuffer.writeInt32(2) + handshakeBuffer.writeInt32(1) + handshakeBuffer.writeInt32(0) // reset the reader position - handshakeBuffer.reset(); + handshakeBuffer.reset() - return handshakeBuffer; + return handshakeBuffer } diff --git a/src/v1/internal/rediscovery.js b/src/v1/internal/rediscovery.js index 59cb567b7..7a3e77ea2 100644 --- a/src/v1/internal/rediscovery.js +++ b/src/v1/internal/rediscovery.js @@ -17,17 +17,16 @@ * limitations under the License. */ -import RoutingTable from './routing-table'; -import {newError, PROTOCOL_ERROR} from '../error'; +import RoutingTable from './routing-table' +import { newError, PROTOCOL_ERROR } from '../error' export default class Rediscovery { - /** * @constructor * @param {RoutingUtil} routingUtil the util to use. */ - constructor(routingUtil) { - this._routingUtil = routingUtil; + constructor (routingUtil) { + this._routingUtil = routingUtil } /** @@ -36,36 +35,51 @@ export default class Rediscovery { * @param {string} routerAddress the URL of the router. * @return {Promise} promise resolved with new routing table or null when connection error happened. */ - lookupRoutingTableOnRouter(session, routerAddress) { - return this._routingUtil.callRoutingProcedure(session, routerAddress).then(records => { - if (records === null) { - // connection error happened, unable to retrieve routing table from this router, next one should be queried - return null; - } + lookupRoutingTableOnRouter (session, routerAddress) { + return this._routingUtil + .callRoutingProcedure(session, routerAddress) + .then(records => { + if (records === null) { + // connection error happened, unable to retrieve routing table from this router, next one should be queried + return null + } - if (records.length !== 1) { - throw newError('Illegal response from router "' + routerAddress + '". ' + - 'Received ' + records.length + ' records but expected only one.\n' + JSON.stringify(records), - PROTOCOL_ERROR); - } + if (records.length !== 1) { + throw newError( + 'Illegal response from router "' + + routerAddress + + '". ' + + 'Received ' + + records.length + + ' records but expected only one.\n' + + JSON.stringify(records), + PROTOCOL_ERROR + ) + } - const record = records[0]; + const record = records[0] - const expirationTime = this._routingUtil.parseTtl(record, routerAddress); - const {routers, readers, writers} = this._routingUtil.parseServers(record, routerAddress); + const expirationTime = this._routingUtil.parseTtl(record, routerAddress) + const { routers, readers, writers } = this._routingUtil.parseServers( + record, + routerAddress + ) - Rediscovery._assertNonEmpty(routers, 'routers', routerAddress); - Rediscovery._assertNonEmpty(readers, 'readers', routerAddress); - // case with no writers is processed higher in the promise chain because only RoutingDriver knows - // how to deal with such table and how to treat router that returned such table + Rediscovery._assertNonEmpty(routers, 'routers', routerAddress) + Rediscovery._assertNonEmpty(readers, 'readers', routerAddress) + // case with no writers is processed higher in the promise chain because only RoutingDriver knows + // how to deal with such table and how to treat router that returned such table - return new RoutingTable(routers, readers, writers, expirationTime); - }); + return new RoutingTable(routers, readers, writers, expirationTime) + }) } - static _assertNonEmpty(serverAddressesArray, serversName, routerAddress) { + static _assertNonEmpty (serverAddressesArray, serversName, routerAddress) { if (serverAddressesArray.length === 0) { - throw newError('Received no ' + serversName + ' from router ' + routerAddress, PROTOCOL_ERROR); + throw newError( + 'Received no ' + serversName + ' from router ' + routerAddress, + PROTOCOL_ERROR + ) } } } diff --git a/src/v1/internal/request-message.js b/src/v1/internal/request-message.js index fd18f0d67..609f4fb37 100644 --- a/src/v1/internal/request-message.js +++ b/src/v1/internal/request-message.js @@ -17,30 +17,31 @@ * limitations under the License. */ -import {ACCESS_MODE_READ} from './constants'; +import { ACCESS_MODE_READ } from './constants' // Signature bytes for each request message type -const INIT = 0x01; // 0000 0001 // INIT -const ACK_FAILURE = 0x0E; // 0000 1110 // ACK_FAILURE - unused -const RESET = 0x0F; // 0000 1111 // RESET -const RUN = 0x10; // 0001 0000 // RUN -const DISCARD_ALL = 0x2F; // 0010 1111 // DISCARD_ALL - unused -const PULL_ALL = 0x3F; // 0011 1111 // PULL_ALL - -const HELLO = 0x01; // 0000 0001 // HELLO -const GOODBYE = 0x02; // 0000 0010 // GOODBYE -const BEGIN = 0x11; // 0001 0001 // BEGIN -const COMMIT = 0x12; // 0001 0010 // COMMIT -const ROLLBACK = 0x13; // 0001 0011 // ROLLBACK - -const READ_MODE = "r"; +const INIT = 0x01 // 0000 0001 // INIT +// eslint-disable-next-line no-unused-vars +const ACK_FAILURE = 0x0e // 0000 1110 // ACK_FAILURE - unused +const RESET = 0x0f // 0000 1111 // RESET +const RUN = 0x10 // 0001 0000 // RUN +// eslint-disable-next-line no-unused-vars +const DISCARD_ALL = 0x2f // 0010 1111 // DISCARD_ALL - unused +const PULL_ALL = 0x3f // 0011 1111 // PULL_ALL + +const HELLO = 0x01 // 0000 0001 // HELLO +const GOODBYE = 0x02 // 0000 0010 // GOODBYE +const BEGIN = 0x11 // 0001 0001 // BEGIN +const COMMIT = 0x12 // 0001 0010 // COMMIT +const ROLLBACK = 0x13 // 0001 0011 // ROLLBACK + +const READ_MODE = 'r' export default class RequestMessage { - - constructor(signature, fields, toString) { - this.signature = signature; - this.fields = fields; - this.toString = toString; + constructor (signature, fields, toString) { + this.signature = signature + this.fields = fields + this.toString = toString } /** @@ -49,8 +50,12 @@ export default class RequestMessage { * @param {object} authToken the authentication token. * @return {RequestMessage} new INIT message. */ - static init(clientName, authToken) { - return new RequestMessage(INIT, [clientName, authToken], () => `INIT ${clientName} {...}`); + static init (clientName, authToken) { + return new RequestMessage( + INIT, + [clientName, authToken], + () => `INIT ${clientName} {...}` + ) } /** @@ -59,24 +64,28 @@ export default class RequestMessage { * @param {object} parameters the statement parameters. * @return {RequestMessage} new RUN message. */ - static run(statement, parameters) { - return new RequestMessage(RUN, [statement, parameters], () => `RUN ${statement} ${JSON.stringify(parameters)}`); + static run (statement, parameters) { + return new RequestMessage( + RUN, + [statement, parameters], + () => `RUN ${statement} ${JSON.stringify(parameters)}` + ) } /** * Get a PULL_ALL message. * @return {RequestMessage} the PULL_ALL message. */ - static pullAll() { - return PULL_ALL_MESSAGE; + static pullAll () { + return PULL_ALL_MESSAGE } /** * Get a RESET message. * @return {RequestMessage} the RESET message. */ - static reset() { - return RESET_MESSAGE; + static reset () { + return RESET_MESSAGE } /** @@ -85,9 +94,13 @@ export default class RequestMessage { * @param {object} authToken the authentication token. * @return {RequestMessage} new HELLO message. */ - static hello(userAgent, authToken) { - const metadata = Object.assign({user_agent: userAgent}, authToken); - return new RequestMessage(HELLO, [metadata], () => `HELLO {user_agent: '${userAgent}', ...}`); + static hello (userAgent, authToken) { + const metadata = Object.assign({ user_agent: userAgent }, authToken) + return new RequestMessage( + HELLO, + [metadata], + () => `HELLO {user_agent: '${userAgent}', ...}` + ) } /** @@ -97,25 +110,29 @@ export default class RequestMessage { * @param {string} mode the access mode. * @return {RequestMessage} new BEGIN message. */ - static begin(bookmark, txConfig, mode) { - const metadata = buildTxMetadata(bookmark, txConfig, mode); - return new RequestMessage(BEGIN, [metadata], () => `BEGIN ${JSON.stringify(metadata)}`); + static begin (bookmark, txConfig, mode) { + const metadata = buildTxMetadata(bookmark, txConfig, mode) + return new RequestMessage( + BEGIN, + [metadata], + () => `BEGIN ${JSON.stringify(metadata)}` + ) } /** * Get a COMMIT message. * @return {RequestMessage} the COMMIT message. */ - static commit() { - return COMMIT_MESSAGE; + static commit () { + return COMMIT_MESSAGE } /** * Get a ROLLBACK message. * @return {RequestMessage} the ROLLBACK message. */ - static rollback() { - return ROLLBACK_MESSAGE; + static rollback () { + return ROLLBACK_MESSAGE } /** @@ -127,18 +144,24 @@ export default class RequestMessage { * @param {string} mode the access mode. * @return {RequestMessage} new RUN message with additional metadata. */ - static runWithMetadata(statement, parameters, bookmark, txConfig, mode) { - const metadata = buildTxMetadata(bookmark, txConfig, mode); - return new RequestMessage(RUN, [statement, parameters, metadata], - () => `RUN ${statement} ${JSON.stringify(parameters)} ${JSON.stringify(metadata)}`); + static runWithMetadata (statement, parameters, bookmark, txConfig, mode) { + const metadata = buildTxMetadata(bookmark, txConfig, mode) + return new RequestMessage( + RUN, + [statement, parameters, metadata], + () => + `RUN ${statement} ${JSON.stringify(parameters)} ${JSON.stringify( + metadata + )}` + ) } /** * Get a GOODBYE message. * @return {RequestMessage} the GOODBYE message. */ - static goodbye() { - return GOODBYE_MESSAGE; + static goodbye () { + return GOODBYE_MESSAGE } } @@ -149,26 +172,26 @@ export default class RequestMessage { * @param {string} mode the access mode. * @return {object} a metadata object. */ -function buildTxMetadata(bookmark, txConfig, mode) { - const metadata = {}; +function buildTxMetadata (bookmark, txConfig, mode) { + const metadata = {} if (!bookmark.isEmpty()) { - metadata['bookmarks'] = bookmark.values(); + metadata['bookmarks'] = bookmark.values() } if (txConfig.timeout) { - metadata['tx_timeout'] = txConfig.timeout; + metadata['tx_timeout'] = txConfig.timeout } if (txConfig.metadata) { - metadata['tx_metadata'] = txConfig.metadata; + metadata['tx_metadata'] = txConfig.metadata } if (mode === ACCESS_MODE_READ) { - metadata['mode'] = READ_MODE; + metadata['mode'] = READ_MODE } - return metadata; + return metadata } // constants for messages that never change -const PULL_ALL_MESSAGE = new RequestMessage(PULL_ALL, [], () => 'PULL_ALL'); -const RESET_MESSAGE = new RequestMessage(RESET, [], () => 'RESET'); -const COMMIT_MESSAGE = new RequestMessage(COMMIT, [], () => 'COMMIT'); -const ROLLBACK_MESSAGE = new RequestMessage(ROLLBACK, [], () => 'ROLLBACK'); -const GOODBYE_MESSAGE = new RequestMessage(GOODBYE, [], () => 'GOODBYE'); +const PULL_ALL_MESSAGE = new RequestMessage(PULL_ALL, [], () => 'PULL_ALL') +const RESET_MESSAGE = new RequestMessage(RESET, [], () => 'RESET') +const COMMIT_MESSAGE = new RequestMessage(COMMIT, [], () => 'COMMIT') +const ROLLBACK_MESSAGE = new RequestMessage(ROLLBACK, [], () => 'ROLLBACK') +const GOODBYE_MESSAGE = new RequestMessage(GOODBYE, [], () => 'GOODBYE') diff --git a/src/v1/internal/resolver/base-host-name-resolver.js b/src/v1/internal/resolver/base-host-name-resolver.js index ff89d65fd..7c00c985e 100644 --- a/src/v1/internal/resolver/base-host-name-resolver.js +++ b/src/v1/internal/resolver/base-host-name-resolver.js @@ -18,15 +18,14 @@ */ export default class BaseHostNameResolver { - - resolve() { - throw new Error('Abstract function'); + resolve () { + throw new Error('Abstract function') } /** * @protected */ - _resolveToItself(address) { - return Promise.resolve([address]); + _resolveToItself (address) { + return Promise.resolve([address]) } } diff --git a/src/v1/internal/resolver/configured-custom-resolver.js b/src/v1/internal/resolver/configured-custom-resolver.js index 7d5555d9c..80324eb83 100644 --- a/src/v1/internal/resolver/configured-custom-resolver.js +++ b/src/v1/internal/resolver/configured-custom-resolver.js @@ -16,25 +16,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import ServerAddress from '../server-address'; +import ServerAddress from '../server-address' -function resolveToSelf(address) { - return Promise.resolve([address]); +function resolveToSelf (address) { + return Promise.resolve([address]) } export default class ConfiguredCustomResolver { - constructor(resolverFunction) { - this._resolverFunction = resolverFunction ? resolverFunction : resolveToSelf; + constructor (resolverFunction) { + this._resolverFunction = resolverFunction || resolveToSelf } - resolve(seedRouter) { - return new Promise(resolve => resolve(this._resolverFunction(seedRouter.asHostPort()))) - .then(resolved => { - if (!Array.isArray(resolved)) { - throw new TypeError(`Configured resolver function should either return an array of addresses or a Promise resolved with an array of addresses.` + - `Each address is ':'. Got: ${resolved}`); - } - return resolved.map(r => ServerAddress.fromUrl(r)); - }); + resolve (seedRouter) { + return new Promise(resolve => + resolve(this._resolverFunction(seedRouter.asHostPort())) + ).then(resolved => { + if (!Array.isArray(resolved)) { + throw new TypeError( + `Configured resolver function should either return an array of addresses or a Promise resolved with an array of addresses.` + + `Each address is ':'. Got: ${resolved}` + ) + } + return resolved.map(r => ServerAddress.fromUrl(r)) + }) } } diff --git a/src/v1/internal/round-robin-array-index.js b/src/v1/internal/round-robin-array-index.js index 091b945e6..269a9362d 100644 --- a/src/v1/internal/round-robin-array-index.js +++ b/src/v1/internal/round-robin-array-index.js @@ -18,13 +18,12 @@ */ export default class RoundRobinArrayIndex { - /** * @constructor * @param {number} [initialOffset=0] the initial offset for round robin. */ - constructor(initialOffset) { - this._offset = initialOffset || 0; + constructor (initialOffset) { + this._offset = initialOffset || 0 } /** @@ -32,17 +31,17 @@ export default class RoundRobinArrayIndex { * @param {number} arrayLength the array length. * @return {number} index in the array. */ - next(arrayLength) { + next (arrayLength) { if (arrayLength === 0) { - return -1; + return -1 } - const nextOffset = this._offset; - this._offset += 1; + const nextOffset = this._offset + this._offset += 1 if (this._offset === Number.MAX_SAFE_INTEGER) { - this._offset = 0; + this._offset = 0 } - return nextOffset % arrayLength; + return nextOffset % arrayLength } } diff --git a/src/v1/internal/round-robin-load-balancing-strategy.js b/src/v1/internal/round-robin-load-balancing-strategy.js index 03802f3ac..d25f2c246 100644 --- a/src/v1/internal/round-robin-load-balancing-strategy.js +++ b/src/v1/internal/round-robin-load-balancing-strategy.js @@ -17,39 +17,38 @@ * limitations under the License. */ -import RoundRobinArrayIndex from './round-robin-array-index'; -import LoadBalancingStrategy from './load-balancing-strategy'; +import RoundRobinArrayIndex from './round-robin-array-index' +import LoadBalancingStrategy from './load-balancing-strategy' -export const ROUND_ROBIN_STRATEGY_NAME = 'round_robin'; +export const ROUND_ROBIN_STRATEGY_NAME = 'round_robin' export default class RoundRobinLoadBalancingStrategy extends LoadBalancingStrategy { - - constructor() { - super(); - this._readersIndex = new RoundRobinArrayIndex(); - this._writersIndex = new RoundRobinArrayIndex(); + constructor () { + super() + this._readersIndex = new RoundRobinArrayIndex() + this._writersIndex = new RoundRobinArrayIndex() } /** * @inheritDoc */ - selectReader(knownReaders) { - return this._select(knownReaders, this._readersIndex); + selectReader (knownReaders) { + return this._select(knownReaders, this._readersIndex) } /** * @inheritDoc */ - selectWriter(knownWriters) { - return this._select(knownWriters, this._writersIndex); + selectWriter (knownWriters) { + return this._select(knownWriters, this._writersIndex) } - _select(addresses, roundRobinIndex) { - const length = addresses.length; + _select (addresses, roundRobinIndex) { + const length = addresses.length if (length === 0) { - return null; + return null } - const index = roundRobinIndex.next(length); - return addresses[index]; + const index = roundRobinIndex.next(length) + return addresses[index] } } diff --git a/src/v1/internal/routing-table.js b/src/v1/internal/routing-table.js index 51e93aeef..b8cb8699d 100644 --- a/src/v1/internal/routing-table.js +++ b/src/v1/internal/routing-table.js @@ -16,35 +16,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {int} from '../integer'; -import {READ, WRITE} from '../driver'; +import { int } from '../integer' +import { READ, WRITE } from '../driver' -const MIN_ROUTERS = 1; +const MIN_ROUTERS = 1 export default class RoutingTable { - - constructor(routers, readers, writers, expirationTime) { - this.routers = routers || []; - this.readers = readers || []; - this.writers = writers || []; - this.expirationTime = expirationTime || int(0); + constructor (routers, readers, writers, expirationTime) { + this.routers = routers || [] + this.readers = readers || [] + this.writers = writers || [] + this.expirationTime = expirationTime || int(0) } - forget(address) { + forget (address) { // Don't remove it from the set of routers, since that might mean we lose our ability to re-discover, // just remove it from the set of readers and writers, so that we don't use it for actual work without // performing discovery first. - this.readers = removeFromArray(this.readers, address); - this.writers = removeFromArray(this.writers, address); + this.readers = removeFromArray(this.readers, address) + this.writers = removeFromArray(this.writers, address) } - forgetRouter(address) { - this.routers = removeFromArray(this.routers, address); + forgetRouter (address) { + this.routers = removeFromArray(this.routers, address) } - forgetWriter(address) { - this.writers = removeFromArray(this.writers, address); + forgetWriter (address) { + this.writers = removeFromArray(this.writers, address) } /** @@ -52,24 +51,28 @@ export default class RoutingTable { * @param {string} accessMode the type of operation. Allowed values are {@link READ} and {@link WRITE}. * @return {boolean} `true` when this table contains servers to serve the required operation, `false` otherwise. */ - isStaleFor(accessMode) { - return this.expirationTime.lessThan(Date.now()) || + isStaleFor (accessMode) { + return ( + this.expirationTime.lessThan(Date.now()) || this.routers.length < MIN_ROUTERS || - accessMode === READ && this.readers.length === 0 || - accessMode === WRITE && this.writers.length === 0; + (accessMode === READ && this.readers.length === 0) || + (accessMode === WRITE && this.writers.length === 0) + ) } - allServers() { - return [...this.routers, ...this.readers, ...this.writers]; + allServers () { + return [...this.routers, ...this.readers, ...this.writers] } - toString() { - return `RoutingTable[` + + toString () { + return ( + `RoutingTable[` + `expirationTime=${this.expirationTime}, ` + `currentTime=${Date.now()}, ` + `routers=[${this.routers}], ` + `readers=[${this.readers}], ` + - `writers=[${this.writers}]]`; + `writers=[${this.writers}]]` + ) } } @@ -79,6 +82,6 @@ export default class RoutingTable { * @param {object} element the element to remove. * @return {Array} new filtered array. */ -function removeFromArray(array, element) { - return array.filter(item => item.asKey() !== element.asKey()); +function removeFromArray (array, element) { + return array.filter(item => item.asKey() !== element.asKey()) } diff --git a/src/v1/internal/routing-util.js b/src/v1/internal/routing-util.js index 42e58efd1..04ac76445 100644 --- a/src/v1/internal/routing-util.js +++ b/src/v1/internal/routing-util.js @@ -17,22 +17,22 @@ * limitations under the License. */ -import {newError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE} from '../error'; -import Integer, {int} from '../integer'; -import {ServerVersion, VERSION_3_2_0} from './server-version'; -import Bookmark from './bookmark'; -import TxConfig from './tx-config'; -import {ACCESS_MODE_WRITE} from "./constants"; -import ServerAddress from './server-address'; - -const CALL_GET_SERVERS = 'CALL dbms.cluster.routing.getServers'; -const CALL_GET_ROUTING_TABLE = 'CALL dbms.cluster.routing.getRoutingTable($context)'; -const PROCEDURE_NOT_FOUND_CODE = 'Neo.ClientError.Procedure.ProcedureNotFound'; +import { newError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE } from '../error' +import Integer, { int } from '../integer' +import { ServerVersion, VERSION_3_2_0 } from './server-version' +import Bookmark from './bookmark' +import TxConfig from './tx-config' +import { ACCESS_MODE_WRITE } from './constants' +import ServerAddress from './server-address' + +const CALL_GET_SERVERS = 'CALL dbms.cluster.routing.getServers' +const CALL_GET_ROUTING_TABLE = + 'CALL dbms.cluster.routing.getRoutingTable($context)' +const PROCEDURE_NOT_FOUND_CODE = 'Neo.ClientError.Procedure.ProcedureNotFound' export default class RoutingUtil { - - constructor(routingContext) { - this._routingContext = routingContext; + constructor (routingContext) { + this._routingContext = routingContext } /** @@ -42,62 +42,76 @@ export default class RoutingUtil { * @return {Promise} promise resolved with records returned by the procedure call or null if * connection error happened. */ - callRoutingProcedure(session, routerAddress) { - return this._callAvailableRoutingProcedure(session).then(result => { - session.close(); - return result.records; - }).catch(error => { - if (error.code === PROCEDURE_NOT_FOUND_CODE) { - // throw when getServers procedure not found because this is clearly a configuration issue - throw newError( - `Server at ${routerAddress.asHostPort()} can't perform routing. Make sure you are connecting to a causal cluster`, - SERVICE_UNAVAILABLE); - } else { - // return nothing when failed to connect because code higher in the callstack is still able to retry with a - // different session towards a different router - return null; - } - }); + callRoutingProcedure (session, routerAddress) { + return this._callAvailableRoutingProcedure(session) + .then(result => { + session.close() + return result.records + }) + .catch(error => { + if (error.code === PROCEDURE_NOT_FOUND_CODE) { + // throw when getServers procedure not found because this is clearly a configuration issue + throw newError( + `Server at ${routerAddress.asHostPort()} can't perform routing. Make sure you are connecting to a causal cluster`, + SERVICE_UNAVAILABLE + ) + } else { + // return nothing when failed to connect because code higher in the callstack is still able to retry with a + // different session towards a different router + return null + } + }) } - parseTtl(record, routerAddress) { + parseTtl (record, routerAddress) { try { - const now = int(Date.now()); - const expires = int(record.get('ttl')).multiply(1000).add(now); + const now = int(Date.now()) + const expires = int(record.get('ttl')) + .multiply(1000) + .add(now) // if the server uses a really big expire time like Long.MAX_VALUE this may have overflowed if (expires.lessThan(now)) { - return Integer.MAX_VALUE; + return Integer.MAX_VALUE } - return expires; + return expires } catch (error) { throw newError( - `Unable to parse TTL entry from router ${routerAddress} from record:\n${JSON.stringify(record)}\nError message: ${error.message}`, - PROTOCOL_ERROR); + `Unable to parse TTL entry from router ${routerAddress} from record:\n${JSON.stringify( + record + )}\nError message: ${error.message}`, + PROTOCOL_ERROR + ) } } - parseServers(record, routerAddress) { + parseServers (record, routerAddress) { try { - const servers = record.get('servers'); + const servers = record.get('servers') - let routers = []; - let readers = []; - let writers = []; + let routers = [] + let readers = [] + let writers = [] servers.forEach(server => { - const role = server['role']; - const addresses = server['addresses']; + const role = server['role'] + const addresses = server['addresses'] if (role === 'ROUTE') { - routers = parseArray(addresses).map(address => ServerAddress.fromUrl(address)); + routers = parseArray(addresses).map(address => + ServerAddress.fromUrl(address) + ) } else if (role === 'WRITE') { - writers = parseArray(addresses).map(address => ServerAddress.fromUrl(address)); + writers = parseArray(addresses).map(address => + ServerAddress.fromUrl(address) + ) } else if (role === 'READ') { - readers = parseArray(addresses).map(address => ServerAddress.fromUrl(address)); + readers = parseArray(addresses).map(address => + ServerAddress.fromUrl(address) + ) } else { - throw newError('Unknown server role "' + role + '"', PROTOCOL_ERROR); + throw newError('Unknown server role "' + role + '"', PROTOCOL_ERROR) } - }); + }) return { routers: routers, @@ -106,35 +120,47 @@ export default class RoutingUtil { } } catch (error) { throw newError( - `Unable to parse servers entry from router ${routerAddress} from record:\n${JSON.stringify(record)}\nError message: ${error.message}`, - PROTOCOL_ERROR); + `Unable to parse servers entry from router ${routerAddress} from record:\n${JSON.stringify( + record + )}\nError message: ${error.message}`, + PROTOCOL_ERROR + ) } } - _callAvailableRoutingProcedure(session) { + _callAvailableRoutingProcedure (session) { return session._run(null, null, (connection, streamObserver) => { - const serverVersionString = connection.server.version; - const serverVersion = ServerVersion.fromString(serverVersionString); + const serverVersionString = connection.server.version + const serverVersion = ServerVersion.fromString(serverVersionString) - let query; - let params; + let query + let params if (serverVersion.compareTo(VERSION_3_2_0) >= 0) { - query = CALL_GET_ROUTING_TABLE; - params = {context: this._routingContext}; + query = CALL_GET_ROUTING_TABLE + params = { context: this._routingContext } } else { - query = CALL_GET_SERVERS; - params = {}; + query = CALL_GET_SERVERS + params = {} } - connection.protocol().run(query, params, Bookmark.empty(), TxConfig.empty(), ACCESS_MODE_WRITE, streamObserver); - }); + connection + .protocol() + .run( + query, + params, + Bookmark.empty(), + TxConfig.empty(), + ACCESS_MODE_WRITE, + streamObserver + ) + }) } } -function parseArray(addresses) { +function parseArray (addresses) { if (!Array.isArray(addresses)) { - throw new TypeError('Array expected but got: ' + addresses); + throw new TypeError('Array expected but got: ' + addresses) } - return Array.from(addresses); + return Array.from(addresses) } diff --git a/src/v1/internal/server-address.js b/src/v1/internal/server-address.js index f02905afb..fe49309bb 100644 --- a/src/v1/internal/server-address.js +++ b/src/v1/internal/server-address.js @@ -16,49 +16,53 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { assertNumber, assertString } from './util'; -import urlUtil from './url-util'; +import { assertNumber, assertString } from './util' +import urlUtil from './url-util' export default class ServerAddress { - - constructor(host, resolved, port, hostPort) { - this._host = assertString(host, 'host'); - this._resolved = resolved ? assertString(resolved, 'resolved') : null; - this._port = assertNumber(port, 'port'); - this._hostPort = hostPort; - this._stringValue = resolved ? `${hostPort}(${resolved})` : `${hostPort}`; + constructor (host, resolved, port, hostPort) { + this._host = assertString(host, 'host') + this._resolved = resolved ? assertString(resolved, 'resolved') : null + this._port = assertNumber(port, 'port') + this._hostPort = hostPort + this._stringValue = resolved ? `${hostPort}(${resolved})` : `${hostPort}` } - host() { - return this._host; + host () { + return this._host } - resolvedHost() { - return this._resolved ? this._resolved : this._host; + resolvedHost () { + return this._resolved ? this._resolved : this._host } - port() { - return this._port; + port () { + return this._port } - resolveWith(resolved) { - return new ServerAddress(this._host, resolved, this._port, this._hostPort); + resolveWith (resolved) { + return new ServerAddress(this._host, resolved, this._port, this._hostPort) } - asHostPort() { - return this._hostPort; + asHostPort () { + return this._hostPort } - asKey() { - return this._hostPort; + asKey () { + return this._hostPort } - toString() { - return this._stringValue; + toString () { + return this._stringValue } - static fromUrl(url) { - const urlParsed = urlUtil.parseDatabaseUrl(url); - return new ServerAddress(urlParsed.host, null, urlParsed.port, urlParsed.hostAndPort); + static fromUrl (url) { + const urlParsed = urlUtil.parseDatabaseUrl(url) + return new ServerAddress( + urlParsed.host, + null, + urlParsed.port, + urlParsed.hostAndPort + ) } } diff --git a/src/v1/internal/server-version.js b/src/v1/internal/server-version.js index c168d035d..3508e6df4 100644 --- a/src/v1/internal/server-version.js +++ b/src/v1/internal/server-version.js @@ -17,23 +17,24 @@ * limitations under the License. */ -import {assertString} from './util'; +import { assertString } from './util' -const SERVER_VERSION_REGEX = new RegExp('^(Neo4j/)?(\\d+)\\.(\\d+)(?:\\.)?(\\d*)(\\.|-|\\+)?([0-9A-Za-z-.]*)?$'); -const NEO4J_IN_DEV_VERSION_STRING = 'Neo4j/dev'; +const SERVER_VERSION_REGEX = new RegExp( + '^(Neo4j/)?(\\d+)\\.(\\d+)(?:\\.)?(\\d*)(\\.|-|\\+)?([0-9A-Za-z-.]*)?$' +) +const NEO4J_IN_DEV_VERSION_STRING = 'Neo4j/dev' class ServerVersion { - /** * @constructor * @param {number} major the major version number. * @param {number} minor the minor version number. * @param {number} patch the patch version number. */ - constructor(major, minor, patch) { - this.major = major; - this.minor = minor; - this.patch = patch; + constructor (major, minor, patch) { + this.major = major + this.minor = minor + this.patch = patch } /** @@ -41,12 +42,12 @@ class ServerVersion { * @param {Driver} driver the driver to use. * @return {Promise} promise resolved with a {@link ServerVersion} object or rejected with error. */ - static fromDriver(driver) { - const session = driver.session(); + static fromDriver (driver) { + const session = driver.session() return session.run('RETURN 1').then(result => { - session.close(); - return ServerVersion.fromString(result.summary.server.version); - }); + session.close() + return ServerVersion.fromString(result.summary.server.version) + }) } /** @@ -55,27 +56,29 @@ class ServerVersion { * @return {ServerVersion} version for the given string. * @throws Error if given string can't be parsed. */ - static fromString(versionStr) { + static fromString (versionStr) { if (!versionStr) { - return new ServerVersion(3, 0, 0); + return new ServerVersion(3, 0, 0) } - assertString(versionStr, 'Neo4j version string'); + assertString(versionStr, 'Neo4j version string') - if (versionStr.toLowerCase() === NEO4J_IN_DEV_VERSION_STRING.toLowerCase()) { - return VERSION_IN_DEV; + if ( + versionStr.toLowerCase() === NEO4J_IN_DEV_VERSION_STRING.toLowerCase() + ) { + return VERSION_IN_DEV } - const version = versionStr.match(SERVER_VERSION_REGEX); + const version = versionStr.match(SERVER_VERSION_REGEX) if (!version) { - throw new Error(`Unparsable Neo4j version: ${versionStr}`); + throw new Error(`Unparsable Neo4j version: ${versionStr}`) } - const major = parseIntStrict(version[2]); - const minor = parseIntStrict(version[3]); - const patch = parseIntStrict(version[4] || 0); + const major = parseIntStrict(version[2]) + const minor = parseIntStrict(version[3]) + const patch = parseIntStrict(version[4] || 0) - return new ServerVersion(major, minor, patch); + return new ServerVersion(major, minor, patch) } /** @@ -85,37 +88,37 @@ class ServerVersion { * was released earlier than the given one and value greater then 0 when this version was released after * than the given one. */ - compareTo(other) { - let result = compareInts(this.major, other.major); + compareTo (other) { + let result = compareInts(this.major, other.major) if (result === 0) { - result = compareInts(this.minor, other.minor); + result = compareInts(this.minor, other.minor) if (result === 0) { - result = compareInts(this.patch, other.patch); + result = compareInts(this.patch, other.patch) } } - return result; + return result } } -function parseIntStrict(str, name) { - const value = parseInt(str, 10); +function parseIntStrict (str, name) { + const value = parseInt(str, 10) if (!value && value !== 0) { - throw new Error(`Unparsable number ${name}: '${str}'`); + throw new Error(`Unparsable number ${name}: '${str}'`) } - return value; + return value } -function compareInts(x, y) { - return (x < y) ? -1 : ((x === y) ? 0 : 1); +function compareInts (x, y) { + return x < y ? -1 : x === y ? 0 : 1 } -const VERSION_3_1_0 = new ServerVersion(3, 1, 0); -const VERSION_3_2_0 = new ServerVersion(3, 2, 0); -const VERSION_3_4_0 = new ServerVersion(3, 4, 0); -const VERSION_3_5_0 = new ServerVersion(3, 5, 0); -const VERSION_4_0_0 = new ServerVersion(4, 0, 0); -const maxVer = Number.MAX_SAFE_INTEGER; -const VERSION_IN_DEV = new ServerVersion(maxVer, maxVer, maxVer); +const VERSION_3_1_0 = new ServerVersion(3, 1, 0) +const VERSION_3_2_0 = new ServerVersion(3, 2, 0) +const VERSION_3_4_0 = new ServerVersion(3, 4, 0) +const VERSION_3_5_0 = new ServerVersion(3, 5, 0) +const VERSION_4_0_0 = new ServerVersion(4, 0, 0) +const maxVer = Number.MAX_SAFE_INTEGER +const VERSION_IN_DEV = new ServerVersion(maxVer, maxVer, maxVer) export { ServerVersion, @@ -125,8 +128,4 @@ export { VERSION_3_5_0, VERSION_4_0_0, VERSION_IN_DEV -}; - - - - +} diff --git a/src/v1/internal/stream-observer.js b/src/v1/internal/stream-observer.js index 02db20ab1..0bcc98df1 100644 --- a/src/v1/internal/stream-observer.js +++ b/src/v1/internal/stream-observer.js @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import Record from '../record'; +import Record from '../record' /** * Handles a RUN/PULL_ALL, or RUN/DISCARD_ALL requests, maps the responses @@ -29,17 +29,16 @@ import Record from '../record'; * @access private */ class StreamObserver { - - constructor() { - this._fieldKeys = null; - this._fieldLookup = null; - this._queuedRecords = []; - this._tail = null; - this._error = null; - this._hasFailed = false; - this._observer = null; - this._conn = null; - this._meta = {}; + constructor () { + this._fieldKeys = null + this._fieldLookup = null + this._queuedRecords = [] + this._tail = null + this._error = null + this._hasFailed = false + this._observer = null + this._conn = null + this._meta = {} } /** @@ -48,55 +47,55 @@ class StreamObserver { * to it's onNext method, otherwise, push to record que. * @param {Array} rawRecord - An array with the raw record */ - onNext(rawRecord) { - let record = new Record(this._fieldKeys, rawRecord, this._fieldLookup); - if( this._observer ) { - this._observer.onNext( record ); + onNext (rawRecord) { + let record = new Record(this._fieldKeys, rawRecord, this._fieldLookup) + if (this._observer) { + this._observer.onNext(record) } else { - this._queuedRecords.push( record ); + this._queuedRecords.push(record) } } - onCompleted(meta) { - if( this._fieldKeys === null ) { + onCompleted (meta) { + if (this._fieldKeys === null) { // Stream header, build a name->index field lookup table // to be used by records. This is an optimization to make it // faster to look up fields in a record by name, rather than by index. // Since the records we get back via Bolt are just arrays of values. - this._fieldKeys = []; - this._fieldLookup = {}; - if( meta.fields && meta.fields.length > 0 ) { - this._fieldKeys = meta.fields; + this._fieldKeys = [] + this._fieldLookup = {} + if (meta.fields && meta.fields.length > 0) { + this._fieldKeys = meta.fields for (let i = 0; i < meta.fields.length; i++) { - this._fieldLookup[meta.fields[i]] = i; + this._fieldLookup[meta.fields[i]] = i } } } else { // End of stream - if( this._observer ) { - this._observer.onCompleted( meta ); + if (this._observer) { + this._observer.onCompleted(meta) } else { - this._tail = meta; + this._tail = meta } } - this._copyMetadataOnCompletion( meta ); + this._copyMetadataOnCompletion(meta) } - _copyMetadataOnCompletion(meta) { - for (var key in meta) { - if (meta.hasOwnProperty(key)) { - this._meta[key] = meta[key]; - } + _copyMetadataOnCompletion (meta) { + for (var key in meta) { + if (meta.hasOwnProperty(key)) { + this._meta[key] = meta[key] } + } } - serverMetadata() { - const serverMeta = {server: this._conn.server}; - return Object.assign({}, this._meta, serverMeta); + serverMetadata () { + const serverMeta = { server: this._conn.server } + return Object.assign({}, this._meta, serverMeta) } - resolveConnection(conn) { - this._conn = conn; + resolveConnection (conn) { + this._conn = conn } /** @@ -109,16 +108,16 @@ class StreamObserver { * * This function prepares the observer to only handle a single response message. */ - prepareToHandleSingleResponse() { - this._fieldKeys = []; + prepareToHandleSingleResponse () { + this._fieldKeys = [] } /** * Mark this observer as if it has completed with no metadata. */ - markCompleted() { - this._fieldKeys = []; - this._tail = {}; + markCompleted () { + this._fieldKeys = [] + this._tail = {} } /** @@ -127,20 +126,20 @@ class StreamObserver { * to it's onError method, otherwise set instance variable _error. * @param {Object} error - An error object */ - onError(error) { + onError (error) { if (this._hasFailed) { - return; + return } - this._hasFailed = true; + this._hasFailed = true if (this._observer) { if (this._observer.onError) { - this._observer.onError(error); + this._observer.onError(error) } else { - console.log(error); + console.log(error) } } else { - this._error = error; + this._error = error } } @@ -151,25 +150,25 @@ class StreamObserver { * @param {function(metadata: Object)} observer.onComplete - Handle stream tail, the metadata. * @param {function(error: Object)} observer.onError - Handle errors. */ - subscribe( observer ) { - if( this._error ) { - observer.onError(this._error); - return; + subscribe (observer) { + if (this._error) { + observer.onError(this._error) + return } - if( this._queuedRecords.length > 0 ) { + if (this._queuedRecords.length > 0) { for (let i = 0; i < this._queuedRecords.length; i++) { - observer.onNext( this._queuedRecords[i] ); + observer.onNext(this._queuedRecords[i]) } } - if( this._tail ) { - observer.onCompleted( this._tail ); + if (this._tail) { + observer.onCompleted(this._tail) } - this._observer = observer; + this._observer = observer } - hasFailed() { - return this._hasFailed; + hasFailed () { + return this._hasFailed } } -export default StreamObserver; +export default StreamObserver diff --git a/src/v1/internal/temporal-util.js b/src/v1/internal/temporal-util.js index 12ca69692..ab9653cda 100644 --- a/src/v1/internal/temporal-util.js +++ b/src/v1/internal/temporal-util.js @@ -17,10 +17,10 @@ * limitations under the License. */ -import {int, isInt} from '../integer'; -import {Date, LocalDateTime, LocalTime} from '../temporal-types'; -import {assertNumberOrInteger} from './util'; -import {newError} from '../error'; +import { int, isInt } from '../integer' +import { Date, LocalDateTime, LocalTime } from '../temporal-types' +import { assertNumberOrInteger } from './util' +import { newError } from '../error' /* Code in this util should be compatible with code in the database that uses JSR-310 java.time APIs. @@ -34,52 +34,54 @@ import {newError} from '../error'; */ class ValueRange { - - constructor(min, max) { - this._minNumber = min; - this._maxNumber = max; - this._minInteger = int(min); - this._maxInteger = int(max); + constructor (min, max) { + this._minNumber = min + this._maxNumber = max + this._minInteger = int(min) + this._maxInteger = int(max) } - contains(value) { + contains (value) { if (isInt(value)) { - return value.greaterThanOrEqual(this._minInteger) && value.lessThanOrEqual(this._maxInteger); + return ( + value.greaterThanOrEqual(this._minInteger) && + value.lessThanOrEqual(this._maxInteger) + ) } else { - return value >= this._minNumber && value <= this._maxNumber; + return value >= this._minNumber && value <= this._maxNumber } } - toString() { - return `[${this._minNumber}, ${this._maxNumber}]`; + toString () { + return `[${this._minNumber}, ${this._maxNumber}]` } } -const YEAR_RANGE = new ValueRange(-999999999, 999999999); -const MONTH_OF_YEAR_RANGE = new ValueRange(1, 12); -const DAY_OF_MONTH_RANGE = new ValueRange(1, 31); -const HOUR_OF_DAY_RANGE = new ValueRange(0, 23); -const MINUTE_OF_HOUR_RANGE = new ValueRange(0, 59); -const SECOND_OF_MINUTE_RANGE = new ValueRange(0, 59); -const NANOSECOND_OF_SECOND_RANGE = new ValueRange(0, 999999999); - -const MINUTES_PER_HOUR = 60; -const SECONDS_PER_MINUTE = 60; -const SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; -const NANOS_PER_SECOND = 1000000000; -const NANOS_PER_MILLISECOND = 1000000; -const NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE; -const NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR; -const DAYS_0000_TO_1970 = 719528; -const DAYS_PER_400_YEAR_CYCLE = 146097; -const SECONDS_PER_DAY = 86400; - -export function normalizeSecondsForDuration(seconds, nanoseconds) { - return int(seconds).add(floorDiv(nanoseconds, NANOS_PER_SECOND)); +const YEAR_RANGE = new ValueRange(-999999999, 999999999) +const MONTH_OF_YEAR_RANGE = new ValueRange(1, 12) +const DAY_OF_MONTH_RANGE = new ValueRange(1, 31) +const HOUR_OF_DAY_RANGE = new ValueRange(0, 23) +const MINUTE_OF_HOUR_RANGE = new ValueRange(0, 59) +const SECOND_OF_MINUTE_RANGE = new ValueRange(0, 59) +const NANOSECOND_OF_SECOND_RANGE = new ValueRange(0, 999999999) + +const MINUTES_PER_HOUR = 60 +const SECONDS_PER_MINUTE = 60 +const SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR +const NANOS_PER_SECOND = 1000000000 +const NANOS_PER_MILLISECOND = 1000000 +const NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE +const NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR +const DAYS_0000_TO_1970 = 719528 +const DAYS_PER_400_YEAR_CYCLE = 146097 +const SECONDS_PER_DAY = 86400 + +export function normalizeSecondsForDuration (seconds, nanoseconds) { + return int(seconds).add(floorDiv(nanoseconds, NANOS_PER_SECOND)) } -export function normalizeNanosecondsForDuration(nanoseconds) { - return floorMod(nanoseconds, NANOS_PER_SECOND); +export function normalizeNanosecondsForDuration (nanoseconds) { + return floorMod(nanoseconds, NANOS_PER_SECOND) } /** @@ -90,16 +92,16 @@ export function normalizeNanosecondsForDuration(nanoseconds) { * @param {Integer|number|string} nanosecond the nanosecond of the local time to convert. * @return {Integer} nanoseconds representing the given local time. */ -export function localTimeToNanoOfDay(hour, minute, second, nanosecond) { - hour = int(hour); - minute = int(minute); - second = int(second); - nanosecond = int(nanosecond); - - let totalNanos = hour.multiply(NANOS_PER_HOUR); - totalNanos = totalNanos.add(minute.multiply(NANOS_PER_MINUTE)); - totalNanos = totalNanos.add(second.multiply(NANOS_PER_SECOND)); - return totalNanos.add(nanosecond); +export function localTimeToNanoOfDay (hour, minute, second, nanosecond) { + hour = int(hour) + minute = int(minute) + second = int(second) + nanosecond = int(nanosecond) + + let totalNanos = hour.multiply(NANOS_PER_HOUR) + totalNanos = totalNanos.add(minute.multiply(NANOS_PER_MINUTE)) + totalNanos = totalNanos.add(second.multiply(NANOS_PER_SECOND)) + return totalNanos.add(nanosecond) } /** @@ -107,19 +109,19 @@ export function localTimeToNanoOfDay(hour, minute, second, nanosecond) { * @param {Integer|number|string} nanoOfDay the nanoseconds of the day to convert. * @return {LocalTime} the local time representing given nanoseconds of the day. */ -export function nanoOfDayToLocalTime(nanoOfDay) { - nanoOfDay = int(nanoOfDay); +export function nanoOfDayToLocalTime (nanoOfDay) { + nanoOfDay = int(nanoOfDay) - const hour = nanoOfDay.div(NANOS_PER_HOUR); - nanoOfDay = nanoOfDay.subtract(hour.multiply(NANOS_PER_HOUR)); + const hour = nanoOfDay.div(NANOS_PER_HOUR) + nanoOfDay = nanoOfDay.subtract(hour.multiply(NANOS_PER_HOUR)) - const minute = nanoOfDay.div(NANOS_PER_MINUTE); - nanoOfDay = nanoOfDay.subtract(minute.multiply(NANOS_PER_MINUTE)); + const minute = nanoOfDay.div(NANOS_PER_MINUTE) + nanoOfDay = nanoOfDay.subtract(minute.multiply(NANOS_PER_MINUTE)) - const second = nanoOfDay.div(NANOS_PER_SECOND); - const nanosecond = nanoOfDay.subtract(second.multiply(NANOS_PER_SECOND)); + const second = nanoOfDay.div(NANOS_PER_SECOND) + const nanosecond = nanoOfDay.subtract(second.multiply(NANOS_PER_SECOND)) - return new LocalTime(hour, minute, second, nanosecond); + return new LocalTime(hour, minute, second, nanosecond) } /** @@ -133,10 +135,18 @@ export function nanoOfDayToLocalTime(nanoOfDay) { * @param {Integer|number|string} nanosecond the nanosecond of the local date-time to convert. * @return {Integer} epoch second in UTC representing the given local date time. */ -export function localDateTimeToEpochSecond(year, month, day, hour, minute, second, nanosecond) { - const epochDay = dateToEpochDay(year, month, day); - const localTimeSeconds = localTimeToSecondOfDay(hour, minute, second); - return epochDay.multiply(SECONDS_PER_DAY).add(localTimeSeconds); +export function localDateTimeToEpochSecond ( + year, + month, + day, + hour, + minute, + second, + nanosecond +) { + const epochDay = dateToEpochDay(year, month, day) + const localTimeSeconds = localTimeToSecondOfDay(hour, minute, second) + return epochDay.multiply(SECONDS_PER_DAY).add(localTimeSeconds) } /** @@ -145,14 +155,22 @@ export function localDateTimeToEpochSecond(year, month, day, hour, minute, secon * @param {Integer|number|string} nano the nanosecond to use. * @return {LocalDateTime} the local date time representing given epoch second and nano. */ -export function epochSecondAndNanoToLocalDateTime(epochSecond, nano) { - const epochDay = floorDiv(epochSecond, SECONDS_PER_DAY); - const secondsOfDay = floorMod(epochSecond, SECONDS_PER_DAY); - const nanoOfDay = secondsOfDay.multiply(NANOS_PER_SECOND).add(nano); - - const localDate = epochDayToDate(epochDay); - const localTime = nanoOfDayToLocalTime(nanoOfDay); - return new LocalDateTime(localDate.year, localDate.month, localDate.day, localTime.hour, localTime.minute, localTime.second, localTime.nanosecond); +export function epochSecondAndNanoToLocalDateTime (epochSecond, nano) { + const epochDay = floorDiv(epochSecond, SECONDS_PER_DAY) + const secondsOfDay = floorMod(epochSecond, SECONDS_PER_DAY) + const nanoOfDay = secondsOfDay.multiply(NANOS_PER_SECOND).add(nano) + + const localDate = epochDayToDate(epochDay) + const localTime = nanoOfDayToLocalTime(nanoOfDay) + return new LocalDateTime( + localDate.year, + localDate.month, + localDate.day, + localTime.hour, + localTime.minute, + localTime.second, + localTime.nanosecond + ) } /** @@ -162,28 +180,44 @@ export function epochSecondAndNanoToLocalDateTime(epochSecond, nano) { * @param {Integer|number|string} day the day of the local date to convert. * @return {Integer} epoch day representing the given date. */ -export function dateToEpochDay(year, month, day) { - year = int(year); - month = int(month); - day = int(day); +export function dateToEpochDay (year, month, day) { + year = int(year) + month = int(month) + day = int(day) - let epochDay = year.multiply(365); + let epochDay = year.multiply(365) if (year.greaterThanOrEqual(0)) { - epochDay = epochDay.add(year.add(3).div(4).subtract(year.add(99).div(100)).add(year.add(399).div(400))); + epochDay = epochDay.add( + year + .add(3) + .div(4) + .subtract(year.add(99).div(100)) + .add(year.add(399).div(400)) + ) } else { - epochDay = epochDay.subtract(year.div(-4).subtract(year.div(-100)).add(year.div(-400))); + epochDay = epochDay.subtract( + year + .div(-4) + .subtract(year.div(-100)) + .add(year.div(-400)) + ) } - epochDay = epochDay.add(month.multiply(367).subtract(362).div(12)); - epochDay = epochDay.add(day.subtract(1)); + epochDay = epochDay.add( + month + .multiply(367) + .subtract(362) + .div(12) + ) + epochDay = epochDay.add(day.subtract(1)) if (month.greaterThan(2)) { - epochDay = epochDay.subtract(1); + epochDay = epochDay.subtract(1) if (!isLeapYear(year)) { - epochDay = epochDay.subtract(1); + epochDay = epochDay.subtract(1) } } - return epochDay.subtract(DAYS_0000_TO_1970); + return epochDay.subtract(DAYS_0000_TO_1970) } /** @@ -191,31 +225,62 @@ export function dateToEpochDay(year, month, day) { * @param {Integer|number|string} epochDay the epoch day to convert. * @return {Date} the date representing the epoch day in years, months and days. */ -export function epochDayToDate(epochDay) { - epochDay = int(epochDay); +export function epochDayToDate (epochDay) { + epochDay = int(epochDay) - let zeroDay = epochDay.add(DAYS_0000_TO_1970).subtract(60); - let adjust = int(0); + let zeroDay = epochDay.add(DAYS_0000_TO_1970).subtract(60) + let adjust = int(0) if (zeroDay.lessThan(0)) { - const adjustCycles = zeroDay.add(1).div(DAYS_PER_400_YEAR_CYCLE).subtract(1); - adjust = adjustCycles.multiply(400); - zeroDay = zeroDay.add(adjustCycles.multiply(-DAYS_PER_400_YEAR_CYCLE)); + const adjustCycles = zeroDay + .add(1) + .div(DAYS_PER_400_YEAR_CYCLE) + .subtract(1) + adjust = adjustCycles.multiply(400) + zeroDay = zeroDay.add(adjustCycles.multiply(-DAYS_PER_400_YEAR_CYCLE)) } - let year = zeroDay.multiply(400).add(591).div(DAYS_PER_400_YEAR_CYCLE); - let dayOfYearEst = zeroDay.subtract(year.multiply(365).add(year.div(4)).subtract(year.div(100)).add(year.div(400))); + let year = zeroDay + .multiply(400) + .add(591) + .div(DAYS_PER_400_YEAR_CYCLE) + let dayOfYearEst = zeroDay.subtract( + year + .multiply(365) + .add(year.div(4)) + .subtract(year.div(100)) + .add(year.div(400)) + ) if (dayOfYearEst.lessThan(0)) { - year = year.subtract(1); - dayOfYearEst = zeroDay.subtract(year.multiply(365).add(year.div(4)).subtract(year.div(100)).add(year.div(400))); + year = year.subtract(1) + dayOfYearEst = zeroDay.subtract( + year + .multiply(365) + .add(year.div(4)) + .subtract(year.div(100)) + .add(year.div(400)) + ) } - year = year.add(adjust); - let marchDayOfYear = dayOfYearEst; - - const marchMonth = marchDayOfYear.multiply(5).add(2).div(153); - const month = marchMonth.add(2).modulo(12).add(1); - const day = marchDayOfYear.subtract(marchMonth.multiply(306).add(5).div(10)).add(1); - year = year.add(marchMonth.div(10)); - - return new Date(year, month, day); + year = year.add(adjust) + let marchDayOfYear = dayOfYearEst + + const marchMonth = marchDayOfYear + .multiply(5) + .add(2) + .div(153) + const month = marchMonth + .add(2) + .modulo(12) + .add(1) + const day = marchDayOfYear + .subtract( + marchMonth + .multiply(306) + .add(5) + .div(10) + ) + .add(1) + year = year.add(marchMonth.div(10)) + + return new Date(year, month, day) } /** @@ -226,11 +291,14 @@ export function epochDayToDate(epochDay) { * @param {Integer|number|string} nanoseconds the number of nanoseconds. * @return {string} ISO string that represents given duration. */ -export function durationToIsoString(months, days, seconds, nanoseconds) { - const monthsString = formatNumber(months); - const daysString = formatNumber(days); - const secondsAndNanosecondsString = formatSecondsAndNanosecondsForDuration(seconds, nanoseconds); - return `P${monthsString}M${daysString}DT${secondsAndNanosecondsString}S`; +export function durationToIsoString (months, days, seconds, nanoseconds) { + const monthsString = formatNumber(months) + const daysString = formatNumber(days) + const secondsAndNanosecondsString = formatSecondsAndNanosecondsForDuration( + seconds, + nanoseconds + ) + return `P${monthsString}M${daysString}DT${secondsAndNanosecondsString}S` } /** @@ -241,12 +309,12 @@ export function durationToIsoString(months, days, seconds, nanoseconds) { * @param {Integer|number|string} nanosecond the nanosecond value. * @return {string} ISO string that represents given time. */ -export function timeToIsoString(hour, minute, second, nanosecond) { - const hourString = formatNumber(hour, 2); - const minuteString = formatNumber(minute, 2); - const secondString = formatNumber(second, 2); - const nanosecondString = formatNanosecond(nanosecond); - return `${hourString}:${minuteString}:${secondString}${nanosecondString}`; +export function timeToIsoString (hour, minute, second, nanosecond) { + const hourString = formatNumber(hour, 2) + const minuteString = formatNumber(minute, 2) + const secondString = formatNumber(second, 2) + const nanosecondString = formatNanosecond(nanosecond) + return `${hourString}:${minuteString}:${secondString}${nanosecondString}` } /** @@ -254,24 +322,29 @@ export function timeToIsoString(hour, minute, second, nanosecond) { * @param {Integer|number|string} offsetSeconds the offset in seconds. * @return {string} ISO string that represents given offset. */ -export function timeZoneOffsetToIsoString(offsetSeconds) { - offsetSeconds = int(offsetSeconds); +export function timeZoneOffsetToIsoString (offsetSeconds) { + offsetSeconds = int(offsetSeconds) if (offsetSeconds.equals(0)) { - return 'Z'; + return 'Z' } - const isNegative = offsetSeconds.isNegative(); + const isNegative = offsetSeconds.isNegative() if (isNegative) { - offsetSeconds = offsetSeconds.multiply(-1); + offsetSeconds = offsetSeconds.multiply(-1) } - const signPrefix = isNegative ? '-' : '+'; - - const hours = formatNumber(offsetSeconds.div(SECONDS_PER_HOUR), 2); - const minutes = formatNumber(offsetSeconds.div(SECONDS_PER_MINUTE).modulo(MINUTES_PER_HOUR), 2); - let secondsValue = offsetSeconds.modulo(SECONDS_PER_MINUTE); - const seconds = secondsValue.equals(0) ? null : formatNumber(secondsValue, 2); - - return seconds ? `${signPrefix}${hours}:${minutes}:${seconds}` : `${signPrefix}${hours}:${minutes}`; + const signPrefix = isNegative ? '-' : '+' + + const hours = formatNumber(offsetSeconds.div(SECONDS_PER_HOUR), 2) + const minutes = formatNumber( + offsetSeconds.div(SECONDS_PER_MINUTE).modulo(MINUTES_PER_HOUR), + 2 + ) + let secondsValue = offsetSeconds.modulo(SECONDS_PER_MINUTE) + const seconds = secondsValue.equals(0) ? null : formatNumber(secondsValue, 2) + + return seconds + ? `${signPrefix}${hours}:${minutes}:${seconds}` + : `${signPrefix}${hours}:${minutes}` } /** @@ -281,20 +354,20 @@ export function timeZoneOffsetToIsoString(offsetSeconds) { * @param {Integer|number|string} day the date day. * @return {string} ISO string that represents given date. */ -export function dateToIsoString(year, month, day) { - year = int(year); - const isNegative = year.isNegative(); +export function dateToIsoString (year, month, day) { + year = int(year) + const isNegative = year.isNegative() if (isNegative) { - year = year.multiply(-1); + year = year.multiply(-1) } - let yearString = formatNumber(year, 4); + let yearString = formatNumber(year, 4) if (isNegative) { - yearString = '-' + yearString; + yearString = '-' + yearString } - const monthString = formatNumber(month, 2); - const dayString = formatNumber(day, 2); - return `${yearString}-${monthString}-${dayString}`; + const monthString = formatNumber(month, 2) + const dayString = formatNumber(day, 2) + return `${yearString}-${monthString}-${dayString}` } /** @@ -303,10 +376,12 @@ export function dateToIsoString(year, month, day) { * @param {Integer|number|undefined} nanoseconds the optional number of nanoseconds. * @return {Integer|number} the total amount of nanoseconds. */ -export function totalNanoseconds(standardDate, nanoseconds) { - nanoseconds = (nanoseconds || 0); - const nanosFromMillis = standardDate.getMilliseconds() * NANOS_PER_MILLISECOND; - return isInt(nanoseconds) ? nanoseconds.add(nanosFromMillis) : nanoseconds + nanosFromMillis; +export function totalNanoseconds (standardDate, nanoseconds) { + nanoseconds = nanoseconds || 0 + const nanosFromMillis = standardDate.getMilliseconds() * NANOS_PER_MILLISECOND + return isInt(nanoseconds) + ? nanoseconds.add(nanosFromMillis) + : nanoseconds + nanosFromMillis } /** @@ -321,12 +396,12 @@ export function totalNanoseconds(standardDate, nanoseconds) { * @param {global.Date} standardDate the standard JavaScript date. * @return {number} the time zone offset in seconds. */ -export function timeZoneOffsetInSeconds(standardDate) { - let offsetInMinutes = standardDate.getTimezoneOffset(); +export function timeZoneOffsetInSeconds (standardDate) { + let offsetInMinutes = standardDate.getTimezoneOffset() if (offsetInMinutes === 0) { - return 0; + return 0 } - return -1 * offsetInMinutes * SECONDS_PER_MINUTE; + return -1 * offsetInMinutes * SECONDS_PER_MINUTE } /** @@ -334,8 +409,8 @@ export function timeZoneOffsetInSeconds(standardDate) { * @param {Integer|number} year the value to check. * @return {Integer|number} the value of the year if it is valid. Exception is thrown otherwise. */ -export function assertValidYear(year) { - return assertValidTemporalValue(year, YEAR_RANGE, 'Year'); +export function assertValidYear (year) { + return assertValidTemporalValue(year, YEAR_RANGE, 'Year') } /** @@ -343,8 +418,8 @@ export function assertValidYear(year) { * @param {Integer|number} month the value to check. * @return {Integer|number} the value of the month if it is valid. Exception is thrown otherwise. */ -export function assertValidMonth(month) { - return assertValidTemporalValue(month, MONTH_OF_YEAR_RANGE, 'Month'); +export function assertValidMonth (month) { + return assertValidTemporalValue(month, MONTH_OF_YEAR_RANGE, 'Month') } /** @@ -352,8 +427,8 @@ export function assertValidMonth(month) { * @param {Integer|number} day the value to check. * @return {Integer|number} the value of the day if it is valid. Exception is thrown otherwise. */ -export function assertValidDay(day) { - return assertValidTemporalValue(day, DAY_OF_MONTH_RANGE, 'Day'); +export function assertValidDay (day) { + return assertValidTemporalValue(day, DAY_OF_MONTH_RANGE, 'Day') } /** @@ -361,8 +436,8 @@ export function assertValidDay(day) { * @param {Integer|number} hour the value to check. * @return {Integer|number} the value of the hour if it is valid. Exception is thrown otherwise. */ -export function assertValidHour(hour) { - return assertValidTemporalValue(hour, HOUR_OF_DAY_RANGE, 'Hour'); +export function assertValidHour (hour) { + return assertValidTemporalValue(hour, HOUR_OF_DAY_RANGE, 'Hour') } /** @@ -370,8 +445,8 @@ export function assertValidHour(hour) { * @param {Integer|number} minute the value to check. * @return {Integer|number} the value of the minute if it is valid. Exception is thrown otherwise. */ -export function assertValidMinute(minute) { - return assertValidTemporalValue(minute, MINUTE_OF_HOUR_RANGE, 'Minute'); +export function assertValidMinute (minute) { + return assertValidTemporalValue(minute, MINUTE_OF_HOUR_RANGE, 'Minute') } /** @@ -379,8 +454,8 @@ export function assertValidMinute(minute) { * @param {Integer|number} second the value to check. * @return {Integer|number} the value of the second if it is valid. Exception is thrown otherwise. */ -export function assertValidSecond(second) { - return assertValidTemporalValue(second, SECOND_OF_MINUTE_RANGE, 'Second'); +export function assertValidSecond (second) { + return assertValidTemporalValue(second, SECOND_OF_MINUTE_RANGE, 'Second') } /** @@ -388,8 +463,12 @@ export function assertValidSecond(second) { * @param {Integer|number} nanosecond the value to check. * @return {Integer|number} the value of the nanosecond if it is valid. Exception is thrown otherwise. */ -export function assertValidNanosecond(nanosecond) { - return assertValidTemporalValue(nanosecond, NANOSECOND_OF_SECOND_RANGE, 'Nanosecond'); +export function assertValidNanosecond (nanosecond) { + return assertValidTemporalValue( + nanosecond, + NANOSECOND_OF_SECOND_RANGE, + 'Nanosecond' + ) } /** @@ -399,12 +478,14 @@ export function assertValidNanosecond(nanosecond) { * @param {string} name the name of the value. * @return {Integer|number} the value if valid. Exception is thrown otherwise. */ -function assertValidTemporalValue(value, range, name) { - assertNumberOrInteger(value, name); +function assertValidTemporalValue (value, range, name) { + assertNumberOrInteger(value, name) if (!range.contains(value)) { - throw newError(`${name} is expected to be in range ${range} but was: ${value}`); + throw newError( + `${name} is expected to be in range ${range} but was: ${value}` + ) } - return value; + return value } /** @@ -414,14 +495,14 @@ function assertValidTemporalValue(value, range, name) { * @param {Integer|number|string} second the second of the local time. * @return {Integer} seconds representing the given local time. */ -function localTimeToSecondOfDay(hour, minute, second) { - hour = int(hour); - minute = int(minute); - second = int(second); - - let totalSeconds = hour.multiply(SECONDS_PER_HOUR); - totalSeconds = totalSeconds.add(minute.multiply(SECONDS_PER_MINUTE)); - return totalSeconds.add(second); +function localTimeToSecondOfDay (hour, minute, second) { + hour = int(hour) + minute = int(minute) + second = int(second) + + let totalSeconds = hour.multiply(SECONDS_PER_HOUR) + totalSeconds = totalSeconds.add(minute.multiply(SECONDS_PER_MINUTE)) + return totalSeconds.add(second) } /** @@ -429,17 +510,17 @@ function localTimeToSecondOfDay(hour, minute, second) { * @param {Integer|number|string} year the year to check. Will be converted to {@link Integer} for all calculations. * @return {boolean} `true` if given year is a leap year, `false` otherwise. */ -function isLeapYear(year) { - year = int(year); +function isLeapYear (year) { + year = int(year) if (!year.modulo(4).equals(0)) { - return false; + return false } else if (!year.modulo(100).equals(0)) { - return true; + return true } else if (!year.modulo(400).equals(0)) { - return false; + return false } else { - return true; + return true } } @@ -448,15 +529,15 @@ function isLeapYear(year) { * @param {Integer|number|string} y the divisor. * @return {Integer} the result. */ -function floorDiv(x, y) { - x = int(x); - y = int(y); +function floorDiv (x, y) { + x = int(x) + y = int(y) - let result = x.div(y); + let result = x.div(y) if (x.isPositive() !== y.isPositive() && result.multiply(y).notEquals(x)) { - result = result.subtract(1); + result = result.subtract(1) } - return result; + return result } /** @@ -464,11 +545,11 @@ function floorDiv(x, y) { * @param {Integer|number|string} y the divisor. * @return {Integer} the result. */ -function floorMod(x, y) { - x = int(x); - y = int(y); +function floorMod (x, y) { + x = int(x) + y = int(y) - return x.subtract(floorDiv(x, y).multiply(y)); + return x.subtract(floorDiv(x, y).multiply(y)) } /** @@ -476,43 +557,50 @@ function floorMod(x, y) { * @param {Integer|number|string} nanoseconds the number of nanoseconds to format. * @return {string} formatted value. */ -function formatSecondsAndNanosecondsForDuration(seconds, nanoseconds) { - seconds = int(seconds); - nanoseconds = int(nanoseconds); +function formatSecondsAndNanosecondsForDuration (seconds, nanoseconds) { + seconds = int(seconds) + nanoseconds = int(nanoseconds) - let secondsString; - let nanosecondsString; + let secondsString + let nanosecondsString - const secondsNegative = seconds.isNegative(); - const nanosecondsGreaterThanZero = nanoseconds.greaterThan(0); + const secondsNegative = seconds.isNegative() + const nanosecondsGreaterThanZero = nanoseconds.greaterThan(0) if (secondsNegative && nanosecondsGreaterThanZero) { if (seconds.equals(-1)) { - secondsString = '-0'; + secondsString = '-0' } else { - secondsString = seconds.add(1).toString(); + secondsString = seconds.add(1).toString() } } else { - secondsString = seconds.toString(); + secondsString = seconds.toString() } if (nanosecondsGreaterThanZero) { if (secondsNegative) { - nanosecondsString = formatNanosecond(nanoseconds.negate().add(2 * NANOS_PER_SECOND).modulo(NANOS_PER_SECOND)); + nanosecondsString = formatNanosecond( + nanoseconds + .negate() + .add(2 * NANOS_PER_SECOND) + .modulo(NANOS_PER_SECOND) + ) } else { - nanosecondsString = formatNanosecond(nanoseconds.add(NANOS_PER_SECOND).modulo(NANOS_PER_SECOND)); + nanosecondsString = formatNanosecond( + nanoseconds.add(NANOS_PER_SECOND).modulo(NANOS_PER_SECOND) + ) } } - return nanosecondsString ? secondsString + nanosecondsString : secondsString; + return nanosecondsString ? secondsString + nanosecondsString : secondsString } /** * @param {Integer|number|string} value the number of nanoseconds to format. * @return {string} formatted and possibly left-padded nanoseconds part as string. */ -function formatNanosecond(value) { - value = int(value); - return value.equals(0) ? '' : '.' + formatNumber(value, 9); +function formatNanosecond (value) { + value = int(value) + return value.equals(0) ? '' : '.' + formatNumber(value, 9) } /** @@ -520,19 +608,19 @@ function formatNanosecond(value) { * @param {number} [stringLength=undefined] the string length to left-pad to. * @return {string} formatted and possibly left-padded number as string. */ -function formatNumber(num, stringLength = undefined) { - num = int(num); - const isNegative = num.isNegative(); +function formatNumber (num, stringLength = undefined) { + num = int(num) + const isNegative = num.isNegative() if (isNegative) { - num = num.negate(); + num = num.negate() } - let numString = num.toString(); + let numString = num.toString() if (stringLength) { // left pad the string with zeroes while (numString.length < stringLength) { - numString = '0' + numString; + numString = '0' + numString } } - return isNegative ? '-' + numString : numString; + return isNegative ? '-' + numString : numString } diff --git a/src/v1/internal/transaction-executor.js b/src/v1/internal/transaction-executor.js index c7df5c303..258c84b77 100644 --- a/src/v1/internal/transaction-executor.js +++ b/src/v1/internal/transaction-executor.js @@ -17,174 +17,237 @@ * limitations under the License. */ -import {newError, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../error'; +import { newError, SERVICE_UNAVAILABLE, SESSION_EXPIRED } from '../error' -const DEFAULT_MAX_RETRY_TIME_MS = 30 * 1000; // 30 seconds -const DEFAULT_INITIAL_RETRY_DELAY_MS = 1000; // 1 seconds -const DEFAULT_RETRY_DELAY_MULTIPLIER = 2.0; -const DEFAULT_RETRY_DELAY_JITTER_FACTOR = 0.2; +const DEFAULT_MAX_RETRY_TIME_MS = 30 * 1000 // 30 seconds +const DEFAULT_INITIAL_RETRY_DELAY_MS = 1000 // 1 seconds +const DEFAULT_RETRY_DELAY_MULTIPLIER = 2.0 +const DEFAULT_RETRY_DELAY_JITTER_FACTOR = 0.2 export default class TransactionExecutor { - - constructor(maxRetryTimeMs, initialRetryDelayMs, multiplier, jitterFactor) { - this._maxRetryTimeMs = _valueOrDefault(maxRetryTimeMs, DEFAULT_MAX_RETRY_TIME_MS); - this._initialRetryDelayMs = _valueOrDefault(initialRetryDelayMs, DEFAULT_INITIAL_RETRY_DELAY_MS); - this._multiplier = _valueOrDefault(multiplier, DEFAULT_RETRY_DELAY_MULTIPLIER); - this._jitterFactor = _valueOrDefault(jitterFactor, DEFAULT_RETRY_DELAY_JITTER_FACTOR); - - this._inFlightTimeoutIds = []; - - this._verifyAfterConstruction(); + constructor (maxRetryTimeMs, initialRetryDelayMs, multiplier, jitterFactor) { + this._maxRetryTimeMs = _valueOrDefault( + maxRetryTimeMs, + DEFAULT_MAX_RETRY_TIME_MS + ) + this._initialRetryDelayMs = _valueOrDefault( + initialRetryDelayMs, + DEFAULT_INITIAL_RETRY_DELAY_MS + ) + this._multiplier = _valueOrDefault( + multiplier, + DEFAULT_RETRY_DELAY_MULTIPLIER + ) + this._jitterFactor = _valueOrDefault( + jitterFactor, + DEFAULT_RETRY_DELAY_JITTER_FACTOR + ) + + this._inFlightTimeoutIds = [] + + this._verifyAfterConstruction() } - execute(transactionCreator, transactionWork) { + execute (transactionCreator, transactionWork) { return new Promise((resolve, reject) => { - this._executeTransactionInsidePromise(transactionCreator, transactionWork, resolve, reject); + this._executeTransactionInsidePromise( + transactionCreator, + transactionWork, + resolve, + reject + ) }).catch(error => { - const retryStartTimeMs = Date.now(); - const retryDelayMs = this._initialRetryDelayMs; - return this._retryTransactionPromise(transactionCreator, transactionWork, error, retryStartTimeMs, retryDelayMs); - }); + const retryStartTimeMs = Date.now() + const retryDelayMs = this._initialRetryDelayMs + return this._retryTransactionPromise( + transactionCreator, + transactionWork, + error, + retryStartTimeMs, + retryDelayMs + ) + }) } - close() { + close () { // cancel all existing timeouts to prevent further retries - this._inFlightTimeoutIds.forEach(timeoutId => clearTimeout(timeoutId)); - this._inFlightTimeoutIds = []; + this._inFlightTimeoutIds.forEach(timeoutId => clearTimeout(timeoutId)) + this._inFlightTimeoutIds = [] } - _retryTransactionPromise(transactionCreator, transactionWork, error, retryStartTime, retryDelayMs) { - const elapsedTimeMs = Date.now() - retryStartTime; - - if (elapsedTimeMs > this._maxRetryTimeMs || !TransactionExecutor._canRetryOn(error)) { - return Promise.reject(error); + _retryTransactionPromise ( + transactionCreator, + transactionWork, + error, + retryStartTime, + retryDelayMs + ) { + const elapsedTimeMs = Date.now() - retryStartTime + + if ( + elapsedTimeMs > this._maxRetryTimeMs || + !TransactionExecutor._canRetryOn(error) + ) { + return Promise.reject(error) } return new Promise((resolve, reject) => { - const nextRetryTime = this._computeDelayWithJitter(retryDelayMs); + const nextRetryTime = this._computeDelayWithJitter(retryDelayMs) const timeoutId = setTimeout(() => { // filter out this timeoutId when time has come and function is being executed - this._inFlightTimeoutIds = this._inFlightTimeoutIds.filter(id => id !== timeoutId); - this._executeTransactionInsidePromise(transactionCreator, transactionWork, resolve, reject); - }, nextRetryTime); + this._inFlightTimeoutIds = this._inFlightTimeoutIds.filter( + id => id !== timeoutId + ) + this._executeTransactionInsidePromise( + transactionCreator, + transactionWork, + resolve, + reject + ) + }, nextRetryTime) // add newly created timeoutId to the list of all in-flight timeouts - this._inFlightTimeoutIds.push(timeoutId); + this._inFlightTimeoutIds.push(timeoutId) }).catch(error => { - const nextRetryDelayMs = retryDelayMs * this._multiplier; - return this._retryTransactionPromise(transactionCreator, transactionWork, error, retryStartTime, nextRetryDelayMs); - }); + const nextRetryDelayMs = retryDelayMs * this._multiplier + return this._retryTransactionPromise( + transactionCreator, + transactionWork, + error, + retryStartTime, + nextRetryDelayMs + ) + }) } - _executeTransactionInsidePromise(transactionCreator, transactionWork, resolve, reject) { - let tx; + _executeTransactionInsidePromise ( + transactionCreator, + transactionWork, + resolve, + reject + ) { + let tx try { - tx = transactionCreator(); + tx = transactionCreator() } catch (error) { // failed to create a transaction - reject(error); - return; + reject(error) + return } - const resultPromise = this._safeExecuteTransactionWork(tx, transactionWork); + const resultPromise = this._safeExecuteTransactionWork(tx, transactionWork) resultPromise - .then(result => this._handleTransactionWorkSuccess(result, tx, resolve, reject)) - .catch(error => this._handleTransactionWorkFailure(error, tx, reject)); + .then(result => + this._handleTransactionWorkSuccess(result, tx, resolve, reject) + ) + .catch(error => this._handleTransactionWorkFailure(error, tx, reject)) } - _safeExecuteTransactionWork(tx, transactionWork) { + _safeExecuteTransactionWork (tx, transactionWork) { try { - const result = transactionWork(tx); + const result = transactionWork(tx) // user defined callback is supposed to return a promise, but it might not; so to protect against an // incorrect API usage we wrap the returned value with a resolved promise; this is effectively a // validation step without type checks - return Promise.resolve(result); + return Promise.resolve(result) } catch (error) { - return Promise.reject(error); + return Promise.reject(error) } } - _handleTransactionWorkSuccess(result, tx, resolve, reject) { + _handleTransactionWorkSuccess (result, tx, resolve, reject) { if (tx.isOpen()) { // transaction work returned resolved promise and transaction has not been committed/rolled back // try to commit the transaction - tx.commit().then(() => { - // transaction was committed, return result to the user - resolve(result); - }).catch(error => { - // transaction failed to commit, propagate the failure - reject(error); - }); + tx.commit() + .then(() => { + // transaction was committed, return result to the user + resolve(result) + }) + .catch(error => { + // transaction failed to commit, propagate the failure + reject(error) + }) } else { // transaction work returned resolved promise and transaction is already committed/rolled back // return the result returned by given transaction work - resolve(result); + resolve(result) } } - _handleTransactionWorkFailure(error, tx, reject) { + _handleTransactionWorkFailure (error, tx, reject) { if (tx.isOpen()) { // transaction work failed and the transaction is still open, roll it back and propagate the failure tx.rollback() .catch(ignore => { // ignore the rollback error }) - .then(() => reject(error)); // propagate the original error we got from the transaction work + .then(() => reject(error)) // propagate the original error we got from the transaction work } else { // transaction is already rolled back, propagate the error - reject(error); + reject(error) } } - _computeDelayWithJitter(delayMs) { - const jitter = (delayMs * this._jitterFactor); - const min = delayMs - jitter; - const max = delayMs + jitter; - return Math.random() * (max - min) + min; + _computeDelayWithJitter (delayMs) { + const jitter = delayMs * this._jitterFactor + const min = delayMs - jitter + const max = delayMs + jitter + return Math.random() * (max - min) + min } - static _canRetryOn(error) { - return error && error.code && + static _canRetryOn (error) { + return ( + error && + error.code && (error.code === SERVICE_UNAVAILABLE || - error.code === SESSION_EXPIRED || - this._isTransientError(error)); + error.code === SESSION_EXPIRED || + this._isTransientError(error)) + ) } - static _isTransientError(error) { + static _isTransientError (error) { // Retries should not happen when transaction was explicitly terminated by the user. // Termination of transaction might result in two different error codes depending on where it was // terminated. These are really client errors but classification on the server is not entirely correct and // they are classified as transient. - - const code = error.code; + + const code = error.code if (code.indexOf('TransientError') >= 0) { - if (code === 'Neo.TransientError.Transaction.Terminated' || code === 'Neo.TransientError.Transaction.LockClientStopped') { - return false; + if ( + code === 'Neo.TransientError.Transaction.Terminated' || + code === 'Neo.TransientError.Transaction.LockClientStopped' + ) { + return false } - return true; + return true } - return false; + return false } - _verifyAfterConstruction() { + _verifyAfterConstruction () { if (this._maxRetryTimeMs < 0) { - throw newError('Max retry time should be >= 0: ' + this._maxRetryTimeMs); + throw newError('Max retry time should be >= 0: ' + this._maxRetryTimeMs) } if (this._initialRetryDelayMs < 0) { - throw newError('Initial retry delay should >= 0: ' + this._initialRetryDelayMs); + throw newError( + 'Initial retry delay should >= 0: ' + this._initialRetryDelayMs + ) } if (this._multiplier < 1.0) { - throw newError('Multiplier should be >= 1.0: ' + this._multiplier); + throw newError('Multiplier should be >= 1.0: ' + this._multiplier) } if (this._jitterFactor < 0 || this._jitterFactor > 1) { - throw newError('Jitter factor should be in [0.0, 1.0]: ' + this._jitterFactor); + throw newError( + 'Jitter factor should be in [0.0, 1.0]: ' + this._jitterFactor + ) } } -}; +} -function _valueOrDefault(value, defaultValue) { +function _valueOrDefault (value, defaultValue) { if (value || value === 0) { - return value; + return value } - return defaultValue; + return defaultValue } diff --git a/src/v1/internal/tx-config.js b/src/v1/internal/tx-config.js index bcca02d32..c505e7b30 100644 --- a/src/v1/internal/tx-config.js +++ b/src/v1/internal/tx-config.js @@ -17,9 +17,9 @@ * limitations under the License. */ -import * as util from './util'; -import {int} from '../integer'; -import {newError} from '../error'; +import * as util from './util' +import { int } from '../integer' +import { newError } from '../error' /** * Internal holder of the transaction configuration. @@ -28,71 +28,70 @@ import {newError} from '../error'; * Driver converts such objects to {@link TxConfig} immediately and uses converted values everywhere. */ export default class TxConfig { - /** * @constructor * @param {object} config the raw configuration object. */ - constructor(config) { - assertValidConfig(config); - this.timeout = extractTimeout(config); - this.metadata = extractMetadata(config); + constructor (config) { + assertValidConfig(config) + this.timeout = extractTimeout(config) + this.metadata = extractMetadata(config) } /** * Get an empty config object. * @return {TxConfig} an empty config. */ - static empty() { - return EMPTY_CONFIG; + static empty () { + return EMPTY_CONFIG } /** * Check if this config object is empty. I.e. has no configuration values specified. * @return {boolean} `true` if this object is empty, `false` otherwise. */ - isEmpty() { - return Object.values(this).every(value => value == null); + isEmpty () { + return Object.values(this).every(value => value == null) } } -const EMPTY_CONFIG = new TxConfig({}); +const EMPTY_CONFIG = new TxConfig({}) /** * @return {Integer|null} */ -function extractTimeout(config) { +function extractTimeout (config) { if (util.isObject(config) && (config.timeout || config.timeout === 0)) { - util.assertNumberOrInteger(config.timeout, 'Transaction timeout'); - const timeout = int(config.timeout); + util.assertNumberOrInteger(config.timeout, 'Transaction timeout') + const timeout = int(config.timeout) if (timeout.isZero()) { - throw newError('Transaction timeout should not be zero'); + throw newError('Transaction timeout should not be zero') } if (timeout.isNegative()) { - throw newError('Transaction timeout should not be negative'); + throw newError('Transaction timeout should not be negative') } - return timeout; + return timeout } - return null; + return null } /** * @return {object|null} */ -function extractMetadata(config) { +function extractMetadata (config) { if (util.isObject(config) && config.metadata) { - const metadata = config.metadata; - util.assertObject(metadata); + const metadata = config.metadata + util.assertObject(metadata) if (Object.keys(metadata).length !== 0) { // not an empty object - return metadata; + return metadata } } - return null; + return null } -function assertValidConfig(config) { +function assertValidConfig (config) { if (config) { - util.assertObject(config, 'Transaction config'); + util.assertObject(config, 'Transaction config') } } diff --git a/src/v1/internal/url-util.js b/src/v1/internal/url-util.js index b5b3ecd0a..4c95f97df 100644 --- a/src/v1/internal/url-util.js +++ b/src/v1/internal/url-util.js @@ -17,36 +17,35 @@ * limitations under the License. */ -import {parse as uriJsParse} from 'uri-js'; -import {assertString} from './util'; +import { parse as uriJsParse } from 'uri-js' +import { assertString } from './util' -const DEFAULT_BOLT_PORT = 7687; -const DEFAULT_HTTP_PORT = 7474; -const DEFAULT_HTTPS_PORT = 7473; +const DEFAULT_BOLT_PORT = 7687 +const DEFAULT_HTTP_PORT = 7474 +const DEFAULT_HTTPS_PORT = 7473 class Url { - - constructor(scheme, host, port, hostAndPort, query) { + constructor (scheme, host, port, hostAndPort, query) { /** * Nullable scheme (protocol) of the URL. * Example: 'bolt', 'bolt+routing', 'http', 'https', etc. * @type {string} */ - this.scheme = scheme; + this.scheme = scheme /** * Nonnull host name or IP address. IPv6 not wrapped in square brackets. * Example: 'neo4j.com', 'localhost', '127.0.0.1', '192.168.10.15', '::1', '2001:4860:4860::8844', etc. * @type {string} */ - this.host = host; + this.host = host /** * Nonnull number representing port. Default port for the given scheme is used if given URL string * does not contain port. Example: 7687 for bolt, 7474 for HTTP and 7473 for HTTPS. * @type {number} */ - this.port = port; + this.port = port /** * Nonnull host name or IP address plus port, separated by ':'. IPv6 wrapped in square brackets. @@ -54,145 +53,149 @@ class Url { * '[2001:4860:4860::8844]:9090', etc. * @type {string} */ - this.hostAndPort = hostAndPort; + this.hostAndPort = hostAndPort /** * Nonnull object representing parsed query string key-value pairs. Duplicated keys not supported. * Example: '{}', '{'key1': 'value1', 'key2': 'value2'}', etc. * @type {object} */ - this.query = query; + this.query = query } } -function parseDatabaseUrl(url) { - assertString(url, 'URL'); +function parseDatabaseUrl (url) { + assertString(url, 'URL') - const sanitized = sanitizeUrl(url); - const parsedUrl = uriJsParse(sanitized.url); + const sanitized = sanitizeUrl(url) + const parsedUrl = uriJsParse(sanitized.url) - const scheme = sanitized.schemeMissing ? null : extractScheme(parsedUrl.scheme); - const host = extractHost(parsedUrl.host); // no square brackets for IPv6 - const formattedHost = formatHost(host); // has square brackets for IPv6 - const port = extractPort(parsedUrl.port, scheme); - const hostAndPort = `${formattedHost}:${port}`; - const query = extractQuery(parsedUrl.query, url); + const scheme = sanitized.schemeMissing + ? null + : extractScheme(parsedUrl.scheme) + const host = extractHost(parsedUrl.host) // no square brackets for IPv6 + const formattedHost = formatHost(host) // has square brackets for IPv6 + const port = extractPort(parsedUrl.port, scheme) + const hostAndPort = `${formattedHost}:${port}` + const query = extractQuery(parsedUrl.query, url) - return new Url(scheme, host, port, hostAndPort, query); + return new Url(scheme, host, port, hostAndPort, query) } -function sanitizeUrl(url) { - url = url.trim(); +function sanitizeUrl (url) { + url = url.trim() if (url.indexOf('://') === -1) { // url does not contain scheme, add dummy 'none://' to make parser work correctly - return {schemeMissing: true, url: `none://${url}`}; + return { schemeMissing: true, url: `none://${url}` } } - return {schemeMissing: false, url: url}; + return { schemeMissing: false, url: url } } -function extractScheme(scheme) { +function extractScheme (scheme) { if (scheme) { - scheme = scheme.trim(); + scheme = scheme.trim() if (scheme.charAt(scheme.length - 1) === ':') { - scheme = scheme.substring(0, scheme.length - 1); + scheme = scheme.substring(0, scheme.length - 1) } - return scheme; + return scheme } - return null; + return null } -function extractHost(host, url) { +function extractHost (host, url) { if (!host) { - throw new Error(`Unable to extract host from ${url}`); + throw new Error(`Unable to extract host from ${url}`) } - return host.trim(); + return host.trim() } -function extractPort(portString, scheme) { - const port = parseInt(portString, 10); - return (port === 0 || port) ? port : defaultPortForScheme(scheme); +function extractPort (portString, scheme) { + const port = parseInt(portString, 10) + return port === 0 || port ? port : defaultPortForScheme(scheme) } -function extractQuery(queryString, url) { - const query = trimAndSanitizeQuery(queryString); - const context = {}; +function extractQuery (queryString, url) { + const query = trimAndSanitizeQuery(queryString) + const context = {} if (query) { query.split('&').forEach(pair => { - const keyValue = pair.split('='); + const keyValue = pair.split('=') if (keyValue.length !== 2) { - throw new Error(`Invalid parameters: '${keyValue}' in URL '${url}'.`); + throw new Error(`Invalid parameters: '${keyValue}' in URL '${url}'.`) } - const key = trimAndVerifyQueryElement(keyValue[0], 'key', url); - const value = trimAndVerifyQueryElement(keyValue[1], 'value', url); + const key = trimAndVerifyQueryElement(keyValue[0], 'key', url) + const value = trimAndVerifyQueryElement(keyValue[1], 'value', url) if (context[key]) { - throw new Error(`Duplicated query parameters with key '${key}' in URL '${url}'`); + throw new Error( + `Duplicated query parameters with key '${key}' in URL '${url}'` + ) } - context[key] = value; - }); + context[key] = value + }) } - return context; + return context } -function trimAndSanitizeQuery(query) { - query = (query || '').trim(); +function trimAndSanitizeQuery (query) { + query = (query || '').trim() if (query && query.charAt(0) === '?') { - query = query.substring(1, query.length); + query = query.substring(1, query.length) } - return query; + return query } -function trimAndVerifyQueryElement(element, name, url) { - element = (element || '').trim(); +function trimAndVerifyQueryElement (element, name, url) { + element = (element || '').trim() if (!element) { - throw new Error(`Illegal empty ${name} in URL query '${url}'`); + throw new Error(`Illegal empty ${name} in URL query '${url}'`) } - return element; + return element } -function escapeIPv6Address(address) { - const startsWithSquareBracket = address.charAt(0) === '['; - const endsWithSquareBracket = address.charAt(address.length - 1) === ']'; +function escapeIPv6Address (address) { + const startsWithSquareBracket = address.charAt(0) === '[' + const endsWithSquareBracket = address.charAt(address.length - 1) === ']' if (!startsWithSquareBracket && !endsWithSquareBracket) { - return `[${address}]`; + return `[${address}]` } else if (startsWithSquareBracket && endsWithSquareBracket) { - return address; + return address } else { - throw new Error(`Illegal IPv6 address ${address}`); + throw new Error(`Illegal IPv6 address ${address}`) } } -function formatHost(host) { +function formatHost (host) { if (!host) { - throw new Error(`Illegal host ${host}`); + throw new Error(`Illegal host ${host}`) } - const isIPv6Address = host.indexOf(':') >= 0; - return isIPv6Address ? escapeIPv6Address(host) : host; + const isIPv6Address = host.indexOf(':') >= 0 + return isIPv6Address ? escapeIPv6Address(host) : host } -function formatIPv4Address(address, port) { - return `${address}:${port}`; +function formatIPv4Address (address, port) { + return `${address}:${port}` } -function formatIPv6Address(address, port) { - const escapedAddress = escapeIPv6Address(address); - return `${escapedAddress}:${port}`; +function formatIPv6Address (address, port) { + const escapedAddress = escapeIPv6Address(address) + return `${escapedAddress}:${port}` } -function defaultPortForScheme(scheme) { +function defaultPortForScheme (scheme) { if (scheme === 'http') { - return DEFAULT_HTTP_PORT; + return DEFAULT_HTTP_PORT } else if (scheme === 'https') { - return DEFAULT_HTTPS_PORT; + return DEFAULT_HTTPS_PORT } else { - return DEFAULT_BOLT_PORT; + return DEFAULT_BOLT_PORT } } @@ -201,4 +204,4 @@ export default { defaultPortForScheme: defaultPortForScheme, formatIPv4Address: formatIPv4Address, formatIPv6Address: formatIPv6Address -}; +} diff --git a/src/v1/internal/util.js b/src/v1/internal/util.js index 63498584e..f08ce7a97 100644 --- a/src/v1/internal/util.js +++ b/src/v1/internal/util.js @@ -17,31 +17,31 @@ * limitations under the License. */ -import {isInt} from '../integer'; +import { isInt } from '../integer' -const ENCRYPTION_ON = "ENCRYPTION_ON"; -const ENCRYPTION_OFF = "ENCRYPTION_OFF"; +const ENCRYPTION_ON = 'ENCRYPTION_ON' +const ENCRYPTION_OFF = 'ENCRYPTION_OFF' -function isEmptyObjectOrNull(obj) { +function isEmptyObjectOrNull (obj) { if (obj === null) { - return true; + return true } if (!isObject(obj)) { - return false; + return false } for (let prop in obj) { if (obj.hasOwnProperty(prop)) { - return false; + return false } } - return true; + return true } -function isObject(obj) { - return typeof obj === 'object' && !Array.isArray(obj) && obj !== null; +function isObject (obj) { + return typeof obj === 'object' && !Array.isArray(obj) && obj !== null } /** @@ -51,76 +51,98 @@ function isObject(obj) { * @return {{query: string, params: object}} the normalized query with parameters. * @throws TypeError when either given query or parameters are invalid. */ -function validateStatementAndParameters(statement, parameters) { - let query = statement; - let params = parameters || {}; +function validateStatementAndParameters (statement, parameters) { + let query = statement + let params = parameters || {} if (typeof statement === 'object' && statement.text) { - query = statement.text; - params = statement.parameters || {}; + query = statement.text + params = statement.parameters || {} } - assertCypherStatement(query); - assertQueryParameters(params); + assertCypherStatement(query) + assertQueryParameters(params) - return {query, params}; + return { query, params } } -function assertObject(obj, objName) { +function assertObject (obj, objName) { if (!isObject(obj)) { - throw new TypeError(objName + ' expected to be an object but was: ' + JSON.stringify(obj)); + throw new TypeError( + objName + ' expected to be an object but was: ' + JSON.stringify(obj) + ) } - return obj; + return obj } -function assertString(obj, objName) { +function assertString (obj, objName) { if (!isString(obj)) { - throw new TypeError(objName + ' expected to be string but was: ' + JSON.stringify(obj)); + throw new TypeError( + objName + ' expected to be string but was: ' + JSON.stringify(obj) + ) } - return obj; + return obj } -function assertNumber(obj, objName) { +function assertNumber (obj, objName) { if (typeof obj !== 'number') { - throw new TypeError(objName + ' expected to be a number but was: ' + JSON.stringify(obj)); + throw new TypeError( + objName + ' expected to be a number but was: ' + JSON.stringify(obj) + ) } - return obj; + return obj } -function assertNumberOrInteger(obj, objName) { +function assertNumberOrInteger (obj, objName) { if (typeof obj !== 'number' && !isInt(obj)) { - throw new TypeError(objName + ' expected to be either a number or an Integer object but was: ' + JSON.stringify(obj)); + throw new TypeError( + objName + + ' expected to be either a number or an Integer object but was: ' + + JSON.stringify(obj) + ) } - return obj; + return obj } -function assertValidDate(obj, objName) { +function assertValidDate (obj, objName) { if (Object.prototype.toString.call(obj) !== '[object Date]') { - throw new TypeError(objName + ' expected to be a standard JavaScript Date but was: ' + JSON.stringify(obj)); + throw new TypeError( + objName + + ' expected to be a standard JavaScript Date but was: ' + + JSON.stringify(obj) + ) } if (Number.isNaN(obj.getTime())) { - throw new TypeError(objName + ' expected to be valid JavaScript Date but its time was NaN: ' + JSON.stringify(obj)); + throw new TypeError( + objName + + ' expected to be valid JavaScript Date but its time was NaN: ' + + JSON.stringify(obj) + ) } - return obj; + return obj } -function assertCypherStatement(obj) { - assertString(obj, 'Cypher statement'); +function assertCypherStatement (obj) { + assertString(obj, 'Cypher statement') if (obj.trim().length === 0) { - throw new TypeError('Cypher statement is expected to be a non-empty string.'); + throw new TypeError( + 'Cypher statement is expected to be a non-empty string.' + ) } } -function assertQueryParameters(obj) { +function assertQueryParameters (obj) { if (!isObject(obj)) { // objects created with `Object.create(null)` do not have a constructor property - const constructor = obj.constructor ? ' ' + obj.constructor.name : ''; - throw new TypeError(`Query parameters are expected to either be undefined/null or an object, given:${constructor} ${obj}`); + const constructor = obj.constructor ? ' ' + obj.constructor.name : '' + throw new TypeError( + `Query parameters are expected to either be undefined/null or an object, given:${constructor} ${obj}` + ) } } -function isString(str) { - return Object.prototype.toString.call(str) === '[object String]'; +function isString (str) { + return Object.prototype.toString.call(str) === '[object String]' } export { diff --git a/src/v1/record.js b/src/v1/record.js index 9691528e5..29bd7f9de 100644 --- a/src/v1/record.js +++ b/src/v1/record.js @@ -17,12 +17,14 @@ * limitations under the License. */ -import {newError} from './error'; +import { newError } from './error' -function generateFieldLookup( keys ) { - let lookup = {}; - keys.forEach( (name, idx) => { lookup[name] = idx; }); - return lookup; +function generateFieldLookup (keys) { + let lookup = {} + keys.forEach((name, idx) => { + lookup[name] = idx + }) + return lookup } /** @@ -55,11 +57,11 @@ class Record { * field names to values. If this is null, one will be * generated. */ - constructor(keys, fields, fieldLookup=null ) { - this.keys = keys; - this.length = keys.length; - this._fields = fields; - this._fieldLookup = fieldLookup || generateFieldLookup( keys ); + constructor (keys, fields, fieldLookup = null) { + this.keys = keys + this.length = keys.length + this._fields = fields + this._fieldLookup = fieldLookup || generateFieldLookup(keys) } /** @@ -69,9 +71,9 @@ class Record { * * @param {function(value: Object, key: string, record: Record)} visitor the function to apply to each field. */ - forEach( visitor ) { - for(let i=0;i { object[key] = value - }); + }) - return object; + return object } /** @@ -95,23 +97,33 @@ class Record { * @param {string|Number} key Field key, or the index of the field. * @returns {*} */ - get( key ) { - let index; - if( !(typeof key === "number") ) { - index = this._fieldLookup[key]; - if( index === undefined ) { - throw newError("This record has no field with key '"+key+"', available key are: [" + this.keys + "]."); + get (key) { + let index + if (!(typeof key === 'number')) { + index = this._fieldLookup[key] + if (index === undefined) { + throw newError( + "This record has no field with key '" + + key + + "', available key are: [" + + this.keys + + '].' + ) } } else { - index = key; + index = key } - if( index > this._fields.length - 1 || index < 0 ) { - throw newError("This record has no field with index '"+index+"'. Remember that indexes start at `0`, " + - "and make sure your statement returns records in the shape you meant it to."); + if (index > this._fields.length - 1 || index < 0) { + throw newError( + "This record has no field with index '" + + index + + "'. Remember that indexes start at `0`, " + + 'and make sure your statement returns records in the shape you meant it to.' + ) } - return this._fields[index]; + return this._fields[index] } /** @@ -120,14 +132,14 @@ class Record { * @param {string|Number} key Field key, or the index of the field. * @returns {boolean} */ - has( key ) { + has (key) { // if key is a number, we check if it is in the _fields array - if( typeof key === "number" ) { - return ( key >= 0 && key < this._fields.length ); + if (typeof key === 'number') { + return key >= 0 && key < this._fields.length } // if it's not a number, we check _fieldLookup dictionary directly - return this._fieldLookup[key] !== undefined; + return this._fieldLookup[key] !== undefined } } diff --git a/src/v1/result-summary.js b/src/v1/result-summary.js index fe8cb21bd..d5dee4a1c 100644 --- a/src/v1/result-summary.js +++ b/src/v1/result-summary.js @@ -17,12 +17,12 @@ * limitations under the License. */ -import {isInt} from './integer'; +import { isInt } from './integer' /** * A ResultSummary instance contains structured metadata for a {@link Result}. - * @access public - */ + * @access public + */ class ResultSummary { /** * @constructor @@ -30,13 +30,13 @@ class ResultSummary { * @param {Object} parameters - Parameters for the statement * @param {Object} metadata - Statement metadata */ - constructor(statement, parameters, metadata) { + constructor (statement, parameters, metadata) { /** * The statement and parameters this summary is for. * @type {{text: string, parameters: Object}} * @public */ - this.statement = {text: statement, parameters}; + this.statement = { text: statement, parameters } /** * The type of statement executed. Can be "r" for read-only statement, "rw" for read-write statement, @@ -45,16 +45,16 @@ class ResultSummary { * @type {string} * @public */ - this.statementType = metadata.type; + this.statementType = metadata.type /** * Counters for operations the statement triggered. * @type {StatementStatistics} * @public */ - this.counters = new StatementStatistics(metadata.stats || {}); - //for backwards compatibility, remove in future version - this.updateStatistics = this.counters; + this.counters = new StatementStatistics(metadata.stats || {}) + // for backwards compatibility, remove in future version + this.updateStatistics = this.counters /** * This describes how the database will execute the statement. @@ -62,7 +62,10 @@ class ResultSummary { * Will only be populated for queries that start with "EXPLAIN". * @type {Plan} */ - this.plan = metadata.plan || metadata.profile ? new Plan(metadata.plan || metadata.profile) : false; + this.plan = + metadata.plan || metadata.profile + ? new Plan(metadata.plan || metadata.profile) + : false /** * This describes how the database did execute your statement. This will contain detailed information about what @@ -71,7 +74,7 @@ class ResultSummary { * @type {ProfiledPlan} * @public */ - this.profile = metadata.profile ? new ProfiledPlan(metadata.profile) : false; + this.profile = metadata.profile ? new ProfiledPlan(metadata.profile) : false /** * An array of notifications that might arise when executing the statement. Notifications can be warnings about @@ -80,42 +83,44 @@ class ResultSummary { * @type {Array} * @public */ - this.notifications = this._buildNotifications(metadata.notifications); + this.notifications = this._buildNotifications(metadata.notifications) /** * The basic information of the server where the result is obtained from. * @type {ServerInfo} * @public */ - this.server = new ServerInfo(metadata.server); + this.server = new ServerInfo(metadata.server) /** * The time it took the server to consume the result. * @type {number} * @public */ - this.resultConsumedAfter = metadata.result_consumed_after; + this.resultConsumedAfter = metadata.result_consumed_after /** * The time it took the server to make the result available for consumption in milliseconds. * @type {number} * @public */ - this.resultAvailableAfter = metadata.result_available_after; + this.resultAvailableAfter = metadata.result_available_after } - _buildNotifications(notifications) { - if(!notifications) { - return []; + _buildNotifications (notifications) { + if (!notifications) { + return [] } - return notifications.map(function(n) { return new Notification(n) }); + return notifications.map(function (n) { + return new Notification(n) + }) } /** * Check if the result summary has a plan * @return {boolean} */ - hasPlan() { + hasPlan () { return this.plan instanceof Plan } @@ -123,60 +128,64 @@ class ResultSummary { * Check if the result summary has a profile * @return {boolean} */ - hasProfile() { + hasProfile () { return this.profile instanceof ProfiledPlan } } /** - * Class for execution plan received by prepending Cypher with EXPLAIN. - * @access public - */ + * Class for execution plan received by prepending Cypher with EXPLAIN. + * @access public + */ class Plan { /** * Create a Plan instance * @constructor * @param {Object} plan - Object with plan data */ - constructor(plan) { - this.operatorType = plan.operatorType; - this.identifiers = plan.identifiers; - this.arguments = plan.args; - this.children = plan.children ? plan.children.map((child) => new Plan(child)) : []; + constructor (plan) { + this.operatorType = plan.operatorType + this.identifiers = plan.identifiers + this.arguments = plan.args + this.children = plan.children + ? plan.children.map(child => new Plan(child)) + : [] } } /** - * Class for execution plan received by prepending Cypher with PROFILE. - * @access public - */ + * Class for execution plan received by prepending Cypher with PROFILE. + * @access public + */ class ProfiledPlan { /** * Create a ProfiledPlan instance * @constructor * @param {Object} profile - Object with profile data */ - constructor(profile) { - this.operatorType = profile.operatorType; - this.identifiers = profile.identifiers; - this.arguments = profile.args; - this.dbHits = profile.args.DbHits.toInt(); - this.rows = profile.args.Rows.toInt(); - this.children = profile.children ? profile.children.map((child) => new ProfiledPlan(child)) : []; + constructor (profile) { + this.operatorType = profile.operatorType + this.identifiers = profile.identifiers + this.arguments = profile.args + this.dbHits = profile.args.DbHits.toInt() + this.rows = profile.args.Rows.toInt() + this.children = profile.children + ? profile.children.map(child => new ProfiledPlan(child)) + : [] } } /** - * Get statistical information for a {@link Result}. - * @access public - */ + * Get statistical information for a {@link Result}. + * @access public + */ class StatementStatistics { /** * Structurize the statistics * @constructor * @param {Object} statistics - Result statistics */ - constructor(statistics) { + constructor (statistics) { this._stats = { nodesCreated: 0, nodesDeleted: 0, @@ -189,123 +198,128 @@ class StatementStatistics { indexesRemoved: 0, constraintsAdded: 0, constraintsRemoved: 0 - }; - Object.keys(statistics).forEach((index) => { - //To camelCase - this._stats[index.replace(/(\-\w)/g, (m) => m[1].toUpperCase())] = - isInt(statistics[index]) ? statistics[index].toInt() : statistics[index]; - }); + } + Object.keys(statistics).forEach(index => { + // To camelCase + this._stats[index.replace(/(-\w)/g, m => m[1].toUpperCase())] = isInt( + statistics[index] + ) + ? statistics[index].toInt() + : statistics[index] + }) } /** * Did the database get updated? * @return {boolean} */ - containsUpdates() { - return Object.keys(this._stats).reduce((last, current) => { - return last + this._stats[current]; - }, 0) > 0; + containsUpdates () { + return ( + Object.keys(this._stats).reduce((last, current) => { + return last + this._stats[current] + }, 0) > 0 + ) } /** * @return {Number} - Number of nodes created. */ - nodesCreated() { - return this._stats.nodesCreated; + nodesCreated () { + return this._stats.nodesCreated } /** * @return {Number} - Number of nodes deleted. */ - nodesDeleted() { - return this._stats.nodesDeleted; + nodesDeleted () { + return this._stats.nodesDeleted } /** * @return {Number} - Number of relationships created. */ - relationshipsCreated() { - return this._stats.relationshipsCreated; + relationshipsCreated () { + return this._stats.relationshipsCreated } /** * @return {Number} - Number of nodes deleted. */ - relationshipsDeleted() { - return this._stats.relationshipsDeleted; + relationshipsDeleted () { + return this._stats.relationshipsDeleted } /** * @return {Number} - Number of properties set. */ - propertiesSet() { - return this._stats.propertiesSet; + propertiesSet () { + return this._stats.propertiesSet } /** * @return {Number} - Number of labels added. */ - labelsAdded() { - return this._stats.labelsAdded; + labelsAdded () { + return this._stats.labelsAdded } /** * @return {Number} - Number of labels removed. */ - labelsRemoved() { - return this._stats.labelsRemoved; + labelsRemoved () { + return this._stats.labelsRemoved } /** * @return {Number} - Number of indexes added. */ - indexesAdded() { - return this._stats.indexesAdded; + indexesAdded () { + return this._stats.indexesAdded } /** * @return {Number} - Number of indexes removed. */ - indexesRemoved() { - return this._stats.indexesRemoved; + indexesRemoved () { + return this._stats.indexesRemoved } /** * @return {Number} - Number of constraints added. */ - constraintsAdded() { - return this._stats.constraintsAdded; + constraintsAdded () { + return this._stats.constraintsAdded } /** * @return {Number} - Number of constraints removed. */ - constraintsRemoved() { - return this._stats.constraintsRemoved; + constraintsRemoved () { + return this._stats.constraintsRemoved } } /** - * Class for Cypher notifications - * @access public - */ + * Class for Cypher notifications + * @access public + */ class Notification { /** * Create a Notification instance * @constructor * @param {Object} notification - Object with notification data */ - constructor(notification) { - this.code = notification.code; - this.title = notification.title; - this.description = notification.description; - this.severity = notification.severity; - this.position = Notification._constructPosition(notification.position); + constructor (notification) { + this.code = notification.code + this.title = notification.title + this.description = notification.description + this.severity = notification.severity + this.position = Notification._constructPosition(notification.position) } - static _constructPosition(pos) { - if(!pos) { - return {}; + static _constructPosition (pos) { + if (!pos) { + return {} } return { offset: pos.offset.toInt(), @@ -316,19 +330,19 @@ class Notification { } /** - * Class for exposing server info from a result. - * @access public - */ + * Class for exposing server info from a result. + * @access public + */ class ServerInfo { /** * Create a ServerInfo instance * @constructor * @param {Object} serverMeta - Object with serverMeta data */ - constructor(serverMeta) { + constructor (serverMeta) { if (serverMeta) { - this.address = serverMeta.address; - this.version = serverMeta.version; + this.address = serverMeta.address + this.version = serverMeta.version } } } @@ -338,10 +352,8 @@ const statementType = { READ_WRITE: 'rw', WRITE_ONLY: 'w', SCHEMA_WRITE: 's' -}; - -export { - statementType } +export { statementType } + export default ResultSummary diff --git a/src/v1/result.js b/src/v1/result.js index cfb0ed7db..a09f55b0c 100644 --- a/src/v1/result.js +++ b/src/v1/result.js @@ -17,14 +17,13 @@ * limitations under the License. */ -import ResultSummary from './result-summary'; -import {EMPTY_CONNECTION_HOLDER} from './internal/connection-holder'; +import ResultSummary from './result-summary' +import { EMPTY_CONNECTION_HOLDER } from './internal/connection-holder' const DEFAULT_ON_ERROR = error => { - console.log('Uncaught error when processing result: ' + error); -}; -const DEFAULT_ON_COMPLETED = summary => { -}; + console.log('Uncaught error when processing result: ' + error) +} +const DEFAULT_ON_COMPLETED = summary => {} /** * A stream of {@link Record} representing the result of a statement. @@ -44,14 +43,24 @@ class Result { * @param metaSupplier function, when called provides metadata * @param {ConnectionHolder} connectionHolder - to be notified when result is either fully consumed or error happened. */ - constructor(streamObserver, statement, parameters, metaSupplier, connectionHolder) { - this._stack = captureStacktrace(); - this._streamObserver = streamObserver; - this._p = null; - this._statement = statement; - this._parameters = parameters || {}; - this._metaSupplier = metaSupplier || function(){return {};}; - this._connectionHolder = connectionHolder || EMPTY_CONNECTION_HOLDER; + constructor ( + streamObserver, + statement, + parameters, + metaSupplier, + connectionHolder + ) { + this._stack = captureStacktrace() + this._streamObserver = streamObserver + this._p = null + this._statement = statement + this._parameters = parameters || {} + this._metaSupplier = + metaSupplier || + function () { + return {} + } + this._connectionHolder = connectionHolder || EMPTY_CONNECTION_HOLDER } /** @@ -59,22 +68,26 @@ class Result { * @return {Promise} new Promise. * @access private */ - _createPromise() { - if(this._p) { - return; + _createPromise () { + if (this._p) { + return } - let self = this; + let self = this this._p = new Promise((resolve, reject) => { - let records = []; + let records = [] let observer = { - onNext: (record) => { records.push(record); }, - onCompleted: (summary) => { - resolve({records: records, summary: summary}); + onNext: record => { + records.push(record) }, - onError: (error) => { reject(error); } - }; - self.subscribe(observer); - }); + onCompleted: summary => { + resolve({ records: records, summary: summary }) + }, + onError: error => { + reject(error) + } + } + self.subscribe(observer) + }) } /** @@ -86,9 +99,9 @@ class Result { * @param {function(error: {message:string, code:string})} onRejected - function to be called upon errors. * @return {Promise} promise. */ - then(onFulfilled, onRejected) { - this._createPromise(); - return this._p.then(onFulfilled, onRejected); + then (onFulfilled, onRejected) { + this._createPromise() + return this._p.then(onFulfilled, onRejected) } /** @@ -97,9 +110,9 @@ class Result { * @param {function(error: Neo4jError)} onRejected - Function to be called upon errors. * @return {Promise} promise. */ - catch(onRejected) { - this._createPromise(); - return this._p.catch(onRejected); + catch (onRejected) { + this._createPromise() + return this._p.catch(onRejected) } /** @@ -112,56 +125,56 @@ class Result { * @param {function(error: {message:string, code:string})} observer.onError - handle errors. * @return */ - subscribe(observer) { - const self = this; + subscribe (observer) { + const self = this - const onCompletedOriginal = observer.onCompleted || DEFAULT_ON_COMPLETED; - const onCompletedWrapper = (metadata) => { - const additionalMeta = self._metaSupplier(); + const onCompletedOriginal = observer.onCompleted || DEFAULT_ON_COMPLETED + const onCompletedWrapper = metadata => { + const additionalMeta = self._metaSupplier() for (let key in additionalMeta) { if (additionalMeta.hasOwnProperty(key)) { - metadata[key] = additionalMeta[key]; + metadata[key] = additionalMeta[key] } } - const sum = new ResultSummary(this._statement, this._parameters, metadata); + const sum = new ResultSummary(this._statement, this._parameters, metadata) // notify connection holder that the used connection is not needed any more because result has // been fully consumed; call the original onCompleted callback after that self._connectionHolder.releaseConnection().then(() => { - onCompletedOriginal.call(observer, sum); - }); - }; - observer.onCompleted = onCompletedWrapper; + onCompletedOriginal.call(observer, sum) + }) + } + observer.onCompleted = onCompletedWrapper - const onErrorOriginal = observer.onError || DEFAULT_ON_ERROR; + const onErrorOriginal = observer.onError || DEFAULT_ON_ERROR const onErrorWrapper = error => { // notify connection holder that the used connection is not needed any more because error happened // and result can't bee consumed any further; call the original onError callback after that self._connectionHolder.releaseConnection().then(() => { - replaceStacktrace(error, this._stack); - onErrorOriginal.call(observer, error); - }); - }; - observer.onError = onErrorWrapper; + replaceStacktrace(error, this._stack) + onErrorOriginal.call(observer, error) + }) + } + observer.onError = onErrorWrapper - this._streamObserver.subscribe(observer); + this._streamObserver.subscribe(observer) } } -function captureStacktrace() { - const error = new Error(''); +function captureStacktrace () { + const error = new Error('') if (error.stack) { - return error.stack.replace(/^Error(\n\r)*/, ''); // we don't need the 'Error\n' part, if only it exists + return error.stack.replace(/^Error(\n\r)*/, '') // we don't need the 'Error\n' part, if only it exists } - return null; + return null } -function replaceStacktrace(error, newStack) { +function replaceStacktrace (error, newStack) { if (newStack) { // Error.prototype.toString() concatenates error.name and error.message nicely // then we add the rest of the stack trace - error.stack = error.toString() + '\n' + newStack; + error.stack = error.toString() + '\n' + newStack } } -export default Result; +export default Result diff --git a/src/v1/routing-driver.js b/src/v1/routing-driver.js index 265ba5d39..30e796986 100644 --- a/src/v1/routing-driver.js +++ b/src/v1/routing-driver.js @@ -17,53 +17,84 @@ * limitations under the License. */ -import {Driver} from './driver'; -import {newError, SESSION_EXPIRED} from './error'; -import {LoadBalancer} from './internal/connection-providers'; -import LeastConnectedLoadBalancingStrategy, {LEAST_CONNECTED_STRATEGY_NAME} from './internal/least-connected-load-balancing-strategy'; -import RoundRobinLoadBalancingStrategy, {ROUND_ROBIN_STRATEGY_NAME} from './internal/round-robin-load-balancing-strategy'; -import ConnectionErrorHandler from './internal/connection-error-handler'; -import ConfiguredCustomResolver from './internal/resolver/configured-custom-resolver'; +import { Driver } from './driver' +import { newError, SESSION_EXPIRED } from './error' +import { LoadBalancer } from './internal/connection-providers' +import LeastConnectedLoadBalancingStrategy, { + LEAST_CONNECTED_STRATEGY_NAME +} from './internal/least-connected-load-balancing-strategy' +import RoundRobinLoadBalancingStrategy, { + ROUND_ROBIN_STRATEGY_NAME +} from './internal/round-robin-load-balancing-strategy' +import ConnectionErrorHandler from './internal/connection-error-handler' +import ConfiguredCustomResolver from './internal/resolver/configured-custom-resolver' /** * A driver that supports routing in a causal cluster. * @private */ class RoutingDriver extends Driver { - - constructor(address, routingContext, userAgent, token = {}, config = {}) { - super(address, userAgent, token, validateConfig(config)); - this._routingContext = routingContext; + constructor (address, routingContext, userAgent, token = {}, config = {}) { + super(address, userAgent, token, validateConfig(config)) + this._routingContext = routingContext } - _afterConstruction() { - this._log.info(`Routing driver ${this._id} created for server address ${this._address}`); + _afterConstruction () { + this._log.info( + `Routing driver ${this._id} created for server address ${this._address}` + ) } - _createConnectionProvider(address, connectionPool, driverOnErrorCallback) { - const loadBalancingStrategy = RoutingDriver._createLoadBalancingStrategy(this._config, connectionPool); - const resolver = createHostNameResolver(this._config); - return new LoadBalancer(address, this._routingContext, connectionPool, loadBalancingStrategy, resolver, driverOnErrorCallback, this._log); + _createConnectionProvider (address, connectionPool, driverOnErrorCallback) { + const loadBalancingStrategy = RoutingDriver._createLoadBalancingStrategy( + this._config, + connectionPool + ) + const resolver = createHostNameResolver(this._config) + return new LoadBalancer( + address, + this._routingContext, + connectionPool, + loadBalancingStrategy, + resolver, + driverOnErrorCallback, + this._log + ) } - _createConnectionErrorHandler() { + _createConnectionErrorHandler () { // connection errors mean SERVICE_UNAVAILABLE for direct driver but for routing driver they should only // result in SESSION_EXPIRED because there might still exist other servers capable of serving the request - return new ConnectionErrorHandler(SESSION_EXPIRED, + return new ConnectionErrorHandler( + SESSION_EXPIRED, (error, address) => this._handleUnavailability(error, address), - (error, address) => this._handleWriteFailure(error, address)); + (error, address) => this._handleWriteFailure(error, address) + ) } - _handleUnavailability(error, address) { - this._log.warn(`Routing driver ${this._id} will forget ${address} because of an error ${error.code} '${error.message}'`); - this._connectionProvider.forget(address); - return error; + _handleUnavailability (error, address) { + this._log.warn( + `Routing driver ${this._id} will forget ${address} because of an error ${ + error.code + } '${error.message}'` + ) + this._connectionProvider.forget(address) + return error } - _handleWriteFailure(error, address) { - this._log.warn(`Routing driver ${this._id} will forget writer ${address} because of an error ${error.code} '${error.message}'`); - this._connectionProvider.forgetWriter(address); - return newError('No longer possible to write to server at ' + address, SESSION_EXPIRED); + _handleWriteFailure (error, address) { + this._log.warn( + `Routing driver ${ + this._id + } will forget writer ${address} because of an error ${error.code} '${ + error.message + }'` + ) + this._connectionProvider.forgetWriter(address) + return newError( + 'No longer possible to write to server at ' + address, + SESSION_EXPIRED + ) } /** @@ -73,14 +104,14 @@ class RoutingDriver extends Driver { * @return {LoadBalancingStrategy} new strategy. * @private */ - static _createLoadBalancingStrategy(config, connectionPool) { - const configuredValue = config.loadBalancingStrategy; + static _createLoadBalancingStrategy (config, connectionPool) { + const configuredValue = config.loadBalancingStrategy if (!configuredValue || configuredValue === LEAST_CONNECTED_STRATEGY_NAME) { - return new LeastConnectedLoadBalancingStrategy(connectionPool); + return new LeastConnectedLoadBalancingStrategy(connectionPool) } else if (configuredValue === ROUND_ROBIN_STRATEGY_NAME) { - return new RoundRobinLoadBalancingStrategy(); + return new RoundRobinLoadBalancingStrategy() } else { - throw newError('Unknown load balancing strategy: ' + configuredValue); + throw newError('Unknown load balancing strategy: ' + configuredValue) } } } @@ -90,23 +121,27 @@ class RoutingDriver extends Driver { * @returns {ConfiguredCustomResolver} new custom resolver that wraps the passed-in resolver function. * If resolved function is not specified, it defaults to an identity resolver. */ -function createHostNameResolver(config) { - return new ConfiguredCustomResolver(config.resolver); +function createHostNameResolver (config) { + return new ConfiguredCustomResolver(config.resolver) } /** * @private * @returns {object} the given config. */ -function validateConfig(config) { +function validateConfig (config) { if (config.trust === 'TRUST_ON_FIRST_USE') { - throw newError('The chosen trust mode is not compatible with a routing driver'); + throw newError( + 'The chosen trust mode is not compatible with a routing driver' + ) } - const resolver = config.resolver; + const resolver = config.resolver if (resolver && typeof resolver !== 'function') { - throw new TypeError(`Configured resolver should be a function. Got: ${resolver}`); + throw new TypeError( + `Configured resolver should be a function. Got: ${resolver}` + ) } - return config; + return config } -export default RoutingDriver; +export default RoutingDriver diff --git a/src/v1/session.js b/src/v1/session.js index 4adbb494d..4f7e15af2 100644 --- a/src/v1/session.js +++ b/src/v1/session.js @@ -16,17 +16,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import StreamObserver from './internal/stream-observer'; -import Result from './result'; -import Transaction from './transaction'; -import {newError} from './error'; -import {validateStatementAndParameters} from './internal/util'; -import ConnectionHolder from './internal/connection-holder'; -import Driver from './driver'; -import {ACCESS_MODE_READ, ACCESS_MODE_WRITE} from './internal/constants'; -import TransactionExecutor from './internal/transaction-executor'; -import Bookmark from './internal/bookmark'; -import TxConfig from './internal/tx-config'; +import StreamObserver from './internal/stream-observer' +import Result from './result' +import Transaction from './transaction' +import { newError } from './error' +import { validateStatementAndParameters } from './internal/util' +import ConnectionHolder from './internal/connection-holder' +import Driver from './driver' +import { ACCESS_MODE_READ, ACCESS_MODE_WRITE } from './internal/constants' +import TransactionExecutor from './internal/transaction-executor' +import Bookmark from './internal/bookmark' +import TxConfig from './internal/tx-config' // Typedef for JSDoc. Declares TransactionConfig type and makes it possible to use in in method-level docs. /** @@ -55,7 +55,6 @@ import TxConfig from './internal/tx-config'; * @access public */ class Session { - /** * @constructor * @param {string} mode the default access mode for this session. @@ -63,14 +62,20 @@ class Session { * @param {Bookmark} bookmark - the initial bookmark for this session. * @param {Object} [config={}] - this driver configuration. */ - constructor(mode, connectionProvider, bookmark, config) { - this._mode = mode; - this._readConnectionHolder = new ConnectionHolder(ACCESS_MODE_READ, connectionProvider); - this._writeConnectionHolder = new ConnectionHolder(ACCESS_MODE_WRITE, connectionProvider); - this._open = true; - this._hasTx = false; - this._lastBookmark = bookmark; - this._transactionExecutor = _createTransactionExecutor(config); + constructor (mode, connectionProvider, bookmark, config) { + this._mode = mode + this._readConnectionHolder = new ConnectionHolder( + ACCESS_MODE_READ, + connectionProvider + ) + this._writeConnectionHolder = new ConnectionHolder( + ACCESS_MODE_WRITE, + connectionProvider + ) + this._open = true + this._hasTx = false + this._lastBookmark = bookmark + this._transactionExecutor = _createTransactionExecutor(config) } /** @@ -82,29 +87,54 @@ class Session { * @param {TransactionConfig} [transactionConfig] - configuration for the new auto-commit transaction. * @return {Result} - New Result */ - run(statement, parameters, transactionConfig) { - const {query, params} = validateStatementAndParameters(statement, parameters); - const autoCommitTxConfig = transactionConfig ? new TxConfig(transactionConfig) : TxConfig.empty(); + run (statement, parameters, transactionConfig) { + const { query, params } = validateStatementAndParameters( + statement, + parameters + ) + const autoCommitTxConfig = transactionConfig + ? new TxConfig(transactionConfig) + : TxConfig.empty() return this._run(query, params, (connection, streamObserver) => - connection.protocol().run(query, params, this._lastBookmark, autoCommitTxConfig, this._mode, streamObserver) - ); + connection + .protocol() + .run( + query, + params, + this._lastBookmark, + autoCommitTxConfig, + this._mode, + streamObserver + ) + ) } - _run(statement, parameters, statementRunner) { - const streamObserver = new SessionStreamObserver(this); - const connectionHolder = this._connectionHolderWithMode(this._mode); + _run (statement, parameters, statementRunner) { + const streamObserver = new SessionStreamObserver(this) + const connectionHolder = this._connectionHolderWithMode(this._mode) if (!this._hasTx) { - connectionHolder.initializeConnection(); - connectionHolder.getConnection(streamObserver) + connectionHolder.initializeConnection() + connectionHolder + .getConnection(streamObserver) .then(connection => statementRunner(connection, streamObserver)) - .catch(error => streamObserver.onError(error)); + .catch(error => streamObserver.onError(error)) } else { - streamObserver.onError(newError('Statements cannot be run directly on a ' + - 'session with an open transaction; either run from within the ' + - 'transaction or use a different session.')); + streamObserver.onError( + newError( + 'Statements cannot be run directly on a ' + + 'session with an open transaction; either run from within the ' + + 'transaction or use a different session.' + ) + ) } - return new Result(streamObserver, statement, parameters, () => streamObserver.serverMetadata(), connectionHolder); + return new Result( + streamObserver, + statement, + parameters, + () => streamObserver.serverMetadata(), + connectionHolder + ) } /** @@ -116,43 +146,53 @@ class Session { * @param {TransactionConfig} [transactionConfig] - configuration for the new auto-commit transaction. * @returns {Transaction} - New Transaction */ - beginTransaction(transactionConfig) { + beginTransaction (transactionConfig) { // this function needs to support bookmarks parameter for backwards compatibility // parameter was of type {string|string[]} and represented either a single or multiple bookmarks // that's why we need to check parameter type and decide how to interpret the value - const arg = transactionConfig; + const arg = transactionConfig - let txConfig = TxConfig.empty(); - if (typeof arg === 'string' || arg instanceof String || Array.isArray(arg)) { + let txConfig = TxConfig.empty() + if ( + typeof arg === 'string' || + arg instanceof String || + Array.isArray(arg) + ) { // argument looks like a single or multiple bookmarks // bookmarks in this function are deprecated but need to be supported for backwards compatibility - this._updateBookmark(new Bookmark(arg)); + this._updateBookmark(new Bookmark(arg)) } else if (arg) { // argument is probably a transaction configuration - txConfig = new TxConfig(arg); + txConfig = new TxConfig(arg) } - return this._beginTransaction(this._mode, txConfig); + return this._beginTransaction(this._mode, txConfig) } - _beginTransaction(accessMode, txConfig) { + _beginTransaction (accessMode, txConfig) { if (this._hasTx) { - throw newError('You cannot begin a transaction on a session with an open transaction; ' + - 'either run from within the transaction or use a different session.'); + throw newError( + 'You cannot begin a transaction on a session with an open transaction; ' + + 'either run from within the transaction or use a different session.' + ) } - const mode = Driver._validateSessionMode(accessMode); - const connectionHolder = this._connectionHolderWithMode(mode); - connectionHolder.initializeConnection(); - this._hasTx = true; + const mode = Driver._validateSessionMode(accessMode) + const connectionHolder = this._connectionHolderWithMode(mode) + connectionHolder.initializeConnection() + this._hasTx = true - const tx = new Transaction(connectionHolder, this._transactionClosed.bind(this), this._updateBookmark.bind(this)); - tx._begin(this._lastBookmark, txConfig); - return tx; + const tx = new Transaction( + connectionHolder, + this._transactionClosed.bind(this), + this._updateBookmark.bind(this) + ) + tx._begin(this._lastBookmark, txConfig) + return tx } - _transactionClosed() { - this._hasTx = false; + _transactionClosed () { + this._hasTx = false } /** @@ -160,8 +200,8 @@ class Session { * * @return {string|null} a reference to a previous transaction */ - lastBookmark() { - return this._lastBookmark.maxBookmarkAsString(); + lastBookmark () { + return this._lastBookmark.maxBookmarkAsString() } /** @@ -178,9 +218,9 @@ class Session { * @return {Promise} resolved promise as returned by the given function or rejected promise when given * function or commit fails. */ - readTransaction(transactionWork, transactionConfig) { - const config = new TxConfig(transactionConfig); - return this._runTransaction(ACCESS_MODE_READ, config, transactionWork); + readTransaction (transactionWork, transactionConfig) { + const config = new TxConfig(transactionConfig) + return this._runTransaction(ACCESS_MODE_READ, config, transactionWork) } /** @@ -197,25 +237,25 @@ class Session { * @return {Promise} resolved promise as returned by the given function or rejected promise when given * function or commit fails. */ - writeTransaction(transactionWork, transactionConfig) { - const config = new TxConfig(transactionConfig); - return this._runTransaction(ACCESS_MODE_WRITE, config, transactionWork); + writeTransaction (transactionWork, transactionConfig) { + const config = new TxConfig(transactionConfig) + return this._runTransaction(ACCESS_MODE_WRITE, config, transactionWork) } - _runTransaction(accessMode, transactionConfig, transactionWork) { + _runTransaction (accessMode, transactionConfig, transactionWork) { return this._transactionExecutor.execute( () => this._beginTransaction(accessMode, transactionConfig), transactionWork - ); + ) } /** * Update value of the last bookmark. * @param {Bookmark} newBookmark the new bookmark. */ - _updateBookmark(newBookmark) { + _updateBookmark (newBookmark) { if (newBookmark && !newBookmark.isEmpty()) { - this._lastBookmark = newBookmark; + this._lastBookmark = newBookmark } } @@ -224,27 +264,27 @@ class Session { * @param {function()} callback - Function to be called after the session has been closed * @return */ - close(callback = (() => null)) { + close (callback = () => null) { if (this._open) { - this._open = false; - this._transactionExecutor.close(); + this._open = false + this._transactionExecutor.close() this._readConnectionHolder.close().then(() => { this._writeConnectionHolder.close().then(() => { - callback(); - }); - }); + callback() + }) + }) } else { - callback(); + callback() } } - _connectionHolderWithMode(mode) { + _connectionHolderWithMode (mode) { if (mode === ACCESS_MODE_READ) { - return this._readConnectionHolder; + return this._readConnectionHolder } else if (mode === ACCESS_MODE_WRITE) { - return this._writeConnectionHolder; + return this._writeConnectionHolder } else { - throw newError('Unknown access mode: ' + mode); + throw newError('Unknown access mode: ' + mode) } } } @@ -253,22 +293,24 @@ class Session { * @private */ class SessionStreamObserver extends StreamObserver { - - constructor(session) { - super(); - this._session = session; + constructor (session) { + super() + this._session = session } - onCompleted(meta) { - super.onCompleted(meta); - const bookmark = new Bookmark(meta.bookmark); - this._session._updateBookmark(bookmark); + onCompleted (meta) { + super.onCompleted(meta) + const bookmark = new Bookmark(meta.bookmark) + this._session._updateBookmark(bookmark) } } -function _createTransactionExecutor(config) { - const maxRetryTimeMs = (config && config.maxTransactionRetryTime) ? config.maxTransactionRetryTime : null; - return new TransactionExecutor(maxRetryTimeMs); +function _createTransactionExecutor (config) { + const maxRetryTimeMs = + config && config.maxTransactionRetryTime + ? config.maxTransactionRetryTime + : null + return new TransactionExecutor(maxRetryTimeMs) } -export default Session; +export default Session diff --git a/src/v1/spatial-types.js b/src/v1/spatial-types.js index 7ad516d1d..af0654fc6 100644 --- a/src/v1/spatial-types.js +++ b/src/v1/spatial-types.js @@ -16,16 +16,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {assertNumber, assertNumberOrInteger} from './internal/util'; +import { assertNumber, assertNumberOrInteger } from './internal/util' -const POINT_IDENTIFIER_PROPERTY = '__isPoint__'; +const POINT_IDENTIFIER_PROPERTY = '__isPoint__' /** * Represents a single two or three-dimensional point in a particular coordinate reference system. * Created `Point` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class Point { - /** * @constructor * @param {Integer|number} srid the coordinate reference system identifier. @@ -33,36 +32,40 @@ export class Point { * @param {number} y the `y` coordinate of the point. * @param {number} [z=undefined] the `y` coordinate of the point or `undefined` if point has 2 dimensions. */ - constructor(srid, x, y, z) { - this.srid = assertNumberOrInteger(srid, 'SRID'); - this.x = assertNumber(x, 'X coordinate'); - this.y = assertNumber(y, 'Y coordinate'); - this.z = (z === null || z === undefined) ? z : assertNumber(z, 'Z coordinate'); - Object.freeze(this); + constructor (srid, x, y, z) { + this.srid = assertNumberOrInteger(srid, 'SRID') + this.x = assertNumber(x, 'X coordinate') + this.y = assertNumber(y, 'Y coordinate') + this.z = z === null || z === undefined ? z : assertNumber(z, 'Z coordinate') + Object.freeze(this) } - toString() { + toString () { return this.z || this.z === 0 - ? `Point{srid=${formatAsFloat(this.srid)}, x=${formatAsFloat(this.x)}, y=${formatAsFloat(this.y)}, z=${formatAsFloat(this.z)}}` - : `Point{srid=${formatAsFloat(this.srid)}, x=${formatAsFloat(this.x)}, y=${formatAsFloat(this.y)}}`; + ? `Point{srid=${formatAsFloat(this.srid)}, x=${formatAsFloat( + this.x + )}, y=${formatAsFloat(this.y)}, z=${formatAsFloat(this.z)}}` + : `Point{srid=${formatAsFloat(this.srid)}, x=${formatAsFloat( + this.x + )}, y=${formatAsFloat(this.y)}}` } } -function formatAsFloat(number) { - return Number.isInteger(number) ? number + '.0' : number.toString(); +function formatAsFloat (number) { + return Number.isInteger(number) ? number + '.0' : number.toString() } Object.defineProperty(Point.prototype, POINT_IDENTIFIER_PROPERTY, { value: true, enumerable: false, configurable: false -}); +}) /** * Test if given object is an instance of {@link Point} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link Point}, `false` otherwise. */ -export function isPoint(obj) { - return (obj && obj[POINT_IDENTIFIER_PROPERTY]) === true; +export function isPoint (obj) { + return (obj && obj[POINT_IDENTIFIER_PROPERTY]) === true } diff --git a/src/v1/temporal-types.js b/src/v1/temporal-types.js index 7e3988e35..467dbd9c9 100644 --- a/src/v1/temporal-types.js +++ b/src/v1/temporal-types.js @@ -17,29 +17,32 @@ * limitations under the License. */ -import * as util from './internal/temporal-util'; -import {assertNumberOrInteger, assertString, assertValidDate} from './internal/util'; -import {newError} from './error'; +import * as util from './internal/temporal-util' +import { + assertNumberOrInteger, + assertString, + assertValidDate +} from './internal/util' +import { newError } from './error' const IDENTIFIER_PROPERTY_ATTRIBUTES = { value: true, enumerable: false, configurable: false -}; +} -const DURATION_IDENTIFIER_PROPERTY = '__isDuration__'; -const LOCAL_TIME_IDENTIFIER_PROPERTY = '__isLocalTime__'; -const TIME_IDENTIFIER_PROPERTY = '__isTime__'; -const DATE_IDENTIFIER_PROPERTY = '__isDate__'; -const LOCAL_DATE_TIME_IDENTIFIER_PROPERTY = '__isLocalDateTime__'; -const DATE_TIME_IDENTIFIER_PROPERTY = '__isDateTime__'; +const DURATION_IDENTIFIER_PROPERTY = '__isDuration__' +const LOCAL_TIME_IDENTIFIER_PROPERTY = '__isLocalTime__' +const TIME_IDENTIFIER_PROPERTY = '__isTime__' +const DATE_IDENTIFIER_PROPERTY = '__isDate__' +const LOCAL_DATE_TIME_IDENTIFIER_PROPERTY = '__isLocalDateTime__' +const DATE_TIME_IDENTIFIER_PROPERTY = '__isDateTime__' /** * Represents an ISO 8601 duration. Contains both date-based values (years, months, days) and time-based values (seconds, nanoseconds). * Created `Duration` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class Duration { - /** * @constructor * @param {Integer|number} months the number of months for the new duration. @@ -47,30 +50,39 @@ export class Duration { * @param {Integer|number} seconds the number of seconds for the new duration. * @param {Integer|number} nanoseconds the number of nanoseconds for the new duration. */ - constructor(months, days, seconds, nanoseconds) { - this.months = assertNumberOrInteger(months, 'Months'); - this.days = assertNumberOrInteger(days, 'Days'); - assertNumberOrInteger(seconds, 'Seconds'); - assertNumberOrInteger(nanoseconds, 'Nanoseconds'); - this.seconds = util.normalizeSecondsForDuration(seconds, nanoseconds); - this.nanoseconds = util.normalizeNanosecondsForDuration(nanoseconds); - Object.freeze(this); + constructor (months, days, seconds, nanoseconds) { + this.months = assertNumberOrInteger(months, 'Months') + this.days = assertNumberOrInteger(days, 'Days') + assertNumberOrInteger(seconds, 'Seconds') + assertNumberOrInteger(nanoseconds, 'Nanoseconds') + this.seconds = util.normalizeSecondsForDuration(seconds, nanoseconds) + this.nanoseconds = util.normalizeNanosecondsForDuration(nanoseconds) + Object.freeze(this) } - toString() { - return util.durationToIsoString(this.months, this.days, this.seconds, this.nanoseconds); + toString () { + return util.durationToIsoString( + this.months, + this.days, + this.seconds, + this.nanoseconds + ) } } -Object.defineProperty(Duration.prototype, DURATION_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES); +Object.defineProperty( + Duration.prototype, + DURATION_IDENTIFIER_PROPERTY, + IDENTIFIER_PROPERTY_ATTRIBUTES +) /** * Test if given object is an instance of {@link Duration} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link Duration}, `false` otherwise. */ -export function isDuration(obj) { - return hasIdentifierProperty(obj, DURATION_IDENTIFIER_PROPERTY); +export function isDuration (obj) { + return hasIdentifierProperty(obj, DURATION_IDENTIFIER_PROPERTY) } /** @@ -78,7 +90,6 @@ export function isDuration(obj) { * Created `LocalTime` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class LocalTime { - /** * @constructor * @param {Integer|number} hour the hour for the new local time. @@ -86,12 +97,12 @@ export class LocalTime { * @param {Integer|number} second the second for the new local time. * @param {Integer|number} nanosecond the nanosecond for the new local time. */ - constructor(hour, minute, second, nanosecond) { - this.hour = util.assertValidHour(hour); - this.minute = util.assertValidMinute(minute); - this.second = util.assertValidSecond(second); - this.nanosecond = util.assertValidNanosecond(nanosecond); - Object.freeze(this); + constructor (hour, minute, second, nanosecond) { + this.hour = util.assertValidHour(hour) + this.minute = util.assertValidMinute(minute) + this.second = util.assertValidSecond(second) + this.nanosecond = util.assertValidNanosecond(nanosecond) + Object.freeze(this) } /** @@ -101,30 +112,40 @@ export class LocalTime { * @param {Integer|number|undefined} nanosecond the optional amount of nanoseconds. * @return {LocalTime} new local time. */ - static fromStandardDate(standardDate, nanosecond) { - verifyStandardDateAndNanos(standardDate, nanosecond); + static fromStandardDate (standardDate, nanosecond) { + verifyStandardDateAndNanos(standardDate, nanosecond) return new LocalTime( standardDate.getHours(), standardDate.getMinutes(), standardDate.getSeconds(), - util.totalNanoseconds(standardDate, nanosecond)); + util.totalNanoseconds(standardDate, nanosecond) + ) } - toString() { - return util.timeToIsoString(this.hour, this.minute, this.second, this.nanosecond); + toString () { + return util.timeToIsoString( + this.hour, + this.minute, + this.second, + this.nanosecond + ) } } -Object.defineProperty(LocalTime.prototype, LOCAL_TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES); +Object.defineProperty( + LocalTime.prototype, + LOCAL_TIME_IDENTIFIER_PROPERTY, + IDENTIFIER_PROPERTY_ATTRIBUTES +) /** * Test if given object is an instance of {@link LocalTime} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link LocalTime}, `false` otherwise. */ -export function isLocalTime(obj) { - return hasIdentifierProperty(obj, LOCAL_TIME_IDENTIFIER_PROPERTY); +export function isLocalTime (obj) { + return hasIdentifierProperty(obj, LOCAL_TIME_IDENTIFIER_PROPERTY) } /** @@ -132,7 +153,6 @@ export function isLocalTime(obj) { * Created `Time` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class Time { - /** * @constructor * @param {Integer|number} hour the hour for the new local time. @@ -142,13 +162,16 @@ export class Time { * @param {Integer|number} timeZoneOffsetSeconds the time zone offset in seconds. Value represents the difference, in seconds, from UTC to local time. * This is different from standard JavaScript `Date.getTimezoneOffset()` which is the difference, in minutes, from local time to UTC. */ - constructor(hour, minute, second, nanosecond, timeZoneOffsetSeconds) { - this.hour = util.assertValidHour(hour); - this.minute = util.assertValidMinute(minute); - this.second = util.assertValidSecond(second); - this.nanosecond = util.assertValidNanosecond(nanosecond); - this.timeZoneOffsetSeconds = assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds'); - Object.freeze(this); + constructor (hour, minute, second, nanosecond, timeZoneOffsetSeconds) { + this.hour = util.assertValidHour(hour) + this.minute = util.assertValidMinute(minute) + this.second = util.assertValidSecond(second) + this.nanosecond = util.assertValidNanosecond(nanosecond) + this.timeZoneOffsetSeconds = assertNumberOrInteger( + timeZoneOffsetSeconds, + 'Time zone offset in seconds' + ) + Object.freeze(this) } /** @@ -158,31 +181,43 @@ export class Time { * @param {Integer|number|undefined} nanosecond the optional amount of nanoseconds. * @return {Time} new time. */ - static fromStandardDate(standardDate, nanosecond) { - verifyStandardDateAndNanos(standardDate, nanosecond); + static fromStandardDate (standardDate, nanosecond) { + verifyStandardDateAndNanos(standardDate, nanosecond) return new Time( standardDate.getHours(), standardDate.getMinutes(), standardDate.getSeconds(), util.totalNanoseconds(standardDate, nanosecond), - util.timeZoneOffsetInSeconds(standardDate)); + util.timeZoneOffsetInSeconds(standardDate) + ) } - toString() { - return util.timeToIsoString(this.hour, this.minute, this.second, this.nanosecond) + util.timeZoneOffsetToIsoString(this.timeZoneOffsetSeconds); + toString () { + return ( + util.timeToIsoString( + this.hour, + this.minute, + this.second, + this.nanosecond + ) + util.timeZoneOffsetToIsoString(this.timeZoneOffsetSeconds) + ) } } -Object.defineProperty(Time.prototype, TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES); +Object.defineProperty( + Time.prototype, + TIME_IDENTIFIER_PROPERTY, + IDENTIFIER_PROPERTY_ATTRIBUTES +) /** * Test if given object is an instance of {@link Time} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link Time}, `false` otherwise. */ -export function isTime(obj) { - return hasIdentifierProperty(obj, TIME_IDENTIFIER_PROPERTY); +export function isTime (obj) { + return hasIdentifierProperty(obj, TIME_IDENTIFIER_PROPERTY) } /** @@ -190,18 +225,17 @@ export function isTime(obj) { * Created `Date` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class Date { - /** * @constructor * @param {Integer|number} year the year for the new local date. * @param {Integer|number} month the month for the new local date. * @param {Integer|number} day the day for the new local date. */ - constructor(year, month, day) { - this.year = util.assertValidYear(year); - this.month = util.assertValidMonth(month); - this.day = util.assertValidDay(day); - Object.freeze(this); + constructor (year, month, day) { + this.year = util.assertValidYear(year) + this.month = util.assertValidMonth(month) + this.day = util.assertValidDay(day) + Object.freeze(this) } /** @@ -210,29 +244,34 @@ export class Date { * @param {global.Date} standardDate the standard JavaScript date to convert. * @return {Date} new date. */ - static fromStandardDate(standardDate) { - verifyStandardDateAndNanos(standardDate, null); + static fromStandardDate (standardDate) { + verifyStandardDateAndNanos(standardDate, null) return new Date( standardDate.getFullYear(), standardDate.getMonth() + 1, - standardDate.getDate()); + standardDate.getDate() + ) } - toString() { - return util.dateToIsoString(this.year, this.month, this.day); + toString () { + return util.dateToIsoString(this.year, this.month, this.day) } } -Object.defineProperty(Date.prototype, DATE_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES); +Object.defineProperty( + Date.prototype, + DATE_IDENTIFIER_PROPERTY, + IDENTIFIER_PROPERTY_ATTRIBUTES +) /** * Test if given object is an instance of {@link Date} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link Date}, `false` otherwise. */ -export function isDate(obj) { - return hasIdentifierProperty(obj, DATE_IDENTIFIER_PROPERTY); +export function isDate (obj) { + return hasIdentifierProperty(obj, DATE_IDENTIFIER_PROPERTY) } /** @@ -240,7 +279,6 @@ export function isDate(obj) { * Created `LocalDateTime` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class LocalDateTime { - /** * @constructor * @param {Integer|number} year the year for the new local date. @@ -251,15 +289,15 @@ export class LocalDateTime { * @param {Integer|number} second the second for the new local time. * @param {Integer|number} nanosecond the nanosecond for the new local time. */ - constructor(year, month, day, hour, minute, second, nanosecond) { - this.year = util.assertValidYear(year); - this.month = util.assertValidMonth(month); - this.day = util.assertValidDay(day); - this.hour = util.assertValidHour(hour); - this.minute = util.assertValidMinute(minute); - this.second = util.assertValidSecond(second); - this.nanosecond = util.assertValidNanosecond(nanosecond); - Object.freeze(this); + constructor (year, month, day, hour, minute, second, nanosecond) { + this.year = util.assertValidYear(year) + this.month = util.assertValidMonth(month) + this.day = util.assertValidDay(day) + this.hour = util.assertValidHour(hour) + this.minute = util.assertValidMinute(minute) + this.second = util.assertValidSecond(second) + this.nanosecond = util.assertValidNanosecond(nanosecond) + Object.freeze(this) } /** @@ -269,8 +307,8 @@ export class LocalDateTime { * @param {Integer|number|undefined} nanosecond the optional amount of nanoseconds. * @return {LocalDateTime} new local date-time. */ - static fromStandardDate(standardDate, nanosecond) { - verifyStandardDateAndNanos(standardDate, nanosecond); + static fromStandardDate (standardDate, nanosecond) { + verifyStandardDateAndNanos(standardDate, nanosecond) return new LocalDateTime( standardDate.getFullYear(), @@ -279,23 +317,36 @@ export class LocalDateTime { standardDate.getHours(), standardDate.getMinutes(), standardDate.getSeconds(), - util.totalNanoseconds(standardDate, nanosecond)); + util.totalNanoseconds(standardDate, nanosecond) + ) } - toString() { - return localDateTimeToString(this.year, this.month, this.day, this.hour, this.minute, this.second, this.nanosecond); + toString () { + return localDateTimeToString( + this.year, + this.month, + this.day, + this.hour, + this.minute, + this.second, + this.nanosecond + ) } } -Object.defineProperty(LocalDateTime.prototype, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES); +Object.defineProperty( + LocalDateTime.prototype, + LOCAL_DATE_TIME_IDENTIFIER_PROPERTY, + IDENTIFIER_PROPERTY_ATTRIBUTES +) /** * Test if given object is an instance of {@link LocalDateTime} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link LocalDateTime}, `false` otherwise. */ -export function isLocalDateTime(obj) { - return hasIdentifierProperty(obj, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY); +export function isLocalDateTime (obj) { + return hasIdentifierProperty(obj, LOCAL_DATE_TIME_IDENTIFIER_PROPERTY) } /** @@ -303,7 +354,6 @@ export function isLocalDateTime(obj) { * Created `DateTime` objects are frozen with `Object.freeze()` in constructor and thus immutable. */ export class DateTime { - /** * @constructor * @param {Integer|number} year the year for the new date-time. @@ -318,20 +368,33 @@ export class DateTime { * This is different from standard JavaScript `Date.getTimezoneOffset()` which is the difference, in minutes, from local time to UTC. * @param {string|null} timeZoneId the time zone id for the new date-time. Either this argument or `timeZoneOffsetSeconds` should be defined. */ - constructor(year, month, day, hour, minute, second, nanosecond, timeZoneOffsetSeconds, timeZoneId) { - this.year = util.assertValidYear(year); - this.month = util.assertValidMonth(month); - this.day = util.assertValidDay(day); - this.hour = util.assertValidHour(hour); - this.minute = util.assertValidMinute(minute); - this.second = util.assertValidSecond(second); - this.nanosecond = util.assertValidNanosecond(nanosecond); - - const [offset, id] = verifyTimeZoneArguments(timeZoneOffsetSeconds, timeZoneId); - this.timeZoneOffsetSeconds = offset; - this.timeZoneId = id; - - Object.freeze(this); + constructor ( + year, + month, + day, + hour, + minute, + second, + nanosecond, + timeZoneOffsetSeconds, + timeZoneId + ) { + this.year = util.assertValidYear(year) + this.month = util.assertValidMonth(month) + this.day = util.assertValidDay(day) + this.hour = util.assertValidHour(hour) + this.minute = util.assertValidMinute(minute) + this.second = util.assertValidSecond(second) + this.nanosecond = util.assertValidNanosecond(nanosecond) + + const [offset, id] = verifyTimeZoneArguments( + timeZoneOffsetSeconds, + timeZoneId + ) + this.timeZoneOffsetSeconds = offset + this.timeZoneId = id + + Object.freeze(this) } /** @@ -340,8 +403,8 @@ export class DateTime { * @param {Integer|number|undefined} nanosecond the optional amount of nanoseconds. * @return {DateTime} new date-time. */ - static fromStandardDate(standardDate, nanosecond) { - verifyStandardDateAndNanos(standardDate, nanosecond); + static fromStandardDate (standardDate, nanosecond) { + verifyStandardDateAndNanos(standardDate, nanosecond) return new DateTime( standardDate.getFullYear(), @@ -352,55 +415,86 @@ export class DateTime { standardDate.getSeconds(), util.totalNanoseconds(standardDate, nanosecond), util.timeZoneOffsetInSeconds(standardDate), - null /* no time zone id */); + null /* no time zone id */ + ) } - toString() { - const localDateTimeStr = localDateTimeToString(this.year, this.month, this.day, this.hour, this.minute, this.second, this.nanosecond); - const timeZoneStr = this.timeZoneId ? `[${this.timeZoneId}]` : util.timeZoneOffsetToIsoString(this.timeZoneOffsetSeconds); - return localDateTimeStr + timeZoneStr; + toString () { + const localDateTimeStr = localDateTimeToString( + this.year, + this.month, + this.day, + this.hour, + this.minute, + this.second, + this.nanosecond + ) + const timeZoneStr = this.timeZoneId + ? `[${this.timeZoneId}]` + : util.timeZoneOffsetToIsoString(this.timeZoneOffsetSeconds) + return localDateTimeStr + timeZoneStr } } -Object.defineProperty(DateTime.prototype, DATE_TIME_IDENTIFIER_PROPERTY, IDENTIFIER_PROPERTY_ATTRIBUTES); +Object.defineProperty( + DateTime.prototype, + DATE_TIME_IDENTIFIER_PROPERTY, + IDENTIFIER_PROPERTY_ATTRIBUTES +) /** * Test if given object is an instance of {@link DateTime} class. * @param {object} obj the object to test. * @return {boolean} `true` if given object is a {@link DateTime}, `false` otherwise. */ -export function isDateTime(obj) { - return hasIdentifierProperty(obj, DATE_TIME_IDENTIFIER_PROPERTY); +export function isDateTime (obj) { + return hasIdentifierProperty(obj, DATE_TIME_IDENTIFIER_PROPERTY) } -function hasIdentifierProperty(obj, property) { - return (obj && obj[property]) === true; +function hasIdentifierProperty (obj, property) { + return (obj && obj[property]) === true } -function localDateTimeToString(year, month, day, hour, minute, second, nanosecond) { - return util.dateToIsoString(year, month, day) + 'T' + util.timeToIsoString(hour, minute, second, nanosecond); +function localDateTimeToString ( + year, + month, + day, + hour, + minute, + second, + nanosecond +) { + return ( + util.dateToIsoString(year, month, day) + + 'T' + + util.timeToIsoString(hour, minute, second, nanosecond) + ) } -function verifyTimeZoneArguments(timeZoneOffsetSeconds, timeZoneId) { - const offsetDefined = timeZoneOffsetSeconds || timeZoneOffsetSeconds === 0; - const idDefined = timeZoneId && timeZoneId !== ''; +function verifyTimeZoneArguments (timeZoneOffsetSeconds, timeZoneId) { + const offsetDefined = timeZoneOffsetSeconds || timeZoneOffsetSeconds === 0 + const idDefined = timeZoneId && timeZoneId !== '' if (offsetDefined && !idDefined) { - assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds'); - return [timeZoneOffsetSeconds, null]; + assertNumberOrInteger(timeZoneOffsetSeconds, 'Time zone offset in seconds') + return [timeZoneOffsetSeconds, null] } else if (!offsetDefined && idDefined) { - assertString(timeZoneId, 'Time zone ID'); - return [null, timeZoneId]; + assertString(timeZoneId, 'Time zone ID') + return [null, timeZoneId] } else if (offsetDefined && idDefined) { - throw newError(`Unable to create DateTime with both time zone offset and id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}`); + throw newError( + `Unable to create DateTime with both time zone offset and id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}` + ) } else { - throw newError(`Unable to create DateTime without either time zone offset or id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}`); + throw newError( + `Unable to create DateTime without either time zone offset or id. Please specify either of them. Given offset: ${timeZoneOffsetSeconds} and id: ${timeZoneId}` + ) } } -function verifyStandardDateAndNanos(standardDate, nanosecond) { - assertValidDate(standardDate, 'Standard date'); +function verifyStandardDateAndNanos (standardDate, nanosecond) { + assertValidDate(standardDate, 'Standard date') if (nanosecond !== null && nanosecond !== undefined) { - assertNumberOrInteger(nanosecond, 'Nanosecond'); + assertNumberOrInteger(nanosecond, 'Nanosecond') } } diff --git a/src/v1/transaction.js b/src/v1/transaction.js index 54a46892e..9f649a965 100644 --- a/src/v1/transaction.js +++ b/src/v1/transaction.js @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import StreamObserver from './internal/stream-observer'; -import Result from './result'; -import {validateStatementAndParameters} from './internal/util'; -import {EMPTY_CONNECTION_HOLDER} from './internal/connection-holder'; -import Bookmark from './internal/bookmark'; -import TxConfig from './internal/tx-config'; +import StreamObserver from './internal/stream-observer' +import Result from './result' +import { validateStatementAndParameters } from './internal/util' +import { EMPTY_CONNECTION_HOLDER } from './internal/connection-holder' +import Bookmark from './internal/bookmark' +import TxConfig from './internal/tx-config' /** * Represents a transaction in the Neo4j database. @@ -35,19 +35,29 @@ class Transaction { * @param {function()} onClose - Function to be called when transaction is committed or rolled back. * @param {function(bookmark: Bookmark)} onBookmark callback invoked when new bookmark is produced. */ - constructor(connectionHolder, onClose, onBookmark) { - this._connectionHolder = connectionHolder; - this._state = _states.ACTIVE; - this._onClose = onClose; - this._onBookmark = onBookmark; + constructor (connectionHolder, onClose, onBookmark) { + this._connectionHolder = connectionHolder + this._state = _states.ACTIVE + this._onClose = onClose + this._onBookmark = onBookmark } - _begin(bookmark, txConfig) { - const streamObserver = new _TransactionStreamObserver(this); + _begin (bookmark, txConfig) { + const streamObserver = new _TransactionStreamObserver(this) - this._connectionHolder.getConnection(streamObserver) - .then(conn => conn.protocol().beginTransaction(bookmark, txConfig, this._connectionHolder.mode(), streamObserver)) - .catch(error => streamObserver.onError(error)); + this._connectionHolder + .getConnection(streamObserver) + .then(conn => + conn + .protocol() + .beginTransaction( + bookmark, + txConfig, + this._connectionHolder.mode(), + streamObserver + ) + ) + .catch(error => streamObserver.onError(error)) } /** @@ -58,10 +68,18 @@ class Transaction { * @param {Object} parameters - Map with parameters to use in statement * @return {Result} New Result */ - run(statement, parameters) { - const {query, params} = validateStatementAndParameters(statement, parameters); + run (statement, parameters) { + const { query, params } = validateStatementAndParameters( + statement, + parameters + ) - return this._state.run(this._connectionHolder, new _TransactionStreamObserver(this), query, params); + return this._state.run( + this._connectionHolder, + new _TransactionStreamObserver(this), + query, + params + ) } /** @@ -71,12 +89,15 @@ class Transaction { * * @returns {Result} New Result */ - commit() { - let committed = this._state.commit(this._connectionHolder, new _TransactionStreamObserver(this)); - this._state = committed.state; - //clean up - this._onClose(); - return committed.result; + commit () { + let committed = this._state.commit( + this._connectionHolder, + new _TransactionStreamObserver(this) + ) + this._state = committed.state + // clean up + this._onClose() + return committed.result } /** @@ -86,164 +107,219 @@ class Transaction { * * @returns {Result} New Result */ - rollback() { - let committed = this._state.rollback(this._connectionHolder, new _TransactionStreamObserver(this)); - this._state = committed.state; - //clean up - this._onClose(); - return committed.result; + rollback () { + let committed = this._state.rollback( + this._connectionHolder, + new _TransactionStreamObserver(this) + ) + this._state = committed.state + // clean up + this._onClose() + return committed.result } /** * Check if this transaction is active, which means commit and rollback did not happen. * @return {boolean} `true` when not committed and not rolled back, `false` otherwise. */ - isOpen() { - return this._state == _states.ACTIVE; + isOpen () { + return this._state === _states.ACTIVE } - _onError() { + _onError () { // error will be "acknowledged" by sending a RESET message // database will then forget about this transaction and cleanup all corresponding resources // it is thus safe to move this transaction to a FAILED state and disallow any further interactions with it - this._state = _states.FAILED; - this._onClose(); + this._state = _states.FAILED + this._onClose() // release connection back to the pool - return this._connectionHolder.releaseConnection(); + return this._connectionHolder.releaseConnection() } } -/** Internal stream observer used for transactional results*/ +/** Internal stream observer used for transactional results */ class _TransactionStreamObserver extends StreamObserver { - constructor(tx) { - super(); - this._tx = tx; + constructor (tx) { + super() + this._tx = tx } - onError(error) { + onError (error) { if (!this._hasFailed) { this._tx._onError().then(() => { - super.onError(error); - }); + super.onError(error) + }) } } - onCompleted(meta) { - super.onCompleted(meta); - const bookmark = new Bookmark(meta.bookmark); - this._tx._onBookmark(bookmark); + onCompleted (meta) { + super.onCompleted(meta) + const bookmark = new Bookmark(meta.bookmark) + this._tx._onBookmark(bookmark) } } -/** internal state machine of the transaction*/ +/** internal state machine of the transaction */ let _states = { - //The transaction is running with no explicit success or failure marked + // The transaction is running with no explicit success or failure marked ACTIVE: { commit: (connectionHolder, observer) => { return { result: finishTransaction(true, connectionHolder, observer), state: _states.SUCCEEDED - }; + } }, rollback: (connectionHolder, observer) => { return { result: finishTransaction(false, connectionHolder, observer), state: _states.ROLLED_BACK - }; + } }, run: (connectionHolder, observer, statement, parameters) => { // RUN in explicit transaction can't contain bookmarks and transaction configuration - const bookmark = Bookmark.empty(); - const txConfig = TxConfig.empty(); + const bookmark = Bookmark.empty() + const txConfig = TxConfig.empty() - connectionHolder.getConnection(observer) - .then(conn => conn.protocol().run(statement, parameters, bookmark, txConfig, connectionHolder.mode(), observer)) - .catch(error => observer.onError(error)); + connectionHolder + .getConnection(observer) + .then(conn => + conn + .protocol() + .run( + statement, + parameters, + bookmark, + txConfig, + connectionHolder.mode(), + observer + ) + ) + .catch(error => observer.onError(error)) - return _newRunResult(observer, statement, parameters, () => observer.serverMetadata()); + return _newRunResult(observer, statement, parameters, () => + observer.serverMetadata() + ) } }, - //An error has occurred, transaction can no longer be used and no more messages will + // An error has occurred, transaction can no longer be used and no more messages will // be sent for this transaction. FAILED: { commit: (connectionHolder, observer) => { observer.onError({ - error: "Cannot commit statements in this transaction, because previous statements in the " + - "transaction has failed and the transaction has been rolled back. Please start a new" + - " transaction to run another statement." - }); - return {result: _newDummyResult(observer, "COMMIT", {}), state: _states.FAILED}; + error: + 'Cannot commit statements in this transaction, because previous statements in the ' + + 'transaction has failed and the transaction has been rolled back. Please start a new' + + ' transaction to run another statement.' + }) + return { + result: _newDummyResult(observer, 'COMMIT', {}), + state: _states.FAILED + } }, rollback: (connectionHolder, observer) => { - observer.markCompleted(); - return {result: _newDummyResult(observer, "ROLLBACK", {}), state: _states.FAILED}; + observer.markCompleted() + return { + result: _newDummyResult(observer, 'ROLLBACK', {}), + state: _states.FAILED + } }, run: (connectionHolder, observer, statement, parameters) => { - observer.onError({error: - "Cannot run statement, because previous statements in the " + - "transaction has failed and the transaction has already been rolled back."}); - return _newDummyResult(observer, statement, parameters); + observer.onError({ + error: + 'Cannot run statement, because previous statements in the ' + + 'transaction has failed and the transaction has already been rolled back.' + }) + return _newDummyResult(observer, statement, parameters) } }, - //This transaction has successfully committed + // This transaction has successfully committed SUCCEEDED: { commit: (connectionHolder, observer) => { observer.onError({ - error: "Cannot commit statements in this transaction, because commit has already been successfully called on the transaction and transaction has been closed. Please start a new" + - " transaction to run another statement." - }); - return {result: _newDummyResult(observer, "COMMIT", {}), state: _states.SUCCEEDED}; + error: + 'Cannot commit statements in this transaction, because commit has already been successfully called on the transaction and transaction has been closed. Please start a new' + + ' transaction to run another statement.' + }) + return { + result: _newDummyResult(observer, 'COMMIT', {}), + state: _states.SUCCEEDED + } }, rollback: (connectionHolder, observer) => { - observer.onError({error: - "Cannot rollback transaction, because transaction has already been successfully closed."}); - return {result: _newDummyResult(observer, "ROLLBACK", {}), state: _states.SUCCEEDED}; + observer.onError({ + error: + 'Cannot rollback transaction, because transaction has already been successfully closed.' + }) + return { + result: _newDummyResult(observer, 'ROLLBACK', {}), + state: _states.SUCCEEDED + } }, run: (connectionHolder, observer, statement, parameters) => { - observer.onError({error: - "Cannot run statement, because transaction has already been successfully closed."}); - return _newDummyResult(observer, statement, parameters); + observer.onError({ + error: + 'Cannot run statement, because transaction has already been successfully closed.' + }) + return _newDummyResult(observer, statement, parameters) } }, - //This transaction has been rolled back + // This transaction has been rolled back ROLLED_BACK: { commit: (connectionHolder, observer) => { observer.onError({ - error: "Cannot commit this transaction, because it has already been rolled back." - }); - return {result: _newDummyResult(observer, "COMMIT", {}), state: _states.ROLLED_BACK}; + error: + 'Cannot commit this transaction, because it has already been rolled back.' + }) + return { + result: _newDummyResult(observer, 'COMMIT', {}), + state: _states.ROLLED_BACK + } }, rollback: (connectionHolder, observer) => { - observer.onError({error: - "Cannot rollback transaction, because transaction has already been rolled back."}); - return {result: _newDummyResult(observer, "ROLLBACK", {}), state: _states.ROLLED_BACK}; + observer.onError({ + error: + 'Cannot rollback transaction, because transaction has already been rolled back.' + }) + return { + result: _newDummyResult(observer, 'ROLLBACK', {}), + state: _states.ROLLED_BACK + } }, run: (connectionHolder, observer, statement, parameters) => { - observer.onError({error: - "Cannot run statement, because transaction has already been rolled back."}); - return _newDummyResult(observer, statement, parameters); + observer.onError({ + error: + 'Cannot run statement, because transaction has already been rolled back.' + }) + return _newDummyResult(observer, statement, parameters) } } -}; +} -function finishTransaction(commit, connectionHolder, observer) { - connectionHolder.getConnection(observer) +function finishTransaction (commit, connectionHolder, observer) { + connectionHolder + .getConnection(observer) .then(connection => { if (commit) { - return connection.protocol().commitTransaction(observer); + return connection.protocol().commitTransaction(observer) } else { - return connection.protocol().rollbackTransaction(observer); + return connection.protocol().rollbackTransaction(observer) } }) - .catch(error => observer.onError(error)); + .catch(error => observer.onError(error)) // for commit & rollback we need result that uses real connection holder and notifies it when // connection is not needed and can be safely released to the pool - return new Result(observer, commit ? 'COMMIT' : 'ROLLBACK', {}, emptyMetadataSupplier, connectionHolder); + return new Result( + observer, + commit ? 'COMMIT' : 'ROLLBACK', + {}, + emptyMetadataSupplier, + connectionHolder + ) } /** @@ -258,8 +334,14 @@ function finishTransaction(commit, connectionHolder, observer) { * @return {Result} new result. * @private */ -function _newRunResult(observer, statement, parameters, metadataSupplier) { - return new Result(observer, statement, parameters, metadataSupplier, EMPTY_CONNECTION_HOLDER); +function _newRunResult (observer, statement, parameters, metadataSupplier) { + return new Result( + observer, + statement, + parameters, + metadataSupplier, + EMPTY_CONNECTION_HOLDER + ) } /** @@ -272,12 +354,18 @@ function _newRunResult(observer, statement, parameters, metadataSupplier) { * @return {Result} new result. * @private */ -function _newDummyResult(observer, statement, parameters) { - return new Result(observer, statement, parameters, emptyMetadataSupplier, EMPTY_CONNECTION_HOLDER); +function _newDummyResult (observer, statement, parameters) { + return new Result( + observer, + statement, + parameters, + emptyMetadataSupplier, + EMPTY_CONNECTION_HOLDER + ) } -function emptyMetadataSupplier() { - return {}; +function emptyMetadataSupplier () { + return {} } -export default Transaction; +export default Transaction diff --git a/src/version.js b/src/version.js index 3810836f6..c16371d61 100644 --- a/src/version.js +++ b/src/version.js @@ -24,4 +24,4 @@ // This is set up this way to keep the version in the code in // sync with the npm package version, and to allow the build // system to control version names at packaging time. -export default "0.0.0-dev"; +export default '0.0.0-dev' diff --git a/test/browser/jasmine-runner.html b/test/browser/jasmine-runner.html index f1406d9aa..fb7bd30e9 100644 --- a/test/browser/jasmine-runner.html +++ b/test/browser/jasmine-runner.html @@ -17,20 +17,33 @@ --> - - - Jasmine Test Runner - - - - - - - - - - - - - + + + Jasmine Test Runner + + + + + + + + + + diff --git a/test/browser/karma-chrome.conf.js b/test/browser/karma-chrome.conf.js index 524aba97d..e950f0d2d 100644 --- a/test/browser/karma-chrome.conf.js +++ b/test/browser/karma-chrome.conf.js @@ -26,7 +26,7 @@ module.exports = function (config) { files: [ 'src/*.js', 'src/**/!(node)/*.js', - 'test/**/!(node)/!(examples).test.js', + 'test/**/!(node)/!(examples).test.js' ], preprocessors: { 'src/**/*.js': ['browserify'], diff --git a/test/browser/karma-edge.conf.js b/test/browser/karma-edge.conf.js index 2efbc37e1..298a217ad 100644 --- a/test/browser/karma-edge.conf.js +++ b/test/browser/karma-edge.conf.js @@ -16,19 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -module.exports = function(config) { +module.exports = function (config) { config.set({ frameworks: ['jasmine'], basePath: '../../', files: ['build/browser/neo4j-web.test.js'], reporters: ['spec'], - port: 9876, // karma web server port + port: 9876, // karma web server port colors: true, logLevel: config.LOG_DEBUG, browsers: ['Edge'], autoWatch: false, singleRun: true, concurrency: 1, - browserNoActivityTimeout: 30 * 60 * 1000, + browserNoActivityTimeout: 30 * 60 * 1000 }) -}; +} diff --git a/test/browser/karma-firefox.conf.js b/test/browser/karma-firefox.conf.js index 87c6799ac..995040be2 100644 --- a/test/browser/karma-firefox.conf.js +++ b/test/browser/karma-firefox.conf.js @@ -26,7 +26,7 @@ module.exports = function (config) { files: [ 'src/*.js', 'src/**/!(node)/*.js', - 'test/**/!(node)/!(examples).test.js', + 'test/**/!(node)/!(examples).test.js' ], preprocessors: { 'src/**/*.js': ['browserify'], diff --git a/test/browser/karma-ie.conf.js b/test/browser/karma-ie.conf.js index cc9b34f46..4a35cc95d 100644 --- a/test/browser/karma-ie.conf.js +++ b/test/browser/karma-ie.conf.js @@ -22,13 +22,13 @@ module.exports = function (config) { basePath: '../../', files: ['build/browser/neo4j-web.test.js'], reporters: ['spec'], - port: 9876, // karma web server port + port: 9876, // karma web server port colors: true, logLevel: config.LOG_DEBUG, browsers: ['IE'], autoWatch: false, singleRun: true, concurrency: 1, - browserNoActivityTimeout: 30 * 60 * 1000, - }); -}; + browserNoActivityTimeout: 30 * 60 * 1000 + }) +} diff --git a/test/internal/bolt-protocol-v1.test.js b/test/internal/bolt-protocol-v1.test.js index 20a6da075..6dc26954f 100644 --- a/test/internal/bolt-protocol-v1.test.js +++ b/test/internal/bolt-protocol-v1.test.js @@ -17,148 +17,171 @@ * limitations under the License. */ -import BoltProtocolV1 from '../../src/v1/internal/bolt-protocol-v1'; -import RequestMessage from '../../src/v1/internal/request-message'; -import Bookmark from '../../src/v1/internal/bookmark'; -import TxConfig from '../../src/v1/internal/tx-config'; -import {WRITE} from "../../src/v1/driver"; +import BoltProtocolV1 from '../../src/v1/internal/bolt-protocol-v1' +import RequestMessage from '../../src/v1/internal/request-message' +import Bookmark from '../../src/v1/internal/bookmark' +import TxConfig from '../../src/v1/internal/tx-config' +import { WRITE } from '../../src/v1/driver' class MessageRecorder { - - constructor() { - this.messages = []; - this.observers = []; - this.flushes = []; + constructor () { + this.messages = [] + this.observers = [] + this.flushes = [] } - write(message, observer, flush) { - this.messages.push(message); - this.observers.push(observer); - this.flushes.push(flush); + write (message, observer, flush) { + this.messages.push(message) + this.observers.push(observer) + this.flushes.push(flush) } - verifyMessageCount(expected) { - expect(this.messages.length).toEqual(expected); - expect(this.observers.length).toEqual(expected); - expect(this.flushes.length).toEqual(expected); + verifyMessageCount (expected) { + expect(this.messages.length).toEqual(expected) + expect(this.observers.length).toEqual(expected) + expect(this.flushes.length).toEqual(expected) } } describe('BoltProtocolV1', () => { - it('should not change metadata', () => { - const metadata = {result_available_after: 1, result_consumed_after: 2, t_first: 3, t_last: 4}; - const protocol = new BoltProtocolV1(new MessageRecorder(), null, false); - - const transformedMetadata = protocol.transformMetadata(metadata); - - expect(transformedMetadata).toEqual({result_available_after: 1, result_consumed_after: 2, t_first: 3, t_last: 4}); - }); + const metadata = { + result_available_after: 1, + result_consumed_after: 2, + t_first: 3, + t_last: 4 + } + const protocol = new BoltProtocolV1(new MessageRecorder(), null, false) + + const transformedMetadata = protocol.transformMetadata(metadata) + + expect(transformedMetadata).toEqual({ + result_available_after: 1, + result_consumed_after: 2, + t_first: 3, + t_last: 4 + }) + }) it('should initialize the connection', () => { - const recorder = new MessageRecorder(); - const protocol = new BoltProtocolV1(recorder, null, false); + const recorder = new MessageRecorder() + const protocol = new BoltProtocolV1(recorder, null, false) - const clientName = 'js-driver/1.2.3'; - const authToken = {username: 'neo4j', password: 'secret'}; - const observer = {}; + const clientName = 'js-driver/1.2.3' + const authToken = { username: 'neo4j', password: 'secret' } + const observer = {} - protocol.initialize(clientName, authToken, observer); + protocol.initialize(clientName, authToken, observer) - recorder.verifyMessageCount(1); - verifyMessage(RequestMessage.init(clientName, authToken), recorder.messages[0]); - expect(recorder.observers).toEqual([observer]); - expect(recorder.flushes).toEqual([true]); - }); + recorder.verifyMessageCount(1) + verifyMessage( + RequestMessage.init(clientName, authToken), + recorder.messages[0] + ) + expect(recorder.observers).toEqual([observer]) + expect(recorder.flushes).toEqual([true]) + }) it('should run a statement', () => { - const recorder = new MessageRecorder(); - const protocol = new BoltProtocolV1(recorder, null, false); - - const statement = 'RETURN $x, $y'; - const parameters = {x: 'x', y: 'y'}; - const observer = {}; - - protocol.run(statement, parameters, Bookmark.empty(), TxConfig.empty(), WRITE, observer); - - recorder.verifyMessageCount(2); - - verifyMessage(RequestMessage.run(statement, parameters), recorder.messages[0]); - verifyMessage(RequestMessage.pullAll(), recorder.messages[1]); - - expect(recorder.observers).toEqual([observer, observer]); - expect(recorder.flushes).toEqual([false, true]); - }); + const recorder = new MessageRecorder() + const protocol = new BoltProtocolV1(recorder, null, false) + + const statement = 'RETURN $x, $y' + const parameters = { x: 'x', y: 'y' } + const observer = {} + + protocol.run( + statement, + parameters, + Bookmark.empty(), + TxConfig.empty(), + WRITE, + observer + ) + + recorder.verifyMessageCount(2) + + verifyMessage( + RequestMessage.run(statement, parameters), + recorder.messages[0] + ) + verifyMessage(RequestMessage.pullAll(), recorder.messages[1]) + + expect(recorder.observers).toEqual([observer, observer]) + expect(recorder.flushes).toEqual([false, true]) + }) it('should reset the connection', () => { - const recorder = new MessageRecorder(); - const protocol = new BoltProtocolV1(recorder, null, false); + const recorder = new MessageRecorder() + const protocol = new BoltProtocolV1(recorder, null, false) - const observer = {}; + const observer = {} - protocol.reset(observer); + protocol.reset(observer) - recorder.verifyMessageCount(1); - verifyMessage(RequestMessage.reset(), recorder.messages[0]); - expect(recorder.observers).toEqual([observer]); - expect(recorder.flushes).toEqual([true]); - }); + recorder.verifyMessageCount(1) + verifyMessage(RequestMessage.reset(), recorder.messages[0]) + expect(recorder.observers).toEqual([observer]) + expect(recorder.flushes).toEqual([true]) + }) it('should begin a transaction', () => { - const recorder = new MessageRecorder(); - const protocol = new BoltProtocolV1(recorder, null, false); + const recorder = new MessageRecorder() + const protocol = new BoltProtocolV1(recorder, null, false) - const bookmark = new Bookmark('neo4j:bookmark:v1:tx42'); - const observer = {}; + const bookmark = new Bookmark('neo4j:bookmark:v1:tx42') + const observer = {} - protocol.beginTransaction(bookmark, TxConfig.empty(), WRITE, observer); + protocol.beginTransaction(bookmark, TxConfig.empty(), WRITE, observer) - recorder.verifyMessageCount(2); + recorder.verifyMessageCount(2) - verifyMessage(RequestMessage.run('BEGIN', bookmark.asBeginTransactionParameters()), recorder.messages[0]); - verifyMessage(RequestMessage.pullAll(), recorder.messages[1]); + verifyMessage( + RequestMessage.run('BEGIN', bookmark.asBeginTransactionParameters()), + recorder.messages[0] + ) + verifyMessage(RequestMessage.pullAll(), recorder.messages[1]) - expect(recorder.observers).toEqual([observer, observer]); - expect(recorder.flushes).toEqual([false, false]); - }); + expect(recorder.observers).toEqual([observer, observer]) + expect(recorder.flushes).toEqual([false, false]) + }) it('should commit a transaction', () => { - const recorder = new MessageRecorder(); - const protocol = new BoltProtocolV1(recorder, null, false); + const recorder = new MessageRecorder() + const protocol = new BoltProtocolV1(recorder, null, false) - const observer = {}; + const observer = {} - protocol.commitTransaction(observer); + protocol.commitTransaction(observer) - recorder.verifyMessageCount(2); + recorder.verifyMessageCount(2) - verifyMessage(RequestMessage.run('COMMIT', {}), recorder.messages[0]); - verifyMessage(RequestMessage.pullAll(), recorder.messages[1]); + verifyMessage(RequestMessage.run('COMMIT', {}), recorder.messages[0]) + verifyMessage(RequestMessage.pullAll(), recorder.messages[1]) - expect(recorder.observers).toEqual([observer, observer]); - expect(recorder.flushes).toEqual([false, true]); - }); + expect(recorder.observers).toEqual([observer, observer]) + expect(recorder.flushes).toEqual([false, true]) + }) it('should rollback a transaction', () => { - const recorder = new MessageRecorder(); - const protocol = new BoltProtocolV1(recorder, null, false); - - const observer = {}; + const recorder = new MessageRecorder() + const protocol = new BoltProtocolV1(recorder, null, false) - protocol.rollbackTransaction(observer); + const observer = {} - recorder.verifyMessageCount(2); + protocol.rollbackTransaction(observer) - verifyMessage(RequestMessage.run('ROLLBACK', {}), recorder.messages[0]); - verifyMessage(RequestMessage.pullAll(), recorder.messages[1]); + recorder.verifyMessageCount(2) - expect(recorder.observers).toEqual([observer, observer]); - expect(recorder.flushes).toEqual([false, true]); - }); + verifyMessage(RequestMessage.run('ROLLBACK', {}), recorder.messages[0]) + verifyMessage(RequestMessage.pullAll(), recorder.messages[1]) -}); + expect(recorder.observers).toEqual([observer, observer]) + expect(recorder.flushes).toEqual([false, true]) + }) +}) -function verifyMessage(expected, actual) { - expect(actual.signature).toEqual(expected.signature); - expect(actual.fields).toEqual(expected.fields); +function verifyMessage (expected, actual) { + expect(actual.signature).toEqual(expected.signature) + expect(actual.fields).toEqual(expected.fields) } diff --git a/test/internal/bolt-protocol-v3.test.js b/test/internal/bolt-protocol-v3.test.js index e154d42e0..f69753824 100644 --- a/test/internal/bolt-protocol-v3.test.js +++ b/test/internal/bolt-protocol-v3.test.js @@ -17,17 +17,20 @@ * limitations under the License. */ -import BoltProtocolV3 from '../../src/v1/internal/bolt-protocol-v3'; +import BoltProtocolV3 from '../../src/v1/internal/bolt-protocol-v3' describe('BoltProtocolV3', () => { - it('should update metadata', () => { - const metadata = {t_first: 1, t_last: 2, db_hits: 3, some_other_key: 4}; - const protocol = new BoltProtocolV3(null, null, false); - - const transformedMetadata = protocol.transformMetadata(metadata); + const metadata = { t_first: 1, t_last: 2, db_hits: 3, some_other_key: 4 } + const protocol = new BoltProtocolV3(null, null, false) - expect(transformedMetadata).toEqual({result_available_after: 1, result_consumed_after: 2, db_hits: 3, some_other_key: 4}); - }); + const transformedMetadata = protocol.transformMetadata(metadata) -}); + expect(transformedMetadata).toEqual({ + result_available_after: 1, + result_consumed_after: 2, + db_hits: 3, + some_other_key: 4 + }) + }) +}) diff --git a/test/internal/bolt-stub.js b/test/internal/bolt-stub.js index cf2145dc1..8e956c0f8 100644 --- a/test/internal/bolt-stub.js +++ b/test/internal/bolt-stub.js @@ -17,114 +17,116 @@ * limitations under the License. */ -import sharedNeo4j from './shared-neo4j'; -import neo4j from '../../src/v1/index'; +import sharedNeo4j from './shared-neo4j' +import neo4j from '../../src/v1/index' class UnsupportedBoltStub { - - start(script, port) { - throw new Error('BoltStub: unable to start, unavailable on this platform'); + start (script, port) { + throw new Error('BoltStub: unable to start, unavailable on this platform') } - startWithTemplate(scriptTemplate, parameters, port) { - throw new Error('BoltStub: unable to start with template, unavailable on this platform'); + startWithTemplate (scriptTemplate, parameters, port) { + throw new Error( + 'BoltStub: unable to start with template, unavailable on this platform' + ) } - run(callback) { - throw new Error('BoltStub: unable to run, unavailable on this platform'); + run (callback) { + throw new Error('BoltStub: unable to run, unavailable on this platform') } } -const verbose = false; // for debugging purposes +const verbose = false // for debugging purposes class SupportedBoltStub extends UnsupportedBoltStub { - - constructor() { - super(); - this._childProcess = require('child_process'); - this._mustache = require('mustache'); - this._fs = require('fs'); - this._tmp = require('tmp'); + constructor () { + super() + this._childProcess = require('child_process') + this._mustache = require('mustache') + this._fs = require('fs') + this._tmp = require('tmp') } - static create() { + static create () { try { - return new SupportedBoltStub(); + return new SupportedBoltStub() } catch (e) { - return null; + return null } } - start(script, port) { - const boltStub = this._childProcess.spawn('boltstub', ['-v', port, script]); + start (script, port) { + const boltStub = this._childProcess.spawn('boltstub', ['-v', port, script]) if (verbose) { - boltStub.stdout.on('data', (data) => { - console.log(`${data}`); - }); - boltStub.stderr.on('data', (data) => { - console.log(`${data}`); - }); + boltStub.stdout.on('data', data => { + console.log(`${data}`) + }) + boltStub.stderr.on('data', data => { + console.log(`${data}`) + }) boltStub.on('end', data => { - console.log(data); - }); + console.log(data) + }) } - let exitCode = -1; + let exitCode = -1 boltStub.on('close', code => { - exitCode = code; - }); + exitCode = code + }) boltStub.on('error', error => { - console.log('Failed to start child process:' + error); - }); + console.log('Failed to start child process:' + error) + }) - return new StubServer(() => exitCode); + return new StubServer(() => exitCode) } - startWithTemplate(scriptTemplate, parameters, port) { - const template = this._fs.readFileSync(scriptTemplate, 'utf-8'); - const scriptContents = this._mustache.render(template, parameters); - const script = this._tmp.fileSync().name; - this._fs.writeFileSync(script, scriptContents, 'utf-8'); - return this.start(script, port); + startWithTemplate (scriptTemplate, parameters, port) { + const template = this._fs.readFileSync(scriptTemplate, 'utf-8') + const scriptContents = this._mustache.render(template, parameters) + const script = this._tmp.fileSync().name + this._fs.writeFileSync(script, scriptContents, 'utf-8') + return this.start(script, port) } - run(callback) { + run (callback) { // wait to make sure boltstub is started before running user code - setTimeout(callback, 1000); + setTimeout(callback, 1000) } } class StubServer { - - constructor(exitCodeSupplier) { - this._exitCodeSupplier = exitCodeSupplier; - this.exit.bind(this); + constructor (exitCodeSupplier) { + this._exitCodeSupplier = exitCodeSupplier + this.exit.bind(this) } - exit(callback) { + exit (callback) { // give process some time to exit setTimeout(() => { - callback(this._exitCodeSupplier()); - }, 1000); + callback(this._exitCodeSupplier()) + }, 1000) } } -function newDriver(url, config = {}) { +function newDriver (url, config = {}) { // left here for debugging purposes const logging = { level: (process.env['NEOLOGLEVEL'] || 'error').toLowerCase(), logger: (level, msg) => console.log(`${level}: ${msg}`) - }; + } // boltstub currently does not support encryption, create driver with encryption turned off - const newConfig = Object.assign({ encrypted: 'ENCRYPTION_OFF', logging }, config); - return neo4j.driver(url, sharedNeo4j.authToken, newConfig); + const newConfig = Object.assign( + { encrypted: 'ENCRYPTION_OFF', logging }, + config + ) + return neo4j.driver(url, sharedNeo4j.authToken, newConfig) } -const supportedStub = SupportedBoltStub.create(); -const supported = supportedStub != null; -const stub = supported ? supportedStub : new UnsupportedBoltStub(); +const supportedStub = SupportedBoltStub.create() +const supported = supportedStub != null +const stub = supported ? supportedStub : new UnsupportedBoltStub() export default { supported: supported, @@ -132,4 +134,4 @@ export default { startWithTemplate: stub.startWithTemplate.bind(stub), run: stub.run.bind(stub), newDriver: newDriver -}; +} diff --git a/test/internal/bookmark.test.js b/test/internal/bookmark.test.js index 5982d2aeb..41a20fb23 100644 --- a/test/internal/bookmark.test.js +++ b/test/internal/bookmark.test.js @@ -16,123 +16,145 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import Bookmark from '../../src/v1/internal/bookmark'; +import Bookmark from '../../src/v1/internal/bookmark' describe('Bookmark', () => { - it('should be possible to construct bookmark from string', () => { - const bookmark = new Bookmark('neo4j:bookmark:v1:tx412'); + const bookmark = new Bookmark('neo4j:bookmark:v1:tx412') - expect(bookmark.isEmpty()).toBeFalsy(); - expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:tx412'); - }); + expect(bookmark.isEmpty()).toBeFalsy() + expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:tx412') + }) it('should be possible to construct bookmark from string array', () => { - const bookmark = new Bookmark(['neo4j:bookmark:v1:tx1', 'neo4j:bookmark:v1:tx2', 'neo4j:bookmark:v1:tx3']); + const bookmark = new Bookmark([ + 'neo4j:bookmark:v1:tx1', + 'neo4j:bookmark:v1:tx2', + 'neo4j:bookmark:v1:tx3' + ]) - expect(bookmark.isEmpty()).toBeFalsy(); - expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:tx3'); - }); + expect(bookmark.isEmpty()).toBeFalsy() + expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:tx3') + }) it('should be possible to construct bookmark from null', () => { - const bookmark = new Bookmark(null); + const bookmark = new Bookmark(null) - expect(bookmark.isEmpty()).toBeTruthy(); - expect(bookmark.maxBookmarkAsString()).toBeNull(); - }); + expect(bookmark.isEmpty()).toBeTruthy() + expect(bookmark.maxBookmarkAsString()).toBeNull() + }) it('should be possible to construct bookmark from undefined', () => { - const bookmark = new Bookmark(undefined); + const bookmark = new Bookmark(undefined) - expect(bookmark.isEmpty()).toBeTruthy(); - expect(bookmark.maxBookmarkAsString()).toBeNull(); - }); + expect(bookmark.isEmpty()).toBeTruthy() + expect(bookmark.maxBookmarkAsString()).toBeNull() + }) it('should be possible to construct bookmark from an empty string', () => { - const bookmark = new Bookmark(''); + const bookmark = new Bookmark('') - expect(bookmark.isEmpty()).toBeTruthy(); - expect(bookmark.maxBookmarkAsString()).toBeNull(); - }); + expect(bookmark.isEmpty()).toBeTruthy() + expect(bookmark.maxBookmarkAsString()).toBeNull() + }) it('should be possible to construct bookmark from empty array', () => { - const bookmark = new Bookmark([]); + const bookmark = new Bookmark([]) - expect(bookmark.isEmpty()).toBeTruthy(); - expect(bookmark.maxBookmarkAsString()).toBeNull(); - }); + expect(bookmark.isEmpty()).toBeTruthy() + expect(bookmark.maxBookmarkAsString()).toBeNull() + }) it('should not be possible to construct bookmark from object', () => { - expect(() => new Bookmark({})).toThrowError(TypeError); - expect(() => new Bookmark({bookmark: 'neo4j:bookmark:v1:tx1'})).toThrowError(TypeError); - }); + expect(() => new Bookmark({})).toThrowError(TypeError) + expect( + () => new Bookmark({ bookmark: 'neo4j:bookmark:v1:tx1' }) + ).toThrowError(TypeError) + }) it('should not be possible to construct bookmark from number array', () => { - expect(() => new Bookmark([1, 2, 3])).toThrowError(TypeError); - }); + expect(() => new Bookmark([1, 2, 3])).toThrowError(TypeError) + }) it('should not be possible to construct bookmark from mixed array', () => { - expect(() => new Bookmark(['neo4j:bookmark:v1:tx1', 2, 'neo4j:bookmark:v1:tx3'])).toThrowError(TypeError); - }); + expect( + () => new Bookmark(['neo4j:bookmark:v1:tx1', 2, 'neo4j:bookmark:v1:tx3']) + ).toThrowError(TypeError) + }) it('should keep unparsable bookmark', () => { - const bookmark = new Bookmark('neo4j:bookmark:v1:txWrong'); + const bookmark = new Bookmark('neo4j:bookmark:v1:txWrong') - expect(bookmark.isEmpty()).toBeFalsy(); - expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:txWrong'); - }); + expect(bookmark.isEmpty()).toBeFalsy() + expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:txWrong') + }) it('should skip unparsable bookmarks', () => { - const bookmark = new Bookmark(['neo4j:bookmark:v1:tx42', 'neo4j:bookmark:v1:txWrong', 'neo4j:bookmark:v1:tx4242']); + const bookmark = new Bookmark([ + 'neo4j:bookmark:v1:tx42', + 'neo4j:bookmark:v1:txWrong', + 'neo4j:bookmark:v1:tx4242' + ]) - expect(bookmark.isEmpty()).toBeFalsy(); - expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:tx4242'); - }); + expect(bookmark.isEmpty()).toBeFalsy() + expect(bookmark.maxBookmarkAsString()).toEqual('neo4j:bookmark:v1:tx4242') + }) it('should turn into empty transaction params when empty', () => { - const bookmark = new Bookmark(null); + const bookmark = new Bookmark(null) - expect(bookmark.isEmpty()).toBeTruthy(); - expect(bookmark.asBeginTransactionParameters()).toEqual({}); - }); + expect(bookmark.isEmpty()).toBeTruthy() + expect(bookmark.asBeginTransactionParameters()).toEqual({}) + }) it('should turn into transaction params when represents single bookmark', () => { - const bookmark = new Bookmark('neo4j:bookmark:v1:tx142'); + const bookmark = new Bookmark('neo4j:bookmark:v1:tx142') - expect(bookmark.isEmpty()).toBeFalsy(); + expect(bookmark.isEmpty()).toBeFalsy() expect(bookmark.asBeginTransactionParameters()).toEqual({ bookmark: 'neo4j:bookmark:v1:tx142', bookmarks: ['neo4j:bookmark:v1:tx142'] - }); - }); + }) + }) it('should turn into transaction params when represents multiple bookmarks', () => { - const bookmark = new Bookmark( - ['neo4j:bookmark:v1:tx1', 'neo4j:bookmark:v1:tx3', 'neo4j:bookmark:v1:tx42', 'neo4j:bookmark:v1:tx5'] - ); - - expect(bookmark.isEmpty()).toBeFalsy(); + const bookmark = new Bookmark([ + 'neo4j:bookmark:v1:tx1', + 'neo4j:bookmark:v1:tx3', + 'neo4j:bookmark:v1:tx42', + 'neo4j:bookmark:v1:tx5' + ]) + + expect(bookmark.isEmpty()).toBeFalsy() expect(bookmark.asBeginTransactionParameters()).toEqual({ bookmark: 'neo4j:bookmark:v1:tx42', - bookmarks: ['neo4j:bookmark:v1:tx1', 'neo4j:bookmark:v1:tx3', 'neo4j:bookmark:v1:tx42', 'neo4j:bookmark:v1:tx5'] - }); - }); + bookmarks: [ + 'neo4j:bookmark:v1:tx1', + 'neo4j:bookmark:v1:tx3', + 'neo4j:bookmark:v1:tx42', + 'neo4j:bookmark:v1:tx5' + ] + }) + }) it('should expose bookmark values', () => { - expect(new Bookmark(undefined).values()).toEqual([]); - expect(new Bookmark(null).values()).toEqual([]); + expect(new Bookmark(undefined).values()).toEqual([]) + expect(new Bookmark(null).values()).toEqual([]) - const bookmarkString = 'neo4j:bookmark:v1:tx123'; - expect(new Bookmark(bookmarkString).values()).toEqual([bookmarkString]); + const bookmarkString = 'neo4j:bookmark:v1:tx123' + expect(new Bookmark(bookmarkString).values()).toEqual([bookmarkString]) - const bookmarkStrings = ['neo4j:bookmark:v1:tx1', 'neo4j:bookmark:v1:tx2', 'neo4j:bookmark:v1:tx3']; - expect(new Bookmark(bookmarkStrings).values()).toEqual(bookmarkStrings); - }); + const bookmarkStrings = [ + 'neo4j:bookmark:v1:tx1', + 'neo4j:bookmark:v1:tx2', + 'neo4j:bookmark:v1:tx3' + ] + expect(new Bookmark(bookmarkStrings).values()).toEqual(bookmarkStrings) + }) it('should expose empty bookmark value', () => { - const bookmark = Bookmark.empty(); - expect(bookmark).toBeDefined(); - expect(bookmark.isEmpty()).toBeTruthy(); - }); - -}); + const bookmark = Bookmark.empty() + expect(bookmark).toBeDefined() + expect(bookmark.isEmpty()).toBeTruthy() + }) +}) diff --git a/test/internal/browser/browser-channel.test.js b/test/internal/browser/browser-channel.test.js index a1168706f..dfca43768 100644 --- a/test/internal/browser/browser-channel.test.js +++ b/test/internal/browser/browser-channel.test.js @@ -17,199 +17,223 @@ * limitations under the License. */ -import WebSocketChannel from '../../../src/v1/internal/browser/browser-channel'; -import ChannelConfig from '../../../src/v1/internal/channel-config'; -import urlUtil from '../../../src/v1/internal/url-util'; -import {Neo4jError, SERVICE_UNAVAILABLE} from '../../../src/v1/error'; -import {setTimeoutMock} from '../timers-util'; -import {ENCRYPTION_OFF, ENCRYPTION_ON} from '../../../src/v1/internal/util'; -import ServerAddress from '../../../src/v1/internal/server-address'; - +import WebSocketChannel from '../../../src/v1/internal/browser/browser-channel' +import ChannelConfig from '../../../src/v1/internal/channel-config' +import { SERVICE_UNAVAILABLE } from '../../../src/v1/error' +import { setTimeoutMock } from '../timers-util' +import { ENCRYPTION_OFF, ENCRYPTION_ON } from '../../../src/v1/internal/util' +import ServerAddress from '../../../src/v1/internal/server-address' + +/* eslint-disable no-global-assign */ describe('WebSocketChannel', () => { - - let OriginalWebSocket; - let webSocketChannel; - let originalConsoleWarn; + let OriginalWebSocket + let webSocketChannel + let originalConsoleWarn beforeEach(() => { - OriginalWebSocket = WebSocket; - originalConsoleWarn = console.warn; + OriginalWebSocket = WebSocket + originalConsoleWarn = console.warn console.warn = () => { // mute by default - }; - }); + } + }) afterEach(() => { - WebSocket = OriginalWebSocket; + WebSocket = OriginalWebSocket if (webSocketChannel) { - webSocketChannel.close(); + webSocketChannel.close() } - console.warn = originalConsoleWarn; - }); + console.warn = originalConsoleWarn + }) it('should fallback to literal IPv6 when SyntaxError is thrown', () => { - testFallbackToLiteralIPv6('bolt://[::1]:7687', 'ws://--1.ipv6-literal.net:7687'); - }); + testFallbackToLiteralIPv6( + 'bolt://[::1]:7687', + 'ws://--1.ipv6-literal.net:7687' + ) + }) it('should fallback to literal link-local IPv6 when SyntaxError is thrown', () => { - testFallbackToLiteralIPv6('bolt://[fe80::1%lo0]:8888', 'ws://fe80--1slo0.ipv6-literal.net:8888'); - }); + testFallbackToLiteralIPv6( + 'bolt://[fe80::1%lo0]:8888', + 'ws://fe80--1slo0.ipv6-literal.net:8888' + ) + }) it('should clear connection timeout when closed', () => { - const fakeSetTimeout = setTimeoutMock.install(); + const fakeSetTimeout = setTimeoutMock.install() try { // do not execute setTimeout callbacks - fakeSetTimeout.pause(); + fakeSetTimeout.pause() - let fakeWebSocketClosed = false; + let fakeWebSocketClosed = false // replace real WebSocket with a function that does nothing WebSocket = () => { return { close: () => { - fakeWebSocketClosed = true; + fakeWebSocketClosed = true } - }; - }; + } + } - const address = ServerAddress.fromUrl('bolt://localhost:8989'); - const driverConfig = {connectionTimeout: 4242}; - const channelConfig = new ChannelConfig(address, driverConfig, SERVICE_UNAVAILABLE); + const address = ServerAddress.fromUrl('bolt://localhost:8989') + const driverConfig = { connectionTimeout: 4242 } + const channelConfig = new ChannelConfig( + address, + driverConfig, + SERVICE_UNAVAILABLE + ) - webSocketChannel = new WebSocketChannel(channelConfig); + webSocketChannel = new WebSocketChannel(channelConfig) - expect(fakeWebSocketClosed).toBeFalsy(); - expect(fakeSetTimeout.invocationDelays).toEqual([]); - expect(fakeSetTimeout.clearedTimeouts).toEqual([]); + expect(fakeWebSocketClosed).toBeFalsy() + expect(fakeSetTimeout.invocationDelays).toEqual([]) + expect(fakeSetTimeout.clearedTimeouts).toEqual([]) - webSocketChannel.close(); + webSocketChannel.close() - expect(fakeWebSocketClosed).toBeTruthy(); - expect(fakeSetTimeout.invocationDelays).toEqual([]); - expect(fakeSetTimeout.clearedTimeouts).toEqual([0]); // cleared one timeout with id 0 + expect(fakeWebSocketClosed).toBeTruthy() + expect(fakeSetTimeout.invocationDelays).toEqual([]) + expect(fakeSetTimeout.clearedTimeouts).toEqual([0]) // cleared one timeout with id 0 } finally { - fakeSetTimeout.uninstall(); + fakeSetTimeout.uninstall() } - }); + }) it('should select wss when running on https page', () => { - testWebSocketScheme('https:', {}, 'wss'); - }); + testWebSocketScheme('https:', {}, 'wss') + }) it('should select ws when running on http page', () => { - testWebSocketScheme('http:', {}, 'ws'); - }); + testWebSocketScheme('http:', {}, 'ws') + }) it('should select ws when running on https page but encryption turned off with boolean', () => { - testWebSocketScheme('https:', {encrypted: false}, 'ws'); - }); + testWebSocketScheme('https:', { encrypted: false }, 'ws') + }) it('should select ws when running on https page but encryption turned off with string', () => { - testWebSocketScheme('https:', {encrypted: ENCRYPTION_OFF}, 'ws'); - }); + testWebSocketScheme('https:', { encrypted: ENCRYPTION_OFF }, 'ws') + }) it('should select wss when running on http page but encryption configured with boolean', () => { - testWebSocketScheme('http:', {encrypted: true}, 'wss'); - }); + testWebSocketScheme('http:', { encrypted: true }, 'wss') + }) it('should select wss when running on http page but encryption configured with string', () => { - testWebSocketScheme('http:', {encrypted: ENCRYPTION_ON}, 'wss'); - }); + testWebSocketScheme('http:', { encrypted: ENCRYPTION_ON }, 'wss') + }) it('should fail when encryption configured with unsupported trust strategy', () => { - const protocolSupplier = () => 'http:'; + const protocolSupplier = () => 'http:' WebSocket = () => { return { - close: () => { - } - }; - }; + close: () => {} + } + } - const address = ServerAddress.fromUrl('bolt://localhost:8989'); - const driverConfig = {encrypted: true, trust: 'TRUST_ON_FIRST_USE'}; - const channelConfig = new ChannelConfig(address, driverConfig, SERVICE_UNAVAILABLE); + const address = ServerAddress.fromUrl('bolt://localhost:8989') + const driverConfig = { encrypted: true, trust: 'TRUST_ON_FIRST_USE' } + const channelConfig = new ChannelConfig( + address, + driverConfig, + SERVICE_UNAVAILABLE + ) - const channel = new WebSocketChannel(channelConfig, protocolSupplier); + const channel = new WebSocketChannel(channelConfig, protocolSupplier) - expect(channel._error).toBeDefined(); - expect(channel._error.name).toEqual('Neo4jError'); - }); + expect(channel._error).toBeDefined() + expect(channel._error.name).toEqual('Neo4jError') + }) it('should generate a warning when encryption turned on for HTTP web page', () => { - testWarningInMixedEnvironment(true, 'http'); - testWarningInMixedEnvironment(ENCRYPTION_ON, 'http'); - }); + testWarningInMixedEnvironment(true, 'http') + testWarningInMixedEnvironment(ENCRYPTION_ON, 'http') + }) it('should generate a warning when encryption turned off for HTTPS web page', () => { - testWarningInMixedEnvironment(false, 'https'); - testWarningInMixedEnvironment(ENCRYPTION_OFF, 'https'); - }); + testWarningInMixedEnvironment(false, 'https') + testWarningInMixedEnvironment(ENCRYPTION_OFF, 'https') + }) - function testFallbackToLiteralIPv6(boltAddress, expectedWsAddress) { + function testFallbackToLiteralIPv6 (boltAddress, expectedWsAddress) { // replace real WebSocket with a function that throws when IPv6 address is used WebSocket = url => { if (url.indexOf('[') !== -1) { - throw new SyntaxError(); + throw new SyntaxError() } return { url: url, - close: () => { - } - }; - }; + close: () => {} + } + } - const address = ServerAddress.fromUrl(boltAddress); + const address = ServerAddress.fromUrl(boltAddress) // disable connection timeout, so that WebSocketChannel does not set any timeouts - const driverConfig = {connectionTimeout: 0}; - const channelConfig = new ChannelConfig(address, driverConfig, SERVICE_UNAVAILABLE); + const driverConfig = { connectionTimeout: 0 } + const channelConfig = new ChannelConfig( + address, + driverConfig, + SERVICE_UNAVAILABLE + ) - webSocketChannel = new WebSocketChannel(channelConfig); + webSocketChannel = new WebSocketChannel(channelConfig) - expect(webSocketChannel._ws.url).toEqual(expectedWsAddress); + expect(webSocketChannel._ws.url).toEqual(expectedWsAddress) } - function testWebSocketScheme(windowLocationProtocol, driverConfig, expectedScheme) { - const protocolSupplier = () => windowLocationProtocol; + function testWebSocketScheme ( + windowLocationProtocol, + driverConfig, + expectedScheme + ) { + const protocolSupplier = () => windowLocationProtocol // replace real WebSocket with a function that memorizes the url WebSocket = url => { return { url: url, - close: () => { - } - }; - }; + close: () => {} + } + } - const address = ServerAddress.fromUrl('bolt://localhost:8989'); - const channelConfig = new ChannelConfig(address, driverConfig, SERVICE_UNAVAILABLE); - const channel = new WebSocketChannel(channelConfig, protocolSupplier); + const address = ServerAddress.fromUrl('bolt://localhost:8989') + const channelConfig = new ChannelConfig( + address, + driverConfig, + SERVICE_UNAVAILABLE + ) + const channel = new WebSocketChannel(channelConfig, protocolSupplier) - expect(channel._ws.url).toEqual(expectedScheme + '://localhost:8989'); + expect(channel._ws.url).toEqual(expectedScheme + '://localhost:8989') } - function testWarningInMixedEnvironment(encrypted, scheme) { + function testWarningInMixedEnvironment (encrypted, scheme) { // replace real WebSocket with a function that memorizes the url WebSocket = url => { return { url: url, - close: () => { - } - }; - }; + close: () => {} + } + } // replace console.warn with a function that memorizes the message - const warnMessages = []; - console.warn = message => warnMessages.push(message); + const warnMessages = [] + console.warn = message => warnMessages.push(message) - const address = ServerAddress.fromUrl('bolt://localhost:8989'); - const config = new ChannelConfig(address, {encrypted: encrypted}, SERVICE_UNAVAILABLE); - const protocolSupplier = () => scheme + ':'; + const address = ServerAddress.fromUrl('bolt://localhost:8989') + const config = new ChannelConfig( + address, + { encrypted: encrypted }, + SERVICE_UNAVAILABLE + ) + const protocolSupplier = () => scheme + ':' - const channel = new WebSocketChannel(config, protocolSupplier); + const channel = new WebSocketChannel(config, protocolSupplier) - expect(channel).toBeDefined(); - expect(warnMessages.length).toEqual(1); + expect(channel).toBeDefined() + expect(warnMessages.length).toEqual(1) } - -}); +}) diff --git a/test/internal/browser/browser-host-name-resolver.test.js b/test/internal/browser/browser-host-name-resolver.test.js index 8c3947321..c640dee7a 100644 --- a/test/internal/browser/browser-host-name-resolver.test.js +++ b/test/internal/browser/browser-host-name-resolver.test.js @@ -17,30 +17,28 @@ * limitations under the License. */ -import BrowserHostNameResolver from '../../../src/v1/internal/browser/browser-host-name-resolver'; +import BrowserHostNameResolver from '../../../src/v1/internal/browser/browser-host-name-resolver' describe('BrowserHostNameResolver', () => { - it('should resolve given address to itself', done => { - const seedRouter = 'localhost'; - const resolver = new BrowserHostNameResolver(); + const seedRouter = 'localhost' + const resolver = new BrowserHostNameResolver() resolver.resolve(seedRouter).then(addresses => { - expect(addresses.length).toEqual(1); - expect(addresses[0]).toEqual(seedRouter); - done(); - }); - }); + expect(addresses.length).toEqual(1) + expect(addresses[0]).toEqual(seedRouter) + done() + }) + }) it('should resolve given address with port to itself', done => { - const seedRouter = 'localhost:7474'; - const resolver = new BrowserHostNameResolver(); + const seedRouter = 'localhost:7474' + const resolver = new BrowserHostNameResolver() resolver.resolve(seedRouter).then(addresses => { - expect(addresses.length).toEqual(1); - expect(addresses[0]).toEqual(seedRouter); - done(); - }); - }); - -}); + expect(addresses.length).toEqual(1) + expect(addresses[0]).toEqual(seedRouter) + done() + }) + }) +}) diff --git a/test/internal/buf.test.js b/test/internal/buf.test.js index dae0e0f8e..b51754c58 100644 --- a/test/internal/buf.test.js +++ b/test/internal/buf.test.js @@ -17,189 +17,187 @@ * limitations under the License. */ -import {Unpacker} from '../../src/v1/internal/packstream-v1'; -import CombinedBuffer from '../../src/v1/internal/buf/combined-buf'; -import {alloc, utf8} from '../../src/v1/internal/node'; +import { Unpacker } from '../../src/v1/internal/packstream-v1' +import CombinedBuffer from '../../src/v1/internal/buf/combined-buf' +import { alloc, utf8 } from '../../src/v1/internal/node' describe('buffers', () => { - it('should have helpful toString', () => { // Given - const b = alloc(4); - b.writeInt8(1); - b.writeInt8(8); - b.writeInt8(15); - b.writeInt8(127); + const b = alloc(4) + b.writeInt8(1) + b.writeInt8(8) + b.writeInt8(15) + b.writeInt8(127) // When - const str = b.toString(); - const hex = b.toHex(); + const str = b.toString() + const hex = b.toHex() // Then - expect(str).toContain('( position=4 )\n 01 08 0f 7f'); - expect(hex).toBe('01 08 0f 7f'); - }); + expect(str).toContain('( position=4 )\n 01 08 0f 7f') + expect(hex).toBe('01 08 0f 7f') + }) it('should read and write 8-bit unsigned integers', () => { // Given - const b = alloc(1); + const b = alloc(1) for (let i = 0; i < 7; i++) { - const n = Math.pow(2, i); + const n = Math.pow(2, i) // When - b.putUInt8(0, n); + b.putUInt8(0, n) // Then - expect(b.getUInt8(0)).toBe(n); + expect(b.getUInt8(0)).toBe(n) } - }); + }) it('should read and write 16-bit unsigned integers', () => { // Given - const b = alloc(2); + const b = alloc(2) for (let i = 0; i < 15; i++) { - const n = Math.pow(2, i); + const n = Math.pow(2, i) // When - b.putUInt16(0, n); + b.putUInt16(0, n) // Then - expect(b.getUInt16(0)).toBe(n); + expect(b.getUInt16(0)).toBe(n) } - }); + }) it('should read and write 32-bit unsigned integers', () => { // Given - const b = alloc(4); + const b = alloc(4) for (let i = 0; i < 30; i++) { - const n = Math.pow(2, i); + const n = Math.pow(2, i) // When - b.putUInt32(0, n); + b.putUInt32(0, n) // Then - expect(b.getUInt32(0)).toBe(n); + expect(b.getUInt32(0)).toBe(n) } - }); + }) it('should read and write 8-bit signed integers', () => { // Given - const b = alloc(1); + const b = alloc(1) for (let i = 0; i < 6; i++) { - const n = Math.pow(2, i); + const n = Math.pow(2, i) // When - b.putInt8(0, n); + b.putInt8(0, n) // Then - expect(b.getInt8(0)).toBe(n); + expect(b.getInt8(0)).toBe(n) } - }); + }) it('should read and write 16-bit signed integers', () => { // Given - const b = alloc(2); + const b = alloc(2) for (let i = 0; i < 14; i++) { - const n = Math.pow(2, i); + const n = Math.pow(2, i) // When - b.putInt16(0, n); + b.putInt16(0, n) // Then - expect(b.getInt16(0)).toBe(n); + expect(b.getInt16(0)).toBe(n) } - }); + }) it('should read and write 32-bit signed integers', () => { // Given - const b = alloc(4); + const b = alloc(4) for (let i = 0; i < 30; i++) { - const n = Math.pow(2, i); + const n = Math.pow(2, i) // When - b.putInt32(0, n); + b.putInt32(0, n) // Then - expect(b.getInt32(0)).toBe(n); + expect(b.getInt32(0)).toBe(n) } - }); + }) it('should encode list correctly', () => { // Given - let b = alloc(5); - b.writeUInt8(0x90 | 0x2); - b = writeString(b, 'a'); - b = writeString(b, 'b'); + let b = alloc(5) + b.writeUInt8(0x90 | 0x2) + b = writeString(b, 'a') + b = writeString(b, 'b') // When - const hex = b.toHex(); + const hex = b.toHex() // Then - expect(hex).toBe('92 81 61 81 62'); - }); + expect(hex).toBe('92 81 61 81 62') + }) it('should decode list correctly', () => { // Given - const b = alloc(5); - b.writeUInt8(0x92); - b.writeUInt8(0x81); - b.writeUInt8(0x61); - b.writeUInt8(0x81); - b.writeUInt8(0x62); - b.reset(); + const b = alloc(5) + b.writeUInt8(0x92) + b.writeUInt8(0x81) + b.writeUInt8(0x61) + b.writeUInt8(0x81) + b.writeUInt8(0x62) + b.reset() // When - const data = new Unpacker().unpack(b); + const data = new Unpacker().unpack(b) // Then - expect(data[0]).toBe('a'); - expect(data[1]).toBe('b'); - }); -}); + expect(data[0]).toBe('a') + expect(data[1]).toBe('b') + }) +}) describe('CombinedBuffer', () => { - it('should read int8', () => { // Given - const b1 = alloc(1); - const b2 = alloc(1); - b1.putInt8(0, 1); - b2.putInt8(0, 2); + const b1 = alloc(1) + const b2 = alloc(1) + b1.putInt8(0, 1) + b2.putInt8(0, 2) - const b = new CombinedBuffer([b1, b2]); + const b = new CombinedBuffer([b1, b2]) // When - const first = b.readInt8(); - const second = b.readInt8(); + const first = b.readInt8() + const second = b.readInt8() // Then - expect(first).toBe(1); - expect(second).toBe(2); - }); + expect(first).toBe(1) + expect(second).toBe(2) + }) it('should read divided float64', () => { // Given - const inner = alloc(8); - inner.putFloat64(0, 0.1); + const inner = alloc(8) + inner.putFloat64(0, 0.1) - const b = new CombinedBuffer([inner.readSlice(4), inner.readSlice(4)]); + const b = new CombinedBuffer([inner.readSlice(4), inner.readSlice(4)]) // When - const read = b.readFloat64(); + const read = b.readFloat64() // Then - expect(read).toBe(0.1); - }); -}); - -function writeString(b, str) { - const bytes = utf8.encode(str); - const size = bytes.length; - b.writeUInt8(0x80 | size); - b.writeBytes(bytes); - return b; + expect(read).toBe(0.1) + }) +}) + +function writeString (b, str) { + const bytes = utf8.encode(str) + const size = bytes.length + b.writeUInt8(0x80 | size) + b.writeBytes(bytes) + return b } diff --git a/test/internal/channel-config.test.js b/test/internal/channel-config.test.js index c80f0f26c..4bfb6e65b 100644 --- a/test/internal/channel-config.test.js +++ b/test/internal/channel-config.test.js @@ -17,146 +17,185 @@ * limitations under the License. */ -import ChannelConfig from '../../src/v1/internal/channel-config'; -import urlUtil from '../../src/v1/internal/url-util'; -import {SERVICE_UNAVAILABLE} from '../../src/v1/error'; -import {ENCRYPTION_OFF, ENCRYPTION_ON} from '../../src/v1/internal/util'; -import ServerAddress from '../../src/v1/internal/server-address'; +import ChannelConfig from '../../src/v1/internal/channel-config' +import { SERVICE_UNAVAILABLE } from '../../src/v1/error' +import { ENCRYPTION_OFF, ENCRYPTION_ON } from '../../src/v1/internal/util' +import ServerAddress from '../../src/v1/internal/server-address' describe('ChannelConfig', () => { - it('should respect given Url', () => { - const address = ServerAddress.fromUrl('bolt://neo4j.com:4242'); + const address = ServerAddress.fromUrl('bolt://neo4j.com:4242') - const config = new ChannelConfig(address, {}, ''); + const config = new ChannelConfig(address, {}, '') - expect(config.address.host()).toEqual('neo4j.com'); - expect(config.address.port()).toEqual(4242); - }); + expect(config.address.host()).toEqual('neo4j.com') + expect(config.address.port()).toEqual(4242) + }) it('should respect given encrypted conf', () => { - const encrypted = 'ENCRYPTION_ON'; + const encrypted = 'ENCRYPTION_ON' - const config = new ChannelConfig(null, {encrypted: encrypted}, ''); + const config = new ChannelConfig(null, { encrypted: encrypted }, '') - expect(config.encrypted).toEqual(encrypted); - }); + expect(config.encrypted).toEqual(encrypted) + }) it('should respect given trust conf', () => { - const trust = 'TRUST_ALL_CERTIFICATES'; + const trust = 'TRUST_ALL_CERTIFICATES' - const config = new ChannelConfig(null, {trust: trust}, ''); + const config = new ChannelConfig(null, { trust: trust }, '') - expect(config.trust).toEqual(trust); - }); + expect(config.trust).toEqual(trust) + }) it('should respect given trusted certificates conf', () => { - const trustedCertificates = ['./foo.pem', './bar.pem', './baz.pem']; + const trustedCertificates = ['./foo.pem', './bar.pem', './baz.pem'] - const config = new ChannelConfig(null, {trustedCertificates: trustedCertificates}, ''); + const config = new ChannelConfig( + null, + { trustedCertificates: trustedCertificates }, + '' + ) - expect(config.trustedCertificates).toEqual(trustedCertificates); - }); + expect(config.trustedCertificates).toEqual(trustedCertificates) + }) it('should respect given known hosts', () => { - const knownHostsPath = '~/.neo4j/known_hosts'; + const knownHostsPath = '~/.neo4j/known_hosts' - const config = new ChannelConfig(null, {knownHosts: knownHostsPath}, ''); + const config = new ChannelConfig(null, { knownHosts: knownHostsPath }, '') - expect(config.knownHostsPath).toEqual(knownHostsPath); - }); + expect(config.knownHostsPath).toEqual(knownHostsPath) + }) it('should respect given connection error code', () => { - const connectionErrorCode = 'ConnectionFailed'; + const connectionErrorCode = 'ConnectionFailed' - const config = new ChannelConfig(null, {}, connectionErrorCode); + const config = new ChannelConfig(null, {}, connectionErrorCode) - expect(config.connectionErrorCode).toEqual(connectionErrorCode); - }); + expect(config.connectionErrorCode).toEqual(connectionErrorCode) + }) it('should expose encryption when nothing configured', () => { - const config = new ChannelConfig(null, {}, ''); + const config = new ChannelConfig(null, {}, '') - expect(config.encrypted).toBeUndefined(); - }); + expect(config.encrypted).toBeUndefined() + }) it('should expose trust when nothing configured', () => { - const config = new ChannelConfig(null, {}, ''); + const config = new ChannelConfig(null, {}, '') - expect(config.trust).toBeUndefined(); - }); + expect(config.trust).toBeUndefined() + }) it('should have no trusted certificates when not configured', () => { - const config = new ChannelConfig(null, {}, ''); + const config = new ChannelConfig(null, {}, '') - expect(config.trustedCertificates).toEqual([]); - }); + expect(config.trustedCertificates).toEqual([]) + }) it('should have null known hosts path when not configured', () => { - const config = new ChannelConfig(null, {}, ''); + const config = new ChannelConfig(null, {}, '') - expect(config.knownHostsPath).toBeNull(); - }); + expect(config.knownHostsPath).toBeNull() + }) it('should have service unavailable as default error code', () => { - const config = new ChannelConfig(null, {}, ''); + const config = new ChannelConfig(null, {}, '') - expect(config.connectionErrorCode).toEqual(SERVICE_UNAVAILABLE); - }); + expect(config.connectionErrorCode).toEqual(SERVICE_UNAVAILABLE) + }) it('should have connection timeout by default', () => { - const config = new ChannelConfig(null, {}, ''); + const config = new ChannelConfig(null, {}, '') - expect(config.connectionTimeout).toEqual(5000); - }); + expect(config.connectionTimeout).toEqual(5000) + }) it('should respect configured connection timeout', () => { - const config = new ChannelConfig(null, {connectionTimeout: 424242}, ''); + const config = new ChannelConfig(null, { connectionTimeout: 424242 }, '') - expect(config.connectionTimeout).toEqual(424242); - }); + expect(config.connectionTimeout).toEqual(424242) + }) it('should respect disabled connection timeout with value zero', () => { - const config = new ChannelConfig(null, {connectionTimeout: 0}, ''); + const config = new ChannelConfig(null, { connectionTimeout: 0 }, '') - expect(config.connectionTimeout).toBeNull(); - }); + expect(config.connectionTimeout).toBeNull() + }) it('should respect disabled connection timeout with negative value', () => { - const config = new ChannelConfig(null, {connectionTimeout: -42}, ''); + const config = new ChannelConfig(null, { connectionTimeout: -42 }, '') - expect(config.connectionTimeout).toBeNull(); - }); + expect(config.connectionTimeout).toBeNull() + }) it('should validate value of "encrypted" property', () => { - expect(new ChannelConfig(null, {encrypted: null}, '').encrypted).toBeNull(); - expect(new ChannelConfig(null, {encrypted: undefined}, '').encrypted).toBeUndefined(); - expect(new ChannelConfig(null, {encrypted: true}, '').encrypted).toBeTruthy(); - expect(new ChannelConfig(null, {encrypted: false}, '').encrypted).toBeFalsy(); - expect(new ChannelConfig(null, {encrypted: ENCRYPTION_ON}, '').encrypted).toEqual(ENCRYPTION_ON); - expect(new ChannelConfig(null, {encrypted: ENCRYPTION_OFF}, '').encrypted).toEqual(ENCRYPTION_OFF); - - expect(() => new ChannelConfig(null, {encrypted: []}, '')).toThrow(); - expect(() => new ChannelConfig(null, {encrypted: {}}, '')).toThrow(); - expect(() => new ChannelConfig(null, {encrypted: () => 'Hello'}, '')).toThrow(); - expect(() => new ChannelConfig(null, {encrypted: 42}, '')).toThrow(); - expect(() => new ChannelConfig(null, {encrypted: 'Hello'}, '')).toThrow(); - }); + expect( + new ChannelConfig(null, { encrypted: null }, '').encrypted + ).toBeNull() + expect( + new ChannelConfig(null, { encrypted: undefined }, '').encrypted + ).toBeUndefined() + expect( + new ChannelConfig(null, { encrypted: true }, '').encrypted + ).toBeTruthy() + expect( + new ChannelConfig(null, { encrypted: false }, '').encrypted + ).toBeFalsy() + expect( + new ChannelConfig(null, { encrypted: ENCRYPTION_ON }, '').encrypted + ).toEqual(ENCRYPTION_ON) + expect( + new ChannelConfig(null, { encrypted: ENCRYPTION_OFF }, '').encrypted + ).toEqual(ENCRYPTION_OFF) + + expect(() => new ChannelConfig(null, { encrypted: [] }, '')).toThrow() + expect(() => new ChannelConfig(null, { encrypted: {} }, '')).toThrow() + expect( + () => new ChannelConfig(null, { encrypted: () => 'Hello' }, '') + ).toThrow() + expect(() => new ChannelConfig(null, { encrypted: 42 }, '')).toThrow() + expect(() => new ChannelConfig(null, { encrypted: 'Hello' }, '')).toThrow() + }) it('should validate value of "trust" property', () => { - expect(new ChannelConfig(null, {trust: null}, '').trust).toBeNull(); - expect(new ChannelConfig(null, {trust: undefined}, '').trust).toBeUndefined(); - expect(new ChannelConfig(null, {trust: 'TRUST_ALL_CERTIFICATES'}, '').trust).toEqual('TRUST_ALL_CERTIFICATES'); - expect(new ChannelConfig(null, {trust: 'TRUST_ON_FIRST_USE'}, '').trust).toEqual('TRUST_ON_FIRST_USE'); - expect(new ChannelConfig(null, {trust: 'TRUST_SIGNED_CERTIFICATES'}, '').trust).toEqual('TRUST_SIGNED_CERTIFICATES'); - expect(new ChannelConfig(null, {trust: 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES'}, '').trust).toEqual('TRUST_CUSTOM_CA_SIGNED_CERTIFICATES'); - expect(new ChannelConfig(null, {trust: 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'}, '').trust).toEqual('TRUST_SYSTEM_CA_SIGNED_CERTIFICATES'); - - expect(() => new ChannelConfig(null, {trust: []}, '')).toThrow(); - expect(() => new ChannelConfig(null, {trust: {}}, '')).toThrow(); - expect(() => new ChannelConfig(null, {trust: () => 'Trust'}, '')).toThrow(); - expect(() => new ChannelConfig(null, {trust: 42}, '')).toThrow(); - expect(() => new ChannelConfig(null, {trust: 'SOME_WRONG_TRUST_STRATEGY'}, '')).toThrow(); - }); - -}); + expect(new ChannelConfig(null, { trust: null }, '').trust).toBeNull() + expect( + new ChannelConfig(null, { trust: undefined }, '').trust + ).toBeUndefined() + expect( + new ChannelConfig(null, { trust: 'TRUST_ALL_CERTIFICATES' }, '').trust + ).toEqual('TRUST_ALL_CERTIFICATES') + expect( + new ChannelConfig(null, { trust: 'TRUST_ON_FIRST_USE' }, '').trust + ).toEqual('TRUST_ON_FIRST_USE') + expect( + new ChannelConfig(null, { trust: 'TRUST_SIGNED_CERTIFICATES' }, '').trust + ).toEqual('TRUST_SIGNED_CERTIFICATES') + expect( + new ChannelConfig( + null, + { trust: 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' }, + '' + ).trust + ).toEqual('TRUST_CUSTOM_CA_SIGNED_CERTIFICATES') + expect( + new ChannelConfig( + null, + { trust: 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES' }, + '' + ).trust + ).toEqual('TRUST_SYSTEM_CA_SIGNED_CERTIFICATES') + + expect(() => new ChannelConfig(null, { trust: [] }, '')).toThrow() + expect(() => new ChannelConfig(null, { trust: {} }, '')).toThrow() + expect( + () => new ChannelConfig(null, { trust: () => 'Trust' }, '') + ).toThrow() + expect(() => new ChannelConfig(null, { trust: 42 }, '')).toThrow() + expect( + () => new ChannelConfig(null, { trust: 'SOME_WRONG_TRUST_STRATEGY' }, '') + ).toThrow() + }) +}) diff --git a/test/internal/chunking.test.js b/test/internal/chunking.test.js index b555df44c..9c6e5ad9d 100644 --- a/test/internal/chunking.test.js +++ b/test/internal/chunking.test.js @@ -17,122 +17,120 @@ * limitations under the License. */ -import {Chunker, Dechunker} from '../../src/v1/internal/chunking'; -import {alloc} from '../../src/v1/internal/node'; -import DummyChannel from './dummy-channel'; +import { Chunker, Dechunker } from '../../src/v1/internal/chunking' +import { alloc } from '../../src/v1/internal/node' +import DummyChannel from './dummy-channel' describe('Chunker', () => { - it('should chunk simple data', () => { // Given - const ch = new DummyChannel(); - const chunker = new Chunker(ch); + const ch = new DummyChannel() + const chunker = new Chunker(ch) // When - chunker.writeInt32(1); - chunker.writeInt32(2); - chunker.flush(); + chunker.writeInt32(1) + chunker.writeInt32(2) + chunker.flush() // Then - expect(ch.toHex()).toBe('00 08 00 00 00 01 00 00 00 02'); - }); + expect(ch.toHex()).toBe('00 08 00 00 00 01 00 00 00 02') + }) it('should chunk blobs larger than the output buffer', () => { // Given - const ch = new DummyChannel(); - const chunker = new Chunker(ch, 4); + const ch = new DummyChannel() + const chunker = new Chunker(ch, 4) // When - chunker.writeBytes(bytes( 1,2,3,4,5,6 )); - chunker.flush(); + chunker.writeBytes(bytes(1, 2, 3, 4, 5, 6)) + chunker.flush() // Then - expect(ch.toHex()).toBe('00 02 01 02 00 02 03 04 00 02 05 06'); - }); + expect(ch.toHex()).toBe('00 02 01 02 00 02 03 04 00 02 05 06') + }) it('should include message boundaries', () => { // Given - const ch = new DummyChannel(); - const chunker = new Chunker(ch); + const ch = new DummyChannel() + const chunker = new Chunker(ch) // When - chunker.writeInt32(1); - chunker.messageBoundary(); - chunker.writeInt32(2); - chunker.flush(); + chunker.writeInt32(1) + chunker.messageBoundary() + chunker.writeInt32(2) + chunker.flush() // Then - expect(ch.toHex()).toBe('00 04 00 00 00 01 00 00 00 04 00 00 00 02'); - }); -}); + expect(ch.toHex()).toBe('00 04 00 00 00 01 00 00 00 04 00 00 00 02') + }) +}) describe('Dechunker', () => { - it('should unchunk a simple message', () => { // Given - const messages = []; - const dechunker = new Dechunker(); - const chunker = new Chunker(dechunker); + const messages = [] + const dechunker = new Dechunker() + const chunker = new Chunker(dechunker) dechunker.onmessage = buffer => { - messages.push(buffer); - }; + messages.push(buffer) + } // When - chunker.writeInt16(1); - chunker.writeInt16(2); - chunker.flush(); - chunker.writeInt16(3); - chunker.messageBoundary(); - chunker.flush(); + chunker.writeInt16(1) + chunker.writeInt16(2) + chunker.flush() + chunker.writeInt16(3) + chunker.messageBoundary() + chunker.flush() // Then - expect( messages.length ).toBe( 1 ); - expect(messages[0].toHex()).toBe('00 01 00 02 00 03'); - }); + expect(messages.length).toBe(1) + expect(messages[0].toHex()).toBe('00 01 00 02 00 03') + }) it('should handle message split at any point', () => { // Given - const ch = new DummyChannel(); - const chunker = new Chunker(ch); + const ch = new DummyChannel() + const chunker = new Chunker(ch) // And given the following message - chunker.writeInt8(1); - chunker.writeInt16(2); - chunker.writeInt32(3); - chunker.writeUInt8(4); - chunker.writeUInt32(5); - chunker.messageBoundary(); - chunker.flush(); + chunker.writeInt8(1) + chunker.writeInt16(2) + chunker.writeInt32(3) + chunker.writeUInt8(4) + chunker.writeUInt32(5) + chunker.messageBoundary() + chunker.flush() - const chunked = ch.toBuffer(); + const chunked = ch.toBuffer() // When I try splitting this chunked data at every possible position // into two separate buffers, and send those to the dechunker for (let i = 1; i < chunked.length; i++) { - const slice1 = chunked.getSlice(0, i); - const slice2 = chunked.getSlice(i, chunked.length - i); + const slice1 = chunked.getSlice(0, i) + const slice2 = chunked.getSlice(i, chunked.length - i) // Dechunk the slices - const messages = []; - const dechunker = new Dechunker(); + const messages = [] + const dechunker = new Dechunker() dechunker.onmessage = buffer => { - messages.push(buffer); - }; - dechunker.write( slice1 ); - dechunker.write( slice2 ); + messages.push(buffer) + } + dechunker.write(slice1) + dechunker.write(slice2) // Then, the output should be correct - expect( messages.length ).toBe( 1 ); - expect(messages[0].toHex()).toBe('01 00 02 00 00 00 03 04 00 00 00 05'); + expect(messages.length).toBe(1) + expect(messages[0].toHex()).toBe('01 00 02 00 00 00 03 04 00 00 00 05') } - }); -}); + }) +}) -function bytes() { - const b = alloc(arguments.length); +function bytes () { + const b = alloc(arguments.length) for (let i = 0; i < arguments.length; i++) { - b.writeUInt8( arguments[i] ); + b.writeUInt8(arguments[i]) } - b.position = 0; - return b; + b.position = 0 + return b } diff --git a/test/internal/connection-error-handler.test.js b/test/internal/connection-error-handler.test.js index 557e6e570..da183842b 100644 --- a/test/internal/connection-error-handler.test.js +++ b/test/internal/connection-error-handler.test.js @@ -17,61 +17,89 @@ * limitations under the License. */ -import ConnectionErrorHandler from '../../src/v1/internal/connection-error-handler'; -import {newError, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../../src/v1/error'; -import ServerAddress from '../../src/v1/internal/server-address'; +import ConnectionErrorHandler from '../../src/v1/internal/connection-error-handler' +import { + newError, + SERVICE_UNAVAILABLE, + SESSION_EXPIRED +} from '../../src/v1/error' +import ServerAddress from '../../src/v1/internal/server-address' describe('ConnectionErrorHandler', () => { - it('should return error code', () => { - const code = 'Neo4j.Error.Hello'; - const handler = new ConnectionErrorHandler(code); - expect(code).toEqual(handler.errorCode()); - }); + const code = 'Neo4j.Error.Hello' + const handler = new ConnectionErrorHandler(code) + expect(code).toEqual(handler.errorCode()) + }) it('should handle and transform availability errors', () => { - const errors = []; - const addresses = []; - const transformedError = newError('Message', 'Code'); - const handler = new ConnectionErrorHandler(SERVICE_UNAVAILABLE, (error, address) => { - errors.push(error); - addresses.push(address); - return transformedError; - }); + const errors = [] + const addresses = [] + const transformedError = newError('Message', 'Code') + const handler = new ConnectionErrorHandler( + SERVICE_UNAVAILABLE, + (error, address) => { + errors.push(error) + addresses.push(address) + return transformedError + } + ) - const error1 = newError('A', SERVICE_UNAVAILABLE); - const error2 = newError('B', SESSION_EXPIRED); - const error3 = newError('C', 'Neo.TransientError.General.DatabaseUnavailable'); + const error1 = newError('A', SERVICE_UNAVAILABLE) + const error2 = newError('B', SESSION_EXPIRED) + const error3 = newError( + 'C', + 'Neo.TransientError.General.DatabaseUnavailable' + ) - [error1, error2, error3].forEach((error, idx) => { - const newTransformedError = handler.handleAndTransformError(error, ServerAddress.fromUrl('localhost:' + idx)); - expect(newTransformedError).toEqual(transformedError); - }); + ;[error1, error2, error3].forEach((error, idx) => { + const newTransformedError = handler.handleAndTransformError( + error, + ServerAddress.fromUrl('localhost:' + idx) + ) + expect(newTransformedError).toEqual(transformedError) + }) - expect(errors).toEqual([error1, error2, error3]); - expect(addresses).toEqual([ServerAddress.fromUrl('localhost:0'), ServerAddress.fromUrl('localhost:1'), ServerAddress.fromUrl('localhost:2')]); - }); + expect(errors).toEqual([error1, error2, error3]) + expect(addresses).toEqual([ + ServerAddress.fromUrl('localhost:0'), + ServerAddress.fromUrl('localhost:1'), + ServerAddress.fromUrl('localhost:2') + ]) + }) it('should handle and transform failure to write errors', () => { - const errors = []; - const addresses = []; - const transformedError = newError('Message', 'Code'); - const handler = new ConnectionErrorHandler(SERVICE_UNAVAILABLE, null, (error, address) => { - errors.push(error); - addresses.push(address); - return transformedError; - }); - - const error1 = newError('A', 'Neo.ClientError.Cluster.NotALeader'); - const error2 = newError('B', 'Neo.ClientError.General.ForbiddenOnReadOnlyDatabase'); + const errors = [] + const addresses = [] + const transformedError = newError('Message', 'Code') + const handler = new ConnectionErrorHandler( + SERVICE_UNAVAILABLE, + null, + (error, address) => { + errors.push(error) + addresses.push(address) + return transformedError + } + ) - [error1, error2].forEach((error, idx) => { - const newTransformedError = handler.handleAndTransformError(error, ServerAddress.fromUrl('localhost:' + idx)); - expect(newTransformedError).toEqual(transformedError); - }); + const error1 = newError('A', 'Neo.ClientError.Cluster.NotALeader') + const error2 = newError( + 'B', + 'Neo.ClientError.General.ForbiddenOnReadOnlyDatabase' + ) - expect(errors).toEqual([error1, error2]); - expect(addresses).toEqual([ServerAddress.fromUrl('localhost:0'), ServerAddress.fromUrl('localhost:1')]); - }); + ;[error1, error2].forEach((error, idx) => { + const newTransformedError = handler.handleAndTransformError( + error, + ServerAddress.fromUrl('localhost:' + idx) + ) + expect(newTransformedError).toEqual(transformedError) + }) -}); + expect(errors).toEqual([error1, error2]) + expect(addresses).toEqual([ + ServerAddress.fromUrl('localhost:0'), + ServerAddress.fromUrl('localhost:1') + ]) + }) +}) diff --git a/test/internal/connection-holder.test.js b/test/internal/connection-holder.test.js index b9a0ce1a8..fb1aec40d 100644 --- a/test/internal/connection-holder.test.js +++ b/test/internal/connection-holder.test.js @@ -17,220 +17,226 @@ * limitations under the License. */ -import ConnectionHolder, {EMPTY_CONNECTION_HOLDER} from '../../src/v1/internal/connection-holder'; -import {SingleConnectionProvider} from '../../src/v1/internal/connection-providers'; -import {READ} from '../../src/v1/driver'; -import FakeConnection from './fake-connection'; -import StreamObserver from '../../src/v1/internal/stream-observer'; +import ConnectionHolder, { + EMPTY_CONNECTION_HOLDER +} from '../../src/v1/internal/connection-holder' +import { SingleConnectionProvider } from '../../src/v1/internal/connection-providers' +import { READ } from '../../src/v1/driver' +import FakeConnection from './fake-connection' +import StreamObserver from '../../src/v1/internal/stream-observer' describe('EmptyConnectionHolder', () => { - it('should return rejected promise instead of connection', done => { EMPTY_CONNECTION_HOLDER.getConnection(new StreamObserver()).catch(() => { - done(); - }); - }); + done() + }) + }) it('should return resolved promise on release', done => { EMPTY_CONNECTION_HOLDER.releaseConnection().then(() => { - done(); - }); - }); + done() + }) + }) it('should return resolved promise on close', done => { EMPTY_CONNECTION_HOLDER.close().then(() => { - done(); - }); - }); - -}); + done() + }) + }) +}) describe('ConnectionHolder', () => { - it('should acquire new connection during initialization', () => { - const connectionProvider = new RecordingConnectionProvider([new FakeConnection()]); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connectionProvider = new RecordingConnectionProvider([ + new FakeConnection() + ]) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() - expect(connectionProvider.acquireConnectionInvoked).toBe(1); - }); + expect(connectionProvider.acquireConnectionInvoked).toBe(1) + }) it('should return acquired during initialization connection', done => { - const connection = new FakeConnection(); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection = new FakeConnection() + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.getConnection(new StreamObserver()).then(conn => { - expect(conn).toBe(connection); - done(); - }); - }); + expect(conn).toBe(connection) + done() + }) + }) it('should make stream observer aware about connection when initialization successful', done => { - const connection = new FakeConnection().withServerVersion('Neo4j/9.9.9'); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); - const streamObserver = new StreamObserver(); + const connection = new FakeConnection().withServerVersion('Neo4j/9.9.9') + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) + const streamObserver = new StreamObserver() - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.getConnection(streamObserver).then(conn => { - verifyConnection(streamObserver, 'Neo4j/9.9.9'); - done(); - }); - }); + verifyConnection(streamObserver, 'Neo4j/9.9.9') + done() + }) + }) it('should propagate connection acquisition failure', done => { - const errorMessage = 'Failed to acquire or initialize the connection'; - const connectionPromise = Promise.reject(new Error(errorMessage)); - const connectionProvider = newSingleConnectionProvider(connectionPromise); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); - const streamObserver = new StreamObserver(); + const errorMessage = 'Failed to acquire or initialize the connection' + const connectionPromise = Promise.reject(new Error(errorMessage)) + const connectionProvider = newSingleConnectionProvider(connectionPromise) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) + const streamObserver = new StreamObserver() - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.getConnection(streamObserver).catch(error => { - expect(error.message).toEqual(errorMessage); - done(); - }); - }); + expect(error.message).toEqual(errorMessage) + done() + }) + }) it('should release connection with single user', done => { - const connection = new FakeConnection(); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection = new FakeConnection() + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.releaseConnection().then(() => { - expect(connection.isReleasedOnce()).toBeTruthy(); - done(); - }); - }); + expect(connection.isReleasedOnce()).toBeTruthy() + done() + }) + }) it('should not release connection with multiple users', done => { - const connection = new FakeConnection(); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection = new FakeConnection() + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); - connectionHolder.initializeConnection(); - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() + connectionHolder.initializeConnection() + connectionHolder.initializeConnection() connectionHolder.releaseConnection().then(() => { - expect(connection.isNeverReleased()).toBeTruthy(); - done(); - }); - }); + expect(connection.isNeverReleased()).toBeTruthy() + done() + }) + }) it('should release connection with multiple users when all users release', done => { - const connection = new FakeConnection(); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection = new FakeConnection() + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); - connectionHolder.initializeConnection(); - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() + connectionHolder.initializeConnection() + connectionHolder.initializeConnection() connectionHolder.releaseConnection().then(() => { connectionHolder.releaseConnection().then(() => { connectionHolder.releaseConnection().then(() => { - expect(connection.isReleasedOnce()).toBeTruthy(); - done(); - }); - }); - }); - }); + expect(connection.isReleasedOnce()).toBeTruthy() + done() + }) + }) + }) + }) it('should do nothing when closed and not initialized', done => { - const connection = new FakeConnection(); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection = new FakeConnection() + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) connectionHolder.close().then(() => { - expect(connection.isNeverReleased()).toBeTruthy(); - done(); - }); - }); + expect(connection.isNeverReleased()).toBeTruthy() + done() + }) + }) it('should close even when users exist', done => { - const connection = new FakeConnection(); - const connectionProvider = newSingleConnectionProvider(connection); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection = new FakeConnection() + const connectionProvider = newSingleConnectionProvider(connection) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() + connectionHolder.initializeConnection() connectionHolder.close().then(() => { - expect(connection.isReleasedOnce()).toBeTruthy(); - done(); - }); - }); + expect(connection.isReleasedOnce()).toBeTruthy() + done() + }) + }) it('should initialize new connection after releasing current one', done => { - const connection1 = new FakeConnection(); - const connection2 = new FakeConnection(); - const connectionProvider = new RecordingConnectionProvider([connection1, connection2]); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection1 = new FakeConnection() + const connection2 = new FakeConnection() + const connectionProvider = new RecordingConnectionProvider([ + connection1, + connection2 + ]) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.releaseConnection().then(() => { - expect(connection1.isReleasedOnce()).toBeTruthy(); + expect(connection1.isReleasedOnce()).toBeTruthy() - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.releaseConnection().then(() => { - expect(connection2.isReleasedOnce()).toBeTruthy(); - done(); - }); - }); - }); + expect(connection2.isReleasedOnce()).toBeTruthy() + done() + }) + }) + }) it('should initialize new connection after being closed', done => { - const connection1 = new FakeConnection(); - const connection2 = new FakeConnection(); - const connectionProvider = new RecordingConnectionProvider([connection1, connection2]); - const connectionHolder = new ConnectionHolder(READ, connectionProvider); + const connection1 = new FakeConnection() + const connection2 = new FakeConnection() + const connectionProvider = new RecordingConnectionProvider([ + connection1, + connection2 + ]) + const connectionHolder = new ConnectionHolder(READ, connectionProvider) - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.close().then(() => { - expect(connection1.isReleasedOnce()).toBeTruthy(); + expect(connection1.isReleasedOnce()).toBeTruthy() - connectionHolder.initializeConnection(); + connectionHolder.initializeConnection() connectionHolder.close().then(() => { - expect(connection2.isReleasedOnce()).toBeTruthy(); - done(); - }); - }); - }); -}); + expect(connection2.isReleasedOnce()).toBeTruthy() + done() + }) + }) + }) +}) class RecordingConnectionProvider extends SingleConnectionProvider { - - constructor(connections) { - super(Promise.resolve()); - this.connectionPromises = connections.map(conn => Promise.resolve(conn)); - this.acquireConnectionInvoked = 0; + constructor (connections) { + super(Promise.resolve()) + this.connectionPromises = connections.map(conn => Promise.resolve(conn)) + this.acquireConnectionInvoked = 0 } - acquireConnection(mode) { - return this.connectionPromises[this.acquireConnectionInvoked++]; + acquireConnection (mode) { + return this.connectionPromises[this.acquireConnectionInvoked++] } } -function newSingleConnectionProvider(connection) { - return new SingleConnectionProvider(Promise.resolve(connection)); +function newSingleConnectionProvider (connection) { + return new SingleConnectionProvider(Promise.resolve(connection)) } -function verifyConnection(streamObserver, expectedServerVersion) { - expect(streamObserver._conn).toBeDefined(); - expect(streamObserver._conn).not.toBeNull(); +function verifyConnection (streamObserver, expectedServerVersion) { + expect(streamObserver._conn).toBeDefined() + expect(streamObserver._conn).not.toBeNull() // server version is taken from connection, verify it as well - const metadata = streamObserver.serverMetadata(); - expect(metadata.server.version).toEqual(expectedServerVersion); + const metadata = streamObserver.serverMetadata() + expect(metadata.server.version).toEqual(expectedServerVersion) } diff --git a/test/internal/connection-providers.test.js b/test/internal/connection-providers.test.js index 4c2c0a6df..aff407aa0 100644 --- a/test/internal/connection-providers.test.js +++ b/test/internal/connection-providers.test.js @@ -17,233 +17,237 @@ * limitations under the License. */ -import {READ, WRITE} from '../../src/v1/driver'; -import Integer, {int} from '../../src/v1/integer'; -import {SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../../src/v1/error'; -import RoutingTable from '../../src/v1/internal/routing-table'; -import {DirectConnectionProvider, LoadBalancer} from '../../src/v1/internal/connection-providers'; -import Pool from '../../src/v1/internal/pool'; -import LeastConnectedLoadBalancingStrategy from '../../src/v1/internal/least-connected-load-balancing-strategy'; -import Logger from '../../src/v1/internal/logger'; -import SimpleHostNameResolver from '../../src/v1/internal/browser/browser-host-name-resolver'; -import ServerAddress from '../../src/v1/internal/server-address'; - -const NO_OP_DRIVER_CALLBACK = () => { -}; +import { READ, WRITE } from '../../src/v1/driver' +import Integer, { int } from '../../src/v1/integer' +import { SERVICE_UNAVAILABLE, SESSION_EXPIRED } from '../../src/v1/error' +import RoutingTable from '../../src/v1/internal/routing-table' +import { + DirectConnectionProvider, + LoadBalancer +} from '../../src/v1/internal/connection-providers' +import Pool from '../../src/v1/internal/pool' +import LeastConnectedLoadBalancingStrategy from '../../src/v1/internal/least-connected-load-balancing-strategy' +import Logger from '../../src/v1/internal/logger' +import SimpleHostNameResolver from '../../src/v1/internal/browser/browser-host-name-resolver' +import ServerAddress from '../../src/v1/internal/server-address' + +const NO_OP_DRIVER_CALLBACK = () => {} describe('DirectConnectionProvider', () => { - it('acquires connection from the pool', done => { - const address = ServerAddress.fromUrl('localhost:123'); - const pool = newPool(); - const connectionProvider = newDirectConnectionProvider(address, pool); + const address = ServerAddress.fromUrl('localhost:123') + const pool = newPool() + const connectionProvider = newDirectConnectionProvider(address, pool) connectionProvider.acquireConnection(READ).then(connection => { - expect(connection).toBeDefined(); - expect(connection.address).toEqual(address); - expect(connection.release).toBeDefined(); - expect(pool.has(address)).toBeTruthy(); - - done(); - }); - }); + expect(connection).toBeDefined() + expect(connection.address).toEqual(address) + expect(connection.release).toBeDefined() + expect(pool.has(address)).toBeTruthy() -}); + done() + }) + }) +}) describe('LoadBalancer', () => { - const server0 = ServerAddress.fromUrl('server0'); - const server1 = ServerAddress.fromUrl('server1'); - const server2 = ServerAddress.fromUrl('server2'); - const server3 = ServerAddress.fromUrl('server3'); - const server4 = ServerAddress.fromUrl('server4'); - const server5 = ServerAddress.fromUrl('server5'); - const server6 = ServerAddress.fromUrl('server6'); - const server7 = ServerAddress.fromUrl('server7'); - const server42 = ServerAddress.fromUrl('server42'); - - const server01 = ServerAddress.fromUrl('server01'); - const server02 = ServerAddress.fromUrl('server02'); - const server03 = ServerAddress.fromUrl('server03'); - - const serverA = ServerAddress.fromUrl('serverA'); - const serverB = ServerAddress.fromUrl('serverB'); - const serverC = ServerAddress.fromUrl('serverC'); - const serverD = ServerAddress.fromUrl('serverD'); - const serverE = ServerAddress.fromUrl('serverE'); - const serverF = ServerAddress.fromUrl('serverF'); - const serverG = ServerAddress.fromUrl('serverG'); - - const serverAA = ServerAddress.fromUrl('serverAA'); - const serverBB = ServerAddress.fromUrl('serverBB'); - const serverCC = ServerAddress.fromUrl('serverCC'); - const serverDD = ServerAddress.fromUrl('serverDD'); - const serverEE = ServerAddress.fromUrl('serverEE'); - - const serverABC = ServerAddress.fromUrl('serverABC'); + const server0 = ServerAddress.fromUrl('server0') + const server1 = ServerAddress.fromUrl('server1') + const server2 = ServerAddress.fromUrl('server2') + const server3 = ServerAddress.fromUrl('server3') + const server4 = ServerAddress.fromUrl('server4') + const server5 = ServerAddress.fromUrl('server5') + const server6 = ServerAddress.fromUrl('server6') + const server7 = ServerAddress.fromUrl('server7') + const server42 = ServerAddress.fromUrl('server42') + + const server01 = ServerAddress.fromUrl('server01') + const server02 = ServerAddress.fromUrl('server02') + const server03 = ServerAddress.fromUrl('server03') + + const serverA = ServerAddress.fromUrl('serverA') + const serverB = ServerAddress.fromUrl('serverB') + const serverC = ServerAddress.fromUrl('serverC') + const serverD = ServerAddress.fromUrl('serverD') + const serverE = ServerAddress.fromUrl('serverE') + const serverF = ServerAddress.fromUrl('serverF') + const serverG = ServerAddress.fromUrl('serverG') + + const serverAA = ServerAddress.fromUrl('serverAA') + const serverBB = ServerAddress.fromUrl('serverBB') + const serverCC = ServerAddress.fromUrl('serverCC') + const serverDD = ServerAddress.fromUrl('serverDD') + const serverEE = ServerAddress.fromUrl('serverEE') + + const serverABC = ServerAddress.fromUrl('serverABC') it('can forget address', () => { const loadBalancer = newLoadBalancer( [server1, server2], [server3, server2], [server2, server4] - ); + ) - loadBalancer.forget(server2); + loadBalancer.forget(server2) - expectRoutingTable(loadBalancer, - [server1, server2], - [server3], - [server4] - ); - }); + expectRoutingTable(loadBalancer, [server1, server2], [server3], [server4]) + }) it('can not forget unknown address', () => { const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], [server5, server6] - ); + ) - loadBalancer.forget(server42); + loadBalancer.forget(server42) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [server1, server2], [server3, server4], [server5, server6] - ); - }); + ) + }) it('purges connections when address is forgotten', () => { - const pool = newPool(); + const pool = newPool() - pool.acquire(server1); - pool.acquire(server3); - pool.acquire(server5); - expectPoolToContain(pool, [server1, server3, server5]); + pool.acquire(server1) + pool.acquire(server3) + pool.acquire(server5) + expectPoolToContain(pool, [server1, server3, server5]) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server2], [server2, server4], pool - ); + ) - loadBalancer.forget(server1); - loadBalancer.forget(server5); + loadBalancer.forget(server1) + loadBalancer.forget(server5) - expectPoolToContain(pool, [server3]); - expectPoolToNotContain(pool, [server1, server5]); - }); + expectPoolToContain(pool, [server3]) + expectPoolToNotContain(pool, [server1, server5]) + }) it('can forget writer address', () => { const loadBalancer = newLoadBalancer( [server1, server2], [server3, server2], [server2, server4] - ); + ) - loadBalancer.forgetWriter(server2); + loadBalancer.forgetWriter(server2) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [server1, server2], [server3, server2], [server4] - ); - }); + ) + }) it('can not forget unknown writer address', () => { const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], [server5, server6] - ); + ) - loadBalancer.forgetWriter(server42); + loadBalancer.forgetWriter(server42) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [server1, server2], [server3, server4], [server5, server6] - ); - }); + ) + }) it('initializes routing table with the given router', () => { - const connectionPool = newPool(); - const loadBalancingStrategy = new LeastConnectedLoadBalancingStrategy(connectionPool); - const loadBalancer = new LoadBalancer(serverABC, {}, connectionPool, loadBalancingStrategy, new SimpleHostNameResolver(), - NO_OP_DRIVER_CALLBACK, Logger.noOp()); - - expectRoutingTable(loadBalancer, - [], - [], - [] - ); - }); + const connectionPool = newPool() + const loadBalancingStrategy = new LeastConnectedLoadBalancingStrategy( + connectionPool + ) + const loadBalancer = new LoadBalancer( + serverABC, + {}, + connectionPool, + loadBalancingStrategy, + new SimpleHostNameResolver(), + NO_OP_DRIVER_CALLBACK, + Logger.noOp() + ) + + expectRoutingTable(loadBalancer, [], [], []) + }) it('acquires read connection with up-to-date routing table', done => { - const pool = newPool(); + const pool = newPool() const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], [server5, server6], pool - ); + ) loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(server3); - expect(pool.has(server3)).toBeTruthy(); + expect(connection.address).toEqual(server3) + expect(pool.has(server3)).toBeTruthy() loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(server4); - expect(pool.has(server4)).toBeTruthy(); + expect(connection.address).toEqual(server4) + expect(pool.has(server4)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('acquires write connection with up-to-date routing table', done => { - const pool = newPool(); + const pool = newPool() const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], [server5, server6], pool - ); + ) loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(server5); - expect(pool.has(server5)).toBeTruthy(); + expect(connection.address).toEqual(server5) + expect(pool.has(server5)).toBeTruthy() loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(server6); - expect(pool.has(server6)).toBeTruthy(); + expect(connection.address).toEqual(server6) + expect(pool.has(server6)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('throws for illegal access mode', done => { const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], [server5, server6] - ); + ) loadBalancer.acquireConnection('WRONG').catch(error => { - expect(error.message).toEqual('Illegal mode WRONG'); - done(); - }); - }); + expect(error.message).toEqual('Illegal mode WRONG') + done() + }) + }) it('refreshes stale routing table to get read connection', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -251,28 +255,28 @@ describe('LoadBalancer', () => { pool, int(0), // expired routing table { 'server1:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(serverC); - expect(pool.has(serverC)).toBeTruthy(); + expect(connection.address).toEqual(serverC) + expect(pool.has(serverC)).toBeTruthy() loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(serverD); - expect(pool.has(serverD)).toBeTruthy(); + expect(connection.address).toEqual(serverD) + expect(pool.has(serverD)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('refreshes stale routing table to get write connection', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -280,28 +284,28 @@ describe('LoadBalancer', () => { pool, int(0), // expired routing table { 'server1:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(serverE); - expect(pool.has(serverE)).toBeTruthy(); + expect(connection.address).toEqual(serverE) + expect(pool.has(serverE)).toBeTruthy() loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(serverF); - expect(pool.has(serverF)).toBeTruthy(); + expect(connection.address).toEqual(serverF) + expect(pool.has(serverF)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('refreshes stale routing table to get read connection when one router fails', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -310,30 +314,30 @@ describe('LoadBalancer', () => { int(0), // expired routing table { 'server1:7687': null, // returns no routing table - 'server2:7687': updatedRoutingTable, + 'server2:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(serverC); - expect(pool.has(serverC)).toBeTruthy(); + expect(connection.address).toEqual(serverC) + expect(pool.has(serverC)).toBeTruthy() loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(serverD); - expect(pool.has(serverD)).toBeTruthy(); + expect(connection.address).toEqual(serverD) + expect(pool.has(serverD)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('refreshes stale routing table to get write connection when one router fails', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -342,30 +346,30 @@ describe('LoadBalancer', () => { int(0), // expired routing table { 'server1:7687': null, // returns no routing table - 'server2:7687': updatedRoutingTable, + 'server2:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(serverE); - expect(pool.has(serverE)).toBeTruthy(); + expect(connection.address).toEqual(serverE) + expect(pool.has(serverE)).toBeTruthy() loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(serverF); - expect(pool.has(serverF)).toBeTruthy(); + expect(connection.address).toEqual(serverF) + expect(pool.has(serverF)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('refreshes routing table without readers to get read connection', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [], // no readers @@ -374,30 +378,30 @@ describe('LoadBalancer', () => { Integer.MAX_VALUE, { 'server1:7687': null, // returns no routing table - 'server2:7687': updatedRoutingTable, + 'server2:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(serverC); - expect(pool.has(serverC)).toBeTruthy(); + expect(connection.address).toEqual(serverC) + expect(pool.has(serverC)).toBeTruthy() loadBalancer.acquireConnection(READ).then(connection => { - expect(connection.address).toEqual(serverD); - expect(pool.has(serverD)).toBeTruthy(); + expect(connection.address).toEqual(serverD) + expect(pool.has(serverD)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('refreshes routing table without writers to get write connection', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -406,22 +410,22 @@ describe('LoadBalancer', () => { int(0), // expired routing table { 'server1:7687': null, // returns no routing table - 'server2:7687': updatedRoutingTable, + 'server2:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(serverE); - expect(pool.has(serverE)).toBeTruthy(); + expect(connection.address).toEqual(serverE) + expect(pool.has(serverE)).toBeTruthy() loadBalancer.acquireConnection(WRITE).then(connection => { - expect(connection.address).toEqual(serverF); - expect(pool.has(serverF)).toBeTruthy(); + expect(connection.address).toEqual(serverF) + expect(pool.has(serverF)).toBeTruthy() - done(); - }); - }); - }); + done() + }) + }) + }) it('throws when all routers return nothing while getting read connection', done => { const loadBalancer = newLoadBalancer( @@ -432,15 +436,15 @@ describe('LoadBalancer', () => { int(0), // expired routing table { 'server1:7687': null, // returns no routing table - 'server2:7687': null // returns no routing table + 'server2:7687': null // returns no routing table } - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); - done(); - }); - }); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) + done() + }) + }) it('throws when all routers return nothing while getting write connection', done => { const loadBalancer = newLoadBalancer( @@ -451,22 +455,22 @@ describe('LoadBalancer', () => { int(0), // expired routing table { 'server1:7687': null, // returns no routing table - 'server2:7687': null // returns no routing table + 'server2:7687': null // returns no routing table } - ); + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); - done(); - }); - }); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) + done() + }) + }) it('throws when all routers return routing tables without readers while getting read connection', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [], // no readers - table can't satisfy connection requirement [serverC, serverD] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -477,20 +481,20 @@ describe('LoadBalancer', () => { 'server1:7687': updatedRoutingTable, 'server2:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SESSION_EXPIRED); - done(); - }); - }); + expect(error.code).toEqual(SESSION_EXPIRED) + done() + }) + }) it('throws when all routers return routing tables without writers while getting write connection', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [] // no writers - table can't satisfy connection requirement - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -501,13 +505,13 @@ describe('LoadBalancer', () => { 'server1:7687': updatedRoutingTable, 'server2:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SESSION_EXPIRED); - done(); - }); - }); + expect(error.code).toEqual(SESSION_EXPIRED) + done() + }) + }) it('throws when stale routing table without routers while getting read connection', done => { const loadBalancer = newLoadBalancer( @@ -516,13 +520,13 @@ describe('LoadBalancer', () => { [server5, server6], newPool(), int(0) // expired routing table - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); - done(); - }); - }); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) + done() + }) + }) it('throws when stale routing table without routers while getting write connection', done => { const loadBalancer = newLoadBalancer( @@ -531,21 +535,21 @@ describe('LoadBalancer', () => { [server5, server6], newPool(), int(0) // expired routing table - ); + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); - done(); - }); - }); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) + done() + }) + }) it('updates routing table after refresh', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -555,18 +559,26 @@ describe('LoadBalancer', () => { { 'server1:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).then(() => { - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); - expectPoolToNotContain(pool, [server1, server2, server3, server4, server5, server6]); - done(); - }); - }); + ) + expectPoolToNotContain(pool, [ + server1, + server2, + server3, + server4, + server5, + server6 + ]) + done() + }) + }) it('forgets all routers when they fail while acquiring read connection', done => { const loadBalancer = newLoadBalancer( @@ -575,18 +587,19 @@ describe('LoadBalancer', () => { [server6, server7], newPool(), int(0) // expired routing table - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); - expectRoutingTable(loadBalancer, + expect(error.code).toEqual(SERVICE_UNAVAILABLE) + expectRoutingTable( + loadBalancer, [], [server4, server5], [server6, server7] - ); - done(); - }); - }); + ) + done() + }) + }) it('forgets all routers when they fail while acquiring write connection', done => { const loadBalancer = newLoadBalancer( @@ -595,28 +608,30 @@ describe('LoadBalancer', () => { [server6, server7], newPool(), int(0) // expired routing table - ); + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); - expectRoutingTable(loadBalancer, + expect(error.code).toEqual(SERVICE_UNAVAILABLE) + expectRoutingTable( + loadBalancer, [], [server4, server5], [server6, server7] - ); - done(); - }); - }); + ) + done() + }) + }) it('uses seed router address when all existing routers fail', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB, serverC], [serverD, serverE], [serverF, serverG] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server0], // seed router address resolves just to itself + server0, + [server0], // seed router address resolves just to itself [server1, server2, server3], [server4, server5], [server6, server7], @@ -627,33 +642,35 @@ describe('LoadBalancer', () => { 'server3:7687': null, // returns no routing table 'server0:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).then(connection1 => { - expect(connection1.address).toEqual(serverD); + expect(connection1.address).toEqual(serverD) loadBalancer.acquireConnection(WRITE).then(connection2 => { - expect(connection2.address).toEqual(serverF); + expect(connection2.address).toEqual(serverF) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB, serverC], [serverD, serverE], [serverF, serverG] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('uses resolved seed router address when all existing routers fail', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server01], // seed router address resolves to a different one + server0, + [server01], // seed router address resolves to a different one [server1, server2, server3], [server4, server5], [server6, server7], @@ -664,33 +681,35 @@ describe('LoadBalancer', () => { 'server3:7687': null, // returns no routing table 'server01:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection1 => { - expect(connection1.address).toEqual(serverE); + expect(connection1.address).toEqual(serverE) loadBalancer.acquireConnection(READ).then(connection2 => { - expect(connection2.address).toEqual(serverC); + expect(connection2.address).toEqual(serverC) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('uses resolved seed router address that returns correct routing table when all existing routers fail', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC], [serverD, serverE] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server01, server02, server03], // seed router address resolves to 3 different addresses + server0, + [server01, server02, server03], // seed router address resolves to 3 different addresses [server1], [server2], [server3], @@ -701,27 +720,29 @@ describe('LoadBalancer', () => { 'server02:7687': null, // returns no routing table 'server03:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection1 => { - expect(connection1.address).toEqual(serverD); + expect(connection1.address).toEqual(serverD) loadBalancer.acquireConnection(WRITE).then(connection2 => { - expect(connection2.address).toEqual(serverE); + expect(connection2.address).toEqual(serverE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC], [serverD, serverE] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('fails when both existing routers and seed router fail to return a routing table', done => { const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server0], // seed router address resolves just to itself + server0, + [server0], // seed router address resolves just to itself [server1, server2, server3], [server4, server5], [server6], @@ -732,34 +753,37 @@ describe('LoadBalancer', () => { 'server3:7687': null, // returns no routing table 'server0:7687': null // returns no routing table } - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [], // all routers were forgotten because they failed [server4, server5], - [server6], - ); + [server6] + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [], // all routers were forgotten because they failed [server4, server5], - [server6], - ); + [server6] + ) - done(); - }); - }); - }); + done() + }) + }) + }) it('fails when both existing routers and resolved seed router fail to return a routing table', done => { const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server01], // seed router address resolves to a different one + server0, + [server01], // seed router address resolves to a different one [server1, server2], [server3], [server4], @@ -769,34 +793,37 @@ describe('LoadBalancer', () => { 'server2:7687': null, // returns no routing table 'server01:7687': null // returns no routing table } - ); + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [], // all routers were forgotten because they failed [server3], - [server4], - ); + [server4] + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [], // all routers were forgotten because they failed [server3], - [server4], - ); + [server4] + ) - done(); - }); - }); - }); + done() + }) + }) + }) it('fails when both existing routers and all resolved seed routers fail to return a routing table', done => { const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server02, server01], // seed router address resolves to 2 different addresses + server0, + [server02, server01], // seed router address resolves to 2 different addresses [server1, server2, server3], [server4], [server5], @@ -808,40 +835,43 @@ describe('LoadBalancer', () => { 'server01:7687': null, // returns no routing table 'server02:7687': null // returns no routing table } - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [], // all known seed servers failed to return routing tables and were forgotten [server4], - [server5], - ); + [server5] + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SERVICE_UNAVAILABLE); + expect(error.code).toEqual(SERVICE_UNAVAILABLE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [], // all known seed servers failed to return routing tables and were forgotten [server4], - [server5], - ); + [server5] + ) - done(); - }); - }); - }); + done() + }) + }) + }) it('uses seed router when no existing routers', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC], [serverD] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server0], // seed router address resolves just to itself + server0, + [server0], // seed router address resolves just to itself [], // no routers in the known routing table [server1, server2], [server3], @@ -849,33 +879,35 @@ describe('LoadBalancer', () => { { 'server0:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection1 => { - expect(connection1.address).toEqual(serverD); + expect(connection1.address).toEqual(serverD) loadBalancer.acquireConnection(READ).then(connection2 => { - expect(connection2.address).toEqual(serverC); + expect(connection2.address).toEqual(serverC) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC], [serverD] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('uses resolved seed router when no existing routers', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverF, serverE] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server01], // seed router address resolves to a different one + server0, + [server01], // seed router address resolves to a different one [], // no routers in the known routing table [server1, server2], [server3, server4], @@ -883,33 +915,35 @@ describe('LoadBalancer', () => { { 'server01:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).then(connection1 => { - expect(connection1.address).toEqual(serverC); + expect(connection1.address).toEqual(serverC) loadBalancer.acquireConnection(WRITE).then(connection2 => { - expect(connection2.address).toEqual(serverF); + expect(connection2.address).toEqual(serverF) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC, serverD], [serverF, serverE] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('uses resolved seed router that returns routing table when no existing routers exist', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB, serverC], [serverD, serverE], [serverF] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server02, server01, server03], // seed router address resolves to 3 different addresses + server0, + [server02, server01, server03], // seed router address resolves to 3 different addresses [], // no routers in the known routing table [server1], [server2, server3], @@ -919,33 +953,35 @@ describe('LoadBalancer', () => { 'server02:7687': null, // returns no routing table 'server03:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).then(connection1 => { - expect(connection1.address).toEqual(serverF); + expect(connection1.address).toEqual(serverF) loadBalancer.acquireConnection(READ).then(connection2 => { - expect(connection2.address).toEqual(serverD); + expect(connection2.address).toEqual(serverD) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB, serverC], [serverD, serverE], [serverF] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('ignores already probed routers after seed router resolution', done => { const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server1, server01, server2, server02], // seed router address resolves to 4 different addresses + server0, + [server1, server01, server2, server02], // seed router address resolves to 4 different addresses [server1, server2], [server3, server4], [server5, server6], @@ -956,43 +992,44 @@ describe('LoadBalancer', () => { 'server2:7687': null, // returns no routing table 'server02:7687': updatedRoutingTable } - ); + ) // override default use of seed router - loadBalancer._useSeedRouter = false; + loadBalancer._useSeedRouter = false - const usedRouterArrays = []; - setupLoadBalancerToRememberRouters(loadBalancer, usedRouterArrays); + const usedRouterArrays = [] + setupLoadBalancerToRememberRouters(loadBalancer, usedRouterArrays) loadBalancer.acquireConnection(READ).then(connection1 => { - expect(connection1.address).toEqual(serverC); + expect(connection1.address).toEqual(serverC) loadBalancer.acquireConnection(WRITE).then(connection2 => { - expect(connection2.address).toEqual(serverE); + expect(connection2.address).toEqual(serverE) // two sets of routers probed: // 1) existing routers server1 & server2 // 2) resolved routers server01 & server02 - expect(usedRouterArrays.length).toEqual(2); - expect(usedRouterArrays[0]).toEqual([server1, server2]); - expect(usedRouterArrays[1]).toEqual([server01, server02]); + expect(usedRouterArrays.length).toEqual(2) + expect(usedRouterArrays[0]).toEqual([server1, server2]) + expect(usedRouterArrays[1]).toEqual([server01, server02]) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC, serverD], [serverE, serverF] - ); - done(); - }); - }); - }); + ) + done() + }) + }) + }) it('throws session expired when refreshed routing table has no readers', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [], // no readers [serverC, serverD] - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -1000,23 +1037,23 @@ describe('LoadBalancer', () => { pool, int(0), // expired routing table { - 'server1:7687': updatedRoutingTable, + 'server1:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(READ).catch(error => { - expect(error.code).toEqual(SESSION_EXPIRED); - done(); - }); - }); + expect(error.code).toEqual(SESSION_EXPIRED) + done() + }) + }) it('throws session expired when refreshed routing table has no writers', done => { - const pool = newPool(); + const pool = newPool() const updatedRoutingTable = newRoutingTable( [serverA, serverB], [serverC, serverD], [] // no writers - ); + ) const loadBalancer = newLoadBalancer( [server1, server2], [server3, server4], @@ -1024,30 +1061,31 @@ describe('LoadBalancer', () => { pool, int(0), // expired routing table { - 'server1:7687': updatedRoutingTable, + 'server1:7687': updatedRoutingTable } - ); + ) loadBalancer.acquireConnection(WRITE).catch(error => { - expect(error.code).toEqual(SESSION_EXPIRED); - done(); - }); - }); + expect(error.code).toEqual(SESSION_EXPIRED) + done() + }) + }) it('should use resolved seed router after accepting table with no writers', done => { const routingTable1 = newRoutingTable( [serverA, serverB], [serverC, serverD], [] // no writers - ); + ) const routingTable2 = newRoutingTable( [serverAA, serverBB], [serverCC, serverDD], [serverEE] - ); + ) const loadBalancer = newLoadBalancerWithSeedRouter( - server0, [server02, server01], // seed router address resolves to 2 different addresses + server0, + [server02, server01], // seed router address resolves to 2 different addresses [server1], [server2, server3], [server4, server5], @@ -1059,131 +1097,165 @@ describe('LoadBalancer', () => { 'server01:7687': null, // returns no routing table 'server02:7687': routingTable2 } - ); + ) // override default use of seed router - loadBalancer._useSeedRouter = false; + loadBalancer._useSeedRouter = false loadBalancer.acquireConnection(READ).then(connection1 => { - expect(connection1.address).toEqual(serverC); + expect(connection1.address).toEqual(serverC) loadBalancer.acquireConnection(READ).then(connection2 => { - expect(connection2.address).toEqual(serverD); + expect(connection2.address).toEqual(serverD) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverA, serverB], [serverC, serverD], [] - ); + ) loadBalancer.acquireConnection(WRITE).then(connection3 => { - expect(connection3.address).toEqual(serverEE); + expect(connection3.address).toEqual(serverEE) - expectRoutingTable(loadBalancer, + expectRoutingTable( + loadBalancer, [serverAA, serverBB], [serverCC, serverDD], [serverEE] - ); + ) - done(); - }); - }); - }); - }); + done() + }) + }) + }) + }) +}) -}); - -function newDirectConnectionProvider(address, pool) { - return new DirectConnectionProvider(address, pool, NO_OP_DRIVER_CALLBACK); +function newDirectConnectionProvider (address, pool) { + return new DirectConnectionProvider(address, pool, NO_OP_DRIVER_CALLBACK) } -function newLoadBalancer(routers, readers, writers, - pool = null, - expirationTime = Integer.MAX_VALUE, - routerToRoutingTable = {}) { - const seedRouter = ServerAddress.fromUrl('server-non-existing-seed-router'); - return newLoadBalancerWithSeedRouter(seedRouter, [seedRouter], routers, readers, writers, expirationTime, - routerToRoutingTable, pool); +function newLoadBalancer ( + routers, + readers, + writers, + pool = null, + expirationTime = Integer.MAX_VALUE, + routerToRoutingTable = {} +) { + const seedRouter = ServerAddress.fromUrl('server-non-existing-seed-router') + return newLoadBalancerWithSeedRouter( + seedRouter, + [seedRouter], + routers, + readers, + writers, + expirationTime, + routerToRoutingTable, + pool + ) } -function newLoadBalancerWithSeedRouter(seedRouter, seedRouterResolved, - routers, readers, writers, - expirationTime = Integer.MAX_VALUE, - routerToRoutingTable = {}, - connectionPool = null) { - const pool = connectionPool || newPool(); - const loadBalancingStrategy = new LeastConnectedLoadBalancingStrategy(pool); - const loadBalancer = new LoadBalancer(seedRouter, {}, pool, loadBalancingStrategy, new SimpleHostNameResolver(), - NO_OP_DRIVER_CALLBACK, Logger.noOp()); - loadBalancer._routingTable = new RoutingTable(routers, readers, writers, expirationTime); - loadBalancer._rediscovery = new FakeRediscovery(routerToRoutingTable); - loadBalancer._hostNameResolver = new FakeDnsResolver(seedRouterResolved); +function newLoadBalancerWithSeedRouter ( + seedRouter, + seedRouterResolved, + routers, + readers, + writers, + expirationTime = Integer.MAX_VALUE, + routerToRoutingTable = {}, + connectionPool = null +) { + const pool = connectionPool || newPool() + const loadBalancingStrategy = new LeastConnectedLoadBalancingStrategy(pool) + const loadBalancer = new LoadBalancer( + seedRouter, + {}, + pool, + loadBalancingStrategy, + new SimpleHostNameResolver(), + NO_OP_DRIVER_CALLBACK, + Logger.noOp() + ) + loadBalancer._routingTable = new RoutingTable( + routers, + readers, + writers, + expirationTime + ) + loadBalancer._rediscovery = new FakeRediscovery(routerToRoutingTable) + loadBalancer._hostNameResolver = new FakeDnsResolver(seedRouterResolved) if (expirationTime === Integer.ZERO) { - loadBalancer._useSeedRouter = false; + loadBalancer._useSeedRouter = false } - return loadBalancer; + return loadBalancer } -function newRoutingTable(routers, readers, writers, expirationTime = Integer.MAX_VALUE) { - return new RoutingTable(routers, readers, writers, expirationTime); +function newRoutingTable ( + routers, + readers, + writers, + expirationTime = Integer.MAX_VALUE +) { + return new RoutingTable(routers, readers, writers, expirationTime) } -function setupLoadBalancerToRememberRouters(loadBalancer, routersArray) { - const originalFetch = loadBalancer._fetchRoutingTable.bind(loadBalancer); +function setupLoadBalancerToRememberRouters (loadBalancer, routersArray) { + const originalFetch = loadBalancer._fetchRoutingTable.bind(loadBalancer) const rememberingFetch = (routerAddresses, routingTable) => { - routersArray.push(routerAddresses); - return originalFetch(routerAddresses, routingTable); - }; - loadBalancer._fetchRoutingTable = rememberingFetch; + routersArray.push(routerAddresses) + return originalFetch(routerAddresses, routingTable) + } + loadBalancer._fetchRoutingTable = rememberingFetch } -function newPool() { - return new Pool((address, release) => Promise.resolve(new FakeConnection(address, release))); +function newPool () { + return new Pool((address, release) => + Promise.resolve(new FakeConnection(address, release)) + ) } -function expectRoutingTable(loadBalancer, routers, readers, writers) { - expect(loadBalancer._routingTable.routers).toEqual(routers); - expect(loadBalancer._routingTable.readers).toEqual(readers); - expect(loadBalancer._routingTable.writers).toEqual(writers); +function expectRoutingTable (loadBalancer, routers, readers, writers) { + expect(loadBalancer._routingTable.routers).toEqual(routers) + expect(loadBalancer._routingTable.readers).toEqual(readers) + expect(loadBalancer._routingTable.writers).toEqual(writers) } -function expectPoolToContain(pool, addresses) { +function expectPoolToContain (pool, addresses) { addresses.forEach(address => { - expect(pool.has(address)).toBeTruthy(); - }); + expect(pool.has(address)).toBeTruthy() + }) } -function expectPoolToNotContain(pool, addresses) { +function expectPoolToNotContain (pool, addresses) { addresses.forEach(address => { - expect(pool.has(address)).toBeFalsy(); - }); + expect(pool.has(address)).toBeFalsy() + }) } class FakeConnection { - - constructor(address, release) { - this.address = address; - this.release = release; + constructor (address, release) { + this.address = address + this.release = release } } class FakeRediscovery { - - constructor(routerToRoutingTable) { - this._routerToRoutingTable = routerToRoutingTable; + constructor (routerToRoutingTable) { + this._routerToRoutingTable = routerToRoutingTable } - lookupRoutingTableOnRouter(ignored, router) { - return Promise.resolve(this._routerToRoutingTable[router.asKey()]); + lookupRoutingTableOnRouter (ignored, router) { + return Promise.resolve(this._routerToRoutingTable[router.asKey()]) } } class FakeDnsResolver { - - constructor(addresses) { - this._addresses = addresses; + constructor (addresses) { + this._addresses = addresses } - resolve(seedRouter) { - return Promise.resolve(this._addresses ? this._addresses : [seedRouter]); + resolve (seedRouter) { + return Promise.resolve(this._addresses ? this._addresses : [seedRouter]) } } diff --git a/test/internal/connection.test.js b/test/internal/connection.test.js index 1fbbce15d..ae3376d81 100644 --- a/test/internal/connection.test.js +++ b/test/internal/connection.test.js @@ -17,461 +17,525 @@ * limitations under the License. */ -import DummyChannel from './dummy-channel'; -import Connection from '../../src/v1/internal/connection'; -import {Packer} from '../../src/v1/internal/packstream-v1'; -import {Chunker} from '../../src/v1/internal/chunking'; -import {alloc} from '../../src/v1/internal/node'; -import {Neo4jError, newError, SERVICE_UNAVAILABLE} from '../../src/v1/error'; -import sharedNeo4j from '../internal/shared-neo4j'; -import {ServerVersion, VERSION_3_5_0} from '../../src/v1/internal/server-version'; -import lolex from 'lolex'; -import Logger from '../../src/v1/internal/logger'; -import StreamObserver from '../../src/v1/internal/stream-observer'; -import ConnectionErrorHandler from '../../src/v1/internal/connection-error-handler'; -import testUtils from '../internal/test-utils'; -import Bookmark from '../../src/v1/internal/bookmark'; -import TxConfig from '../../src/v1/internal/tx-config'; -import {WRITE} from "../../src/v1/driver"; -import ServerAddress from '../../src/v1/internal/server-address'; - -const ILLEGAL_MESSAGE = {signature: 42, fields: []}; -const SUCCESS_MESSAGE = {signature: 0x70, fields: [{}]}; -const FAILURE_MESSAGE = {signature: 0x7F, fields: [newError('Hello')]}; -const RECORD_MESSAGE = {signature: 0x71, fields: [{value: 'Hello'}]}; +import DummyChannel from './dummy-channel' +import Connection from '../../src/v1/internal/connection' +import { Packer } from '../../src/v1/internal/packstream-v1' +import { Chunker } from '../../src/v1/internal/chunking' +import { alloc } from '../../src/v1/internal/node' +import { Neo4jError, newError, SERVICE_UNAVAILABLE } from '../../src/v1/error' +import sharedNeo4j from '../internal/shared-neo4j' +import { + ServerVersion, + VERSION_3_5_0 +} from '../../src/v1/internal/server-version' +import lolex from 'lolex' +import Logger from '../../src/v1/internal/logger' +import StreamObserver from '../../src/v1/internal/stream-observer' +import ConnectionErrorHandler from '../../src/v1/internal/connection-error-handler' +import testUtils from '../internal/test-utils' +import Bookmark from '../../src/v1/internal/bookmark' +import TxConfig from '../../src/v1/internal/tx-config' +import { WRITE } from '../../src/v1/driver' +import ServerAddress from '../../src/v1/internal/server-address' + +const ILLEGAL_MESSAGE = { signature: 42, fields: [] } +const SUCCESS_MESSAGE = { signature: 0x70, fields: [{}] } +const FAILURE_MESSAGE = { signature: 0x7f, fields: [newError('Hello')] } +const RECORD_MESSAGE = { signature: 0x71, fields: [{ value: 'Hello' }] } describe('Connection', () => { - - let clock; - let connection; + let clock + let connection afterEach(done => { if (clock) { - clock.uninstall(); - clock = null; + clock.uninstall() + clock = null } - const usedConnection = connection; - connection = null; + const usedConnection = connection + connection = null if (usedConnection) { - usedConnection.close(); + usedConnection.close() } - done(); - }); + done() + }) it('should have correct creation timestamp', () => { - clock = lolex.install(); - clock.setSystemTime(424242); + clock = lolex.install() + clock.setSystemTime(424242) - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') - expect(connection.creationTimestamp).toEqual(424242); - }); + expect(connection.creationTimestamp).toEqual(424242) + }) it('should read/write basic messages', done => { - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') connection._negotiateProtocol().then(() => { connection.protocol().initialize('mydriver/0.0.0', basicAuthToken(), { onCompleted: msg => { - expect(msg).not.toBeNull(); - done(); + expect(msg).not.toBeNull() + done() }, onError: console.log - }); - }); - }); + }) + }) + }) it('should retrieve stream', done => { - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') - const records = []; + const records = [] const pullAllObserver = { onNext: record => { - records.push(record); + records.push(record) }, onCompleted: () => { - expect(records[0].get(0)).toBe(1); - done(); + expect(records[0].get(0)).toBe(1) + done() } - }; - const streamObserver = new StreamObserver(); - streamObserver.subscribe(pullAllObserver); - - connection.connect('mydriver/0.0.0', basicAuthToken()) - .then(() => { - connection.protocol().run('RETURN 1.0', {}, Bookmark.empty(), TxConfig.empty(), WRITE, streamObserver); - }); - }); + } + const streamObserver = new StreamObserver() + streamObserver.subscribe(pullAllObserver) + + connection.connect('mydriver/0.0.0', basicAuthToken()).then(() => { + connection + .protocol() + .run( + 'RETURN 1.0', + {}, + Bookmark.empty(), + TxConfig.empty(), + WRITE, + streamObserver + ) + }) + }) it('should write protocol handshake', () => { - const channel = new DummyChannel(); - connection = new Connection(channel, new ConnectionErrorHandler(SERVICE_UNAVAILABLE), ServerAddress.fromUrl('localhost:7687'), Logger.noOp()); - - connection._negotiateProtocol(); - - const boltMagicPreamble = '60 60 b0 17'; - const protocolVersion3 = '00 00 00 03'; - const protocolVersion2 = '00 00 00 02'; - const protocolVersion1 = '00 00 00 01'; - const noProtocolVersion = '00 00 00 00'; - expect(channel.toHex()).toBe(`${boltMagicPreamble} ${protocolVersion3} ${protocolVersion2} ${protocolVersion1} ${noProtocolVersion}`); - }); + const channel = new DummyChannel() + connection = new Connection( + channel, + new ConnectionErrorHandler(SERVICE_UNAVAILABLE), + ServerAddress.fromUrl('localhost:7687'), + Logger.noOp() + ) + + connection._negotiateProtocol() + + const boltMagicPreamble = '60 60 b0 17' + const protocolVersion3 = '00 00 00 03' + const protocolVersion2 = '00 00 00 02' + const protocolVersion1 = '00 00 00 01' + const noProtocolVersion = '00 00 00 00' + expect(channel.toHex()).toBe( + `${boltMagicPreamble} ${protocolVersion3} ${protocolVersion2} ${protocolVersion1} ${noProtocolVersion}` + ) + }) it('should provide error message when connecting to http-port', done => { - connection = createConnection('bolt://localhost:7474', {encrypted: false}); + connection = createConnection('bolt://localhost:7474', { encrypted: false }) connection.connect('mydriver/0.0.0', basicAuthToken()).catch(error => { - expect(error).toBeDefined(); - expect(error).not.toBeNull(); + expect(error).toBeDefined() + expect(error).not.toBeNull() if (testUtils.isServer()) { - //only node gets the pretty error message - expect(error.message).toBe('Server responded HTTP. Make sure you are not trying to connect to the http endpoint ' + - '(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)'); + // only node gets the pretty error message + expect(error.message).toBe( + 'Server responded HTTP. Make sure you are not trying to connect to the http endpoint ' + + '(HTTP defaults to port 7474 whereas BOLT defaults to port 7687)' + ) } - done(); - }); - }); + done() + }) + }) it('should convert failure messages to errors', done => { - const channel = new DummyChannel(); - connection = new Connection(channel, new ConnectionErrorHandler(SERVICE_UNAVAILABLE), ServerAddress.fromUrl('localhost:7687'), Logger.noOp()); + const channel = new DummyChannel() + connection = new Connection( + channel, + new ConnectionErrorHandler(SERVICE_UNAVAILABLE), + ServerAddress.fromUrl('localhost:7687'), + Logger.noOp() + ) - connection._negotiateProtocol(); + connection._negotiateProtocol() - const errorCode = 'Neo.ClientError.Schema.ConstraintValidationFailed'; - const errorMessage = 'Node 0 already exists with label User and property "email"=[john@doe.com]'; + const errorCode = 'Neo.ClientError.Schema.ConstraintValidationFailed' + const errorMessage = + 'Node 0 already exists with label User and property "email"=[john@doe.com]' connection._queueObserver({ onError: error => { - expectNeo4jError(error, errorCode, errorMessage); - done(); + expectNeo4jError(error, errorCode, errorMessage) + done() } - }); + }) - channel.onmessage(packedHandshakeMessage()); - channel.onmessage(packedFailureMessage(errorCode, errorMessage)); - }); + channel.onmessage(packedHandshakeMessage()) + channel.onmessage(packedFailureMessage(errorCode, errorMessage)) + }) it('should notify when connection initialization completes', done => { - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') - connection.connect('mydriver/0.0.0', basicAuthToken()) + connection + .connect('mydriver/0.0.0', basicAuthToken()) .then(initializedConnection => { - expect(initializedConnection).toBe(connection); - done(); - }); - }); + expect(initializedConnection).toBe(connection) + done() + }) + }) it('should notify when connection initialization fails', done => { - connection = createConnection('bolt://localhost:7474'); // wrong port + connection = createConnection('bolt://localhost:7474') // wrong port - connection.connect('mydriver/0.0.0', basicAuthToken()) + connection + .connect('mydriver/0.0.0', basicAuthToken()) .then(() => done.fail('Should not initialize')) .catch(error => { - expect(error).toBeDefined(); - done(); - }); - }); + expect(error).toBeDefined() + done() + }) + }) it('should have server version after connection initialization completed', done => { - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') - connection.connect('mydriver/0.0.0', basicAuthToken()) + connection + .connect('mydriver/0.0.0', basicAuthToken()) .then(initializedConnection => { - expect(initializedConnection).toBe(connection); - const serverVersion = ServerVersion.fromString(connection.server.version); - expect(serverVersion).toBeDefined(); - done(); - }); - }); + expect(initializedConnection).toBe(connection) + const serverVersion = ServerVersion.fromString( + connection.server.version + ) + expect(serverVersion).toBeDefined() + done() + }) + }) it('should fail all new observers after failure to connect', done => { - connection = createConnection('bolt://localhost:7474'); // wrong port + connection = createConnection('bolt://localhost:7474') // wrong port - connection.connect('mydriver/0.0.0', basicAuthToken()) + connection + .connect('mydriver/0.0.0', basicAuthToken()) .then(() => done.fail('Should not connect')) .catch(initialError => { - expect(initialError).toBeDefined(); - expect(initialError).not.toBeNull(); + expect(initialError).toBeDefined() + expect(initialError).not.toBeNull() - expect(connection.isOpen()).toBeFalsy(); + expect(connection.isOpen()).toBeFalsy() - const streamObserver = new StreamObserver(); + const streamObserver = new StreamObserver() streamObserver.subscribe({ onError: error => { - expect(error).toEqual(initialError); - done(); + expect(error).toEqual(initialError) + done() } - }); - connection._queueObserver(streamObserver); - }); - }); + }) + connection._queueObserver(streamObserver) + }) + }) it('should respect connection timeout', done => { - testConnectionTimeout(false, done); - }); + testConnectionTimeout(false, done) + }) it('should respect encrypted connection timeout', done => { - testConnectionTimeout(true, done); - }); + testConnectionTimeout(true, done) + }) it('should not queue INIT observer when broken', done => { - testQueueingOfObserversWithBrokenConnection(connection => connection.protocol().initialize('Hello', {}, {}), done); - }); + testQueueingOfObserversWithBrokenConnection( + connection => connection.protocol().initialize('Hello', {}, {}), + done + ) + }) it('should not queue RUN observer when broken', done => { - testQueueingOfObserversWithBrokenConnection(connection => - connection.protocol().run('RETURN 1', {}, Bookmark.empty(), TxConfig.empty(), {}), done); - }); + testQueueingOfObserversWithBrokenConnection( + connection => + connection + .protocol() + .run('RETURN 1', {}, Bookmark.empty(), TxConfig.empty(), {}), + done + ) + }) it('should not queue RESET observer when broken', done => { - const resetAction = connection => connection.resetAndFlush().catch(ignore => { - }); + const resetAction = connection => + connection.resetAndFlush().catch(ignore => {}) - testQueueingOfObserversWithBrokenConnection(resetAction, done); - }); + testQueueingOfObserversWithBrokenConnection(resetAction, done) + }) it('should reset and flush when SUCCESS received', done => { - connection = createConnection('bolt://localhost'); - - connection.connect('my-driver/1.2.3', basicAuthToken()) - .then(() => { - connection.resetAndFlush().then(() => { - expect(connection.isOpen()).toBeTruthy(); - done(); - }).catch(error => done.fail(error)); - - // write a SUCCESS message for RESET before the actual response is received - connection._handleMessage(SUCCESS_MESSAGE); - // enqueue a dummy observer to handle the real SUCCESS message - connection._queueObserver({ - onCompleted: () => { - } - }); - }); - }); + connection = createConnection('bolt://localhost') + + connection.connect('my-driver/1.2.3', basicAuthToken()).then(() => { + connection + .resetAndFlush() + .then(() => { + expect(connection.isOpen()).toBeTruthy() + done() + }) + .catch(error => done.fail(error)) + + // write a SUCCESS message for RESET before the actual response is received + connection._handleMessage(SUCCESS_MESSAGE) + // enqueue a dummy observer to handle the real SUCCESS message + connection._queueObserver({ + onCompleted: () => {} + }) + }) + }) it('should fail to reset and flush when FAILURE received', done => { - connection = createConnection('bolt://localhost'); - - connection.connect('my-driver/1.2.3', basicAuthToken()) - .then(() => { - connection.resetAndFlush() - .then(() => done.fail('Should fail')) - .catch(error => { - expect(error.message).toEqual('Received FAILURE as a response for RESET: Neo4jError: Hello'); - expect(connection._isBroken).toBeTruthy(); - expect(connection.isOpen()).toBeFalsy(); - done(); - }); - - // write a FAILURE message for RESET before the actual response is received - connection._handleMessage(FAILURE_MESSAGE); - // enqueue a dummy observer to handle the real SUCCESS message - connection._queueObserver({ - onCompleted: () => { - } - }); - }); - }); + connection = createConnection('bolt://localhost') + + connection.connect('my-driver/1.2.3', basicAuthToken()).then(() => { + connection + .resetAndFlush() + .then(() => done.fail('Should fail')) + .catch(error => { + expect(error.message).toEqual( + 'Received FAILURE as a response for RESET: Neo4jError: Hello' + ) + expect(connection._isBroken).toBeTruthy() + expect(connection.isOpen()).toBeFalsy() + done() + }) + + // write a FAILURE message for RESET before the actual response is received + connection._handleMessage(FAILURE_MESSAGE) + // enqueue a dummy observer to handle the real SUCCESS message + connection._queueObserver({ + onCompleted: () => {} + }) + }) + }) it('should fail to reset and flush when RECORD received', done => { - connection = createConnection('bolt://localhost'); - - connection.connect('my-driver/1.2.3', basicAuthToken()) - .then(() => { - connection.resetAndFlush() - .then(() => done.fail('Should fail')) - .catch(error => { - expect(error.message).toEqual('Received RECORD as a response for RESET: {"value":"Hello"}'); - expect(connection._isBroken).toBeTruthy(); - expect(connection.isOpen()).toBeFalsy(); - done(); - }); - - // write a RECORD message for RESET before the actual response is received - connection._handleMessage(RECORD_MESSAGE); - // enqueue a dummy observer to handle the real SUCCESS message - connection._queueObserver({ - onCompleted: () => { - } - }); - }); - }); + connection = createConnection('bolt://localhost') + + connection.connect('my-driver/1.2.3', basicAuthToken()).then(() => { + connection + .resetAndFlush() + .then(() => done.fail('Should fail')) + .catch(error => { + expect(error.message).toEqual( + 'Received RECORD as a response for RESET: {"value":"Hello"}' + ) + expect(connection._isBroken).toBeTruthy() + expect(connection.isOpen()).toBeFalsy() + done() + }) + + // write a RECORD message for RESET before the actual response is received + connection._handleMessage(RECORD_MESSAGE) + // enqueue a dummy observer to handle the real SUCCESS message + connection._queueObserver({ + onCompleted: () => {} + }) + }) + }) it('should acknowledge failure with RESET when SUCCESS received', done => { - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') - connection.connect('my-driver/1.2.3', basicAuthToken()) - .then(() => { - connection._currentFailure = newError('Hello'); - connection._resetOnFailure(); - - // write a SUCCESS message for RESET before the actual response is received - connection._handleMessage(SUCCESS_MESSAGE); - // enqueue a dummy observer to handle the real SUCCESS message - connection._queueObserver({ - onCompleted: () => { - } - }); + connection.connect('my-driver/1.2.3', basicAuthToken()).then(() => { + connection._currentFailure = newError('Hello') + connection._resetOnFailure() - expect(connection._currentFailure).toBeNull(); - done(); - }); - }); + // write a SUCCESS message for RESET before the actual response is received + connection._handleMessage(SUCCESS_MESSAGE) + // enqueue a dummy observer to handle the real SUCCESS message + connection._queueObserver({ + onCompleted: () => {} + }) + + expect(connection._currentFailure).toBeNull() + done() + }) + }) it('should handle and transform fatal errors', done => { - const errors = []; - const addresses = []; - const transformedError = newError('Message', 'Code'); - const errorHandler = new ConnectionErrorHandler(SERVICE_UNAVAILABLE, (error, address) => { - errors.push(error); - addresses.push(address); - return transformedError; - }); + const errors = [] + const addresses = [] + const transformedError = newError('Message', 'Code') + const errorHandler = new ConnectionErrorHandler( + SERVICE_UNAVAILABLE, + (error, address) => { + errors.push(error) + addresses.push(address) + return transformedError + } + ) - connection = Connection.create(ServerAddress.fromUrl('bolt://localhost'), {}, errorHandler, Logger.noOp()); + connection = Connection.create( + ServerAddress.fromUrl('bolt://localhost'), + {}, + errorHandler, + Logger.noOp() + ) connection._queueObserver({ onError: error => { - expect(error).toEqual(transformedError); - expect(errors.length).toEqual(1); - expect(errors[0].code).toEqual(SERVICE_UNAVAILABLE); - expect(addresses).toEqual([connection.address]); - done(); + expect(error).toEqual(transformedError) + expect(errors.length).toEqual(1) + expect(errors[0].code).toEqual(SERVICE_UNAVAILABLE) + expect(addresses).toEqual([connection.address]) + done() } - }); + }) - connection._handleFatalError(newError('Hello', SERVICE_UNAVAILABLE)); - }); + connection._handleFatalError(newError('Hello', SERVICE_UNAVAILABLE)) + }) it('should send INIT/HELLO and GOODBYE messages', done => { - const messages = []; - connection = createConnection('bolt://localhost'); - recordWrittenMessages(connection, messages); + const messages = [] + connection = createConnection('bolt://localhost') + recordWrittenMessages(connection, messages) - connection.connect('mydriver/0.0.0', basicAuthToken()) + connection + .connect('mydriver/0.0.0', basicAuthToken()) .then(() => { - expect(connection.isOpen()).toBeTruthy(); + expect(connection.isOpen()).toBeTruthy() connection.close(() => { - expect(messages.length).toBeGreaterThan(0); - expect(messages[0].signature).toEqual(0x01); // first message is either INIT or HELLO + expect(messages.length).toBeGreaterThan(0) + expect(messages[0].signature).toEqual(0x01) // first message is either INIT or HELLO - const serverVersion = ServerVersion.fromString(connection.server.version); + const serverVersion = ServerVersion.fromString( + connection.server.version + ) if (serverVersion.compareTo(VERSION_3_5_0) >= 0) { - expect(messages[messages.length - 1].signature).toEqual(0x02); // last message is GOODBYE in V3 + expect(messages[messages.length - 1].signature).toEqual(0x02) // last message is GOODBYE in V3 } - done(); - }); - }).catch(done.fail); - }); + done() + }) + }) + .catch(done.fail) + }) it('should not prepare broken connection to close', done => { - connection = createConnection('bolt://localhost'); + connection = createConnection('bolt://localhost') - connection.connect('my-connection/9.9.9', basicAuthToken()) + connection + .connect('my-connection/9.9.9', basicAuthToken()) .then(() => { - expect(connection._protocol).toBeDefined(); - expect(connection._protocol).not.toBeNull(); + expect(connection._protocol).toBeDefined() + expect(connection._protocol).not.toBeNull() // make connection seem broken - connection._isBroken = true; - expect(connection.isOpen()).toBeFalsy(); + connection._isBroken = true + expect(connection.isOpen()).toBeFalsy() connection._protocol.prepareToClose = () => { - throw new Error('Not supposed to be called'); - }; + throw new Error('Not supposed to be called') + } - connection.close(() => done()); + connection.close(() => done()) }) - .catch(error => done.fail(error)); - }); - - function packedHandshakeMessage() { - const result = alloc(4); - result.putInt32(0, 1); - result.reset(); - return result; + .catch(error => done.fail(error)) + }) + + function packedHandshakeMessage () { + const result = alloc(4) + result.putInt32(0, 1) + result.reset() + return result } - function packedFailureMessage(code, message) { - const channel = new DummyChannel(); - const chunker = new Chunker(channel); - const packer = new Packer(chunker); - packer.packStruct(0x7F, [packer.packable({code: code, message: message})]); - chunker.messageBoundary(); - chunker.flush(); - const data = channel.toBuffer(); - const result = alloc(data.length); - result.putBytes(0, data); - return result; + function packedFailureMessage (code, message) { + const channel = new DummyChannel() + const chunker = new Chunker(channel) + const packer = new Packer(chunker) + packer.packStruct(0x7f, [packer.packable({ code: code, message: message })]) + chunker.messageBoundary() + chunker.flush() + const data = channel.toBuffer() + const result = alloc(data.length) + result.putBytes(0, data) + return result } - function expectNeo4jError(error, expectedCode, expectedMessage) { + function expectNeo4jError (error, expectedCode, expectedMessage) { expect(() => { - throw error; - }).toThrow(new Neo4jError(expectedMessage, expectedCode)); - expect(error.name).toBe('Neo4jError'); + throw error + }).toThrow(new Neo4jError(expectedMessage, expectedCode)) + expect(error.name).toBe('Neo4jError') } - function basicAuthToken() { + function basicAuthToken () { return { scheme: 'basic', principal: sharedNeo4j.username, credentials: sharedNeo4j.password - }; + } } - function testConnectionTimeout(encrypted, done) { - const boltUri = 'bolt://10.0.0.0'; // use non-routable IP address which never responds - connection = createConnection(boltUri, {encrypted: encrypted, connectionTimeout: 1000}, 'TestErrorCode'); + function testConnectionTimeout (encrypted, done) { + const boltUri = 'bolt://10.0.0.0' // use non-routable IP address which never responds + connection = createConnection( + boltUri, + { encrypted: encrypted, connectionTimeout: 1000 }, + 'TestErrorCode' + ) - connection.connect('mydriver/0.0.0', basicAuthToken()) + connection + .connect('mydriver/0.0.0', basicAuthToken()) .then(() => done.fail('Should not be able to connect')) .catch(error => { - expect(error.code).toEqual('TestErrorCode'); + expect(error.code).toEqual('TestErrorCode') // in some environments non-routable address results in immediate 'connection refused' error and connect // timeout is not fired; skip message assertion for such cases, it is important for connect attempt to not hang if (error.message.indexOf('Failed to establish connection') === 0) { - expect(error.message).toEqual('Failed to establish connection in 1000ms'); + expect(error.message).toEqual( + 'Failed to establish connection in 1000ms' + ) } - done(); - }); + done() + }) } - function testQueueingOfObserversWithBrokenConnection(connectionAction, done) { - connection = createConnection('bolt://localhost'); + function testQueueingOfObserversWithBrokenConnection (connectionAction, done) { + connection = createConnection('bolt://localhost') connection._negotiateProtocol().then(() => { - connection._handleMessage(ILLEGAL_MESSAGE); - expect(connection.isOpen()).toBeFalsy(); + connection._handleMessage(ILLEGAL_MESSAGE) + expect(connection.isOpen()).toBeFalsy() - expect(connection._pendingObservers.length).toEqual(0); - connectionAction(connection); - expect(connection._pendingObservers.length).toEqual(0); + expect(connection._pendingObservers.length).toEqual(0) + connectionAction(connection) + expect(connection._pendingObservers.length).toEqual(0) - done(); - }); + done() + }) } /** * @return {Connection} */ - function createConnection(url, config, errorCode = null) { - return Connection.create(ServerAddress.fromUrl(url), config || {}, new ConnectionErrorHandler(errorCode || SERVICE_UNAVAILABLE), Logger.noOp()); + function createConnection (url, config, errorCode = null) { + return Connection.create( + ServerAddress.fromUrl(url), + config || {}, + new ConnectionErrorHandler(errorCode || SERVICE_UNAVAILABLE), + Logger.noOp() + ) } - function recordWrittenMessages(connection, messages) { - const originalWrite = connection.write.bind(connection); + function recordWrittenMessages (connection, messages) { + const originalWrite = connection.write.bind(connection) connection.write = (message, observer, flush) => { - messages.push(message); - originalWrite(message, observer, flush); - }; + messages.push(message) + originalWrite(message, observer, flush) + } } - -}); +}) diff --git a/test/internal/connectivity-verifier.test.js b/test/internal/connectivity-verifier.test.js index 6cea8d1d6..45b69b645 100644 --- a/test/internal/connectivity-verifier.test.js +++ b/test/internal/connectivity-verifier.test.js @@ -17,21 +17,19 @@ * limitations under the License. */ -import ConnectivityVerifier from '../../src/v1/internal/connectivity-verifier'; -import {SingleConnectionProvider} from '../../src/v1/internal/connection-providers'; -import FakeConnection from './fake-connection'; +import ConnectivityVerifier from '../../src/v1/internal/connectivity-verifier' +import { SingleConnectionProvider } from '../../src/v1/internal/connection-providers' +import FakeConnection from './fake-connection' describe('ConnectivityVerifier', () => { - it('should call success callback when able to acquire and release a connection', done => { - const connectionPromise = Promise.resolve(new FakeConnection()); - const connectionProvider = new SingleConnectionProvider(connectionPromise); + const connectionPromise = Promise.resolve(new FakeConnection()) + const connectionProvider = new SingleConnectionProvider(connectionPromise) const verifier = new ConnectivityVerifier(connectionProvider, () => { - done(); - }); - - verifier.verify(); - }); + done() + }) -}); + verifier.verify() + }) +}) diff --git a/test/internal/dummy-channel.js b/test/internal/dummy-channel.js index 522ea2d55..ee29b0912 100644 --- a/test/internal/dummy-channel.js +++ b/test/internal/dummy-channel.js @@ -17,49 +17,48 @@ * limitations under the License. */ -import CombinedBuffer from '../../src/v1/internal/buf/combined-buf'; +import CombinedBuffer from '../../src/v1/internal/buf/combined-buf' export default class DummyChannel { - /** * @constructor * @param {ChannelConfig} config - configuration for the new channel. */ - constructor(config) { - this.written = []; + constructor (config) { + this.written = [] } - isEncrypted() { - return false; + isEncrypted () { + return false } - write(buf) { - this.written.push(buf); + write (buf) { + this.written.push(buf) } - toHex() { - let out = ''; + toHex () { + let out = '' for (let i = 0; i < this.written.length; i++) { - out += this.written[i].toHex(); + out += this.written[i].toHex() if (i !== this.written.length - 1) { - out += ' '; + out += ' ' } } - return out; + return out } - toBuffer() { - return new CombinedBuffer(this.written); + toBuffer () { + return new CombinedBuffer(this.written) } - close(cb) { - this.clear(); + close (cb) { + this.clear() if (cb) { - return cb(); + return cb() } } - clear() { - this.written = []; + clear () { + this.written = [] } } diff --git a/test/internal/fake-connection.js b/test/internal/fake-connection.js index afa968ceb..2df0b2b4d 100644 --- a/test/internal/fake-connection.js +++ b/test/internal/fake-connection.js @@ -25,65 +25,64 @@ * PhantomJS which does not support proxies. */ export default class FakeConnection { + constructor () { + this._open = true + this.creationTimestamp = Date.now() - constructor() { - this._open = true; - this.creationTimestamp = Date.now(); - - this.resetInvoked = 0; - this.releaseInvoked = 0; - this.seenStatements = []; - this.seenParameters = []; - this.server = {}; + this.resetInvoked = 0 + this.releaseInvoked = 0 + this.seenStatements = [] + this.seenParameters = [] + this.server = {} } - protocol() { + protocol () { // return fake protocol object that simply records seen statements and parameters return { run: (statement, parameters) => { - this.seenStatements.push(statement); - this.seenParameters.push(parameters); + this.seenStatements.push(statement) + this.seenParameters.push(parameters) } - }; + } } - resetAndFlush() { - this.resetInvoked++; - return Promise.resolve(); + resetAndFlush () { + this.resetInvoked++ + return Promise.resolve() } - _release() { - this.releaseInvoked++; + _release () { + this.releaseInvoked++ } - isOpen() { - return this._open; + isOpen () { + return this._open } - isNeverReleased() { - return this.isReleasedTimes(0); + isNeverReleased () { + return this.isReleasedTimes(0) } - isReleasedOnce() { - return this.isReleasedTimes(1); + isReleasedOnce () { + return this.isReleasedTimes(1) } - isReleasedTimes(times) { - return this.resetInvoked === times && this.releaseInvoked === times; + isReleasedTimes (times) { + return this.resetInvoked === times && this.releaseInvoked === times } - withServerVersion(version) { - this.server.version = version; - return this; + withServerVersion (version) { + this.server.version = version + return this } - withCreationTimestamp(value) { - this.creationTimestamp = value; - return this; + withCreationTimestamp (value) { + this.creationTimestamp = value + return this } - closed() { - this._open = false; - return this; + closed () { + this._open = false + return this } -}; +} diff --git a/test/internal/http/http-driver.test.js b/test/internal/http/http-driver.test.js index 9fb3d29b0..11977d763 100644 --- a/test/internal/http/http-driver.test.js +++ b/test/internal/http/http-driver.test.js @@ -17,95 +17,156 @@ * limitations under the License. */ -import neo4j from '../../../src/v1'; -import sharedNeo4j from '../../internal/shared-neo4j'; -import testUtils from '.././test-utils'; -import {ServerVersion, VERSION_3_1_0, VERSION_3_4_0} from '../../../src/v1/internal/server-version'; +import neo4j from '../../../src/v1' +import sharedNeo4j from '../../internal/shared-neo4j' +import testUtils from '.././test-utils' +import { + ServerVersion, + VERSION_3_1_0, + VERSION_3_4_0 +} from '../../../src/v1/internal/server-version' describe('http driver', () => { - - let originalTimeout; - let boltDriver; - let httpDriver; - let serverVersion; + let originalTimeout + let boltDriver + let httpDriver + let serverVersion beforeEach(async () => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000 - boltDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {disableLosslessIntegers: true}); - httpDriver = neo4j.driver('http://localhost:7474', sharedNeo4j.authToken); + boltDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + disableLosslessIntegers: true + }) + httpDriver = neo4j.driver('http://localhost:7474', sharedNeo4j.authToken) - const session = boltDriver.session(); + const session = boltDriver.session() try { - const result = await session.run('MATCH (n) DETACH DELETE n'); - serverVersion = ServerVersion.fromString(result.summary.server.version); + const result = await session.run('MATCH (n) DETACH DELETE n') + serverVersion = ServerVersion.fromString(result.summary.server.version) } finally { - session.close(); + session.close() } - }); + }) afterEach(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout if (boltDriver) { - boltDriver.close(); - boltDriver = null; + boltDriver.close() + boltDriver = null } if (httpDriver) { - httpDriver.close(); - httpDriver = null; + httpDriver.close() + httpDriver = null } - }); + }) it('should send and receive primitives', async () => { if (testUtils.isServer()) { - return; + return } const primitiveValues = [ null, - 0, 1, 2, 3, 42, -1, -2, -3, 100, -100, 424242, -424242, - 0.12345, -0.12345, 1.25, -1.25, 5.99, -5.99, 1000.99, -1000.99, 1234.56789, -1234.56789, - neo4j.int(0), neo4j.int(1), neo4j.int(-1), neo4j.int(42), neo4j.int(-42), neo4j.int(12345), neo4j.int(-12345), - '', 'hello', 'hello world!', 'Thor and Mjölnir', 'Хеллоу' - ]; - - await testSendAndReceiveWithReturnQuery(primitiveValues); - }); + 0, + 1, + 2, + 3, + 42, + -1, + -2, + -3, + 100, + -100, + 424242, + -424242, + 0.12345, + -0.12345, + 1.25, + -1.25, + 5.99, + -5.99, + 1000.99, + -1000.99, + 1234.56789, + -1234.56789, + neo4j.int(0), + neo4j.int(1), + neo4j.int(-1), + neo4j.int(42), + neo4j.int(-42), + neo4j.int(12345), + neo4j.int(-12345), + '', + 'hello', + 'hello world!', + 'Thor and Mjölnir', + 'Хеллоу' + ] + + await testSendAndReceiveWithReturnQuery(primitiveValues) + }) it('should send and receive arrays', async () => { if (testUtils.isServer()) { - return; + return } const arrayValues = [ [], - [42], [-42], [1, 2, 3], [-1, -2, -3], [1, 2, 3, 4, 5, 6, 7, 10000000], [-10000000, 42, 7, 6, 5, 4, 3, 2, 1], - [0.001], [-0.19, 0.19], [100.25, 123.456, 90.99, 88.112], [-901.33, -90.90, 133, 144, 77835], - [''], ['hello'], ['hello', ' ', 'world', '!'], ['Thor', ' ', 'has ', 'Mjölnir'], ['Hello', ' is ', 'Хеллоу'], - ]; - - await testSendAndReceiveWithReturnQuery(arrayValues); - }); + [42], + [-42], + [1, 2, 3], + [-1, -2, -3], + [1, 2, 3, 4, 5, 6, 7, 10000000], + [-10000000, 42, 7, 6, 5, 4, 3, 2, 1], + [0.001], + [-0.19, 0.19], + [100.25, 123.456, 90.99, 88.112], + [-901.33, -90.9, 133, 144, 77835], + [''], + ['hello'], + ['hello', ' ', 'world', '!'], + ['Thor', ' ', 'has ', 'Mjölnir'], + ['Hello', ' is ', 'Хеллоу'] + ] + + await testSendAndReceiveWithReturnQuery(arrayValues) + }) it('should send and receive objects', async () => { if (testUtils.isServer()) { - return; + return } const objectValues = [ {}, - {name: 'Sam', age: 20, salary: 100}, {name: 'Tom', age: 20, scores: [1, 2, 3], values: [neo4j.int(1), neo4j.int(42)]}, - {name: 'Cat', value: neo4j.int(42), info: {otherName: 'Dog', wight: neo4j.int(20), otherInfo: {likes: ['eat', 'drink']}}} - ]; + { name: 'Sam', age: 20, salary: 100 }, + { + name: 'Tom', + age: 20, + scores: [1, 2, 3], + values: [neo4j.int(1), neo4j.int(42)] + }, + { + name: 'Cat', + value: neo4j.int(42), + info: { + otherName: 'Dog', + wight: neo4j.int(20), + otherInfo: { likes: ['eat', 'drink'] } + } + } + ] - await testSendAndReceiveWithReturnQuery(objectValues); - }); + await testSendAndReceiveWithReturnQuery(objectValues) + }) it('should receive nodes', async () => { if (testUtils.isServer()) { - return; + return } await runSetupQueries([ @@ -114,7 +175,7 @@ describe('http driver', () => { `CREATE (:Node3 {name: 'Node3', age: 42})`, `CREATE (:Node4 {name: 'Node4', age: 4242, value: 42.05})`, `CREATE (:Node5:Cat:Dog {name: 'Node5', age: 12, value: -0.006, scores: [0.25, -0.15, 100], likes: ['food', 'drinks']})` - ]); + ]) await testReceivingOfResults([ `MATCH (n:Node1) RETURN n`, @@ -127,31 +188,31 @@ describe('http driver', () => { `MATCH (a:Node1), (b:Node2), (c:Node3), (d:Node4), (e:Node5) RETURN a, b, c, d, e AS eee`, `MATCH (a:Node1), (b:Node2), (c:Node3), (d:Node4), (e:Node5) RETURN e, a, c, d, b`, `MATCH (n) RETURN n` - ]); - }); + ]) + }) it('should receive relationships', async () => { if (testUtils.isServer()) { - return; + return } await runSetupQueries([ `CREATE (:Node1)-[:KNOWS]->(:Node2)`, `CREATE (:Node3)-[:KNOWS {name: 'foo'}]->(:Node4)`, - `CREATE (:Node5)-[:KNOWS {name: 'foo', value: 42, score: 12.5, values: [1,2,3, -42], strings: ['a','b','c']}]->(:Node6)`, - ]); + `CREATE (:Node5)-[:KNOWS {name: 'foo', value: 42, score: 12.5, values: [1,2,3, -42], strings: ['a','b','c']}]->(:Node6)` + ]) await testReceivingOfResults([ `MATCH (:Node1)-[r]->(:Node2) RETURN r`, `MATCH (:Node3)-[r]->(:Node4) RETURN r`, `MATCH (:Node5)-[r]->(:Node6) RETURN r`, `MATCH ()-[r]-() RETURN r` - ]); - }); + ]) + }) it('should receive paths', async () => { if (testUtils.isServer()) { - return; + return } await runSetupQueries([ @@ -160,7 +221,7 @@ describe('http driver', () => { (:Person4 {name: 'Person4'})<-[:LIKES {why: 'why!'}]- (:Person5 {name: 'Person5'})-[:KNOWS]-> (:Person6 {name: 'Person6'})` - ]); + ]) await testReceivingOfResults([ `MATCH p=((:Person1)-[:KNOWS]->(:Person2)) RETURN p`, @@ -170,192 +231,234 @@ describe('http driver', () => { `MATCH p=((:Person1)-[*]-()) RETURN p`, `MATCH p=((:Person3)-[*]-()) RETURN p`, `MATCH p=((:Person6)-[*]-()) RETURN p` - ]); - }); + ]) + }) it('should receive errors', async () => { if (testUtils.isServer()) { - return; + return } - const query = 'UNWIND [1,2,3,0] AS x RETURN 10/x'; + const query = 'UNWIND [1,2,3,0] AS x RETURN 10/x' - const boltError = await runQueryAndGetError(query, boltDriver); - const httpError = await runQueryAndGetError(query, httpDriver); + const boltError = await runQueryAndGetError(query, boltDriver) + const httpError = await runQueryAndGetError(query, httpDriver) - expect(boltError.name).toEqual(httpError.name); - expect(boltError.code).toEqual(httpError.code); - expect(boltError.message).toEqual(httpError.message); - }); + expect(boltError.name).toEqual(httpError.name) + expect(boltError.code).toEqual(httpError.code) + expect(boltError.message).toEqual(httpError.message) + }) it('should receive server address', async () => { if (testUtils.isServer()) { - return; + return } - const query = `CREATE (n1:Node1 {name: 'Node1'})-[r:LIKES {date: 12345}]->(n2:Node2 {name: 'Node2'}) RETURN n1, r, n2`; + const query = `CREATE (n1:Node1 {name: 'Node1'})-[r:LIKES {date: 12345}]->(n2:Node2 {name: 'Node2'}) RETURN n1, r, n2` - const summary = await runQueryAndGetSummary(query, httpDriver); - expect(summary.server.address).toEqual('localhost:7474'); - }); + const summary = await runQueryAndGetSummary(query, httpDriver) + expect(summary.server.address).toEqual('localhost:7474') + }) it('should receive statement statistics', async () => { if (testUtils.isServer()) { - return; + return } - const query = `CREATE (n1:Node {value: 1}), (n2:Node {name: '2', value: 2}) WITH n1, n2 DELETE n1 RETURN n1, n2`; + const query = `CREATE (n1:Node {value: 1}), (n2:Node {name: '2', value: 2}) WITH n1, n2 DELETE n1 RETURN n1, n2` - const boltStatementStatistics = await runQueryAndGetStatementStatistics(query, boltDriver); - const httpStatementStatistics = await runQueryAndGetStatementStatistics(query, httpDriver); + const boltStatementStatistics = await runQueryAndGetStatementStatistics( + query, + boltDriver + ) + const httpStatementStatistics = await runQueryAndGetStatementStatistics( + query, + httpDriver + ) - expect(boltStatementStatistics).toEqual(httpStatementStatistics); - }); + expect(boltStatementStatistics).toEqual(httpStatementStatistics) + }) it('should use default HTTP port', async () => { if (testUtils.isServer()) { - return; + return } - const driver = neo4j.driver('http://localhost', sharedNeo4j.authToken); - const session = driver.session(); + const driver = neo4j.driver('http://localhost', sharedNeo4j.authToken) + const session = driver.session() try { - const result = await session.run('RETURN 4242'); - expect(result.records[0].get(0)).toEqual(4242); - expect(result.summary.server.address).toEqual('localhost:7474'); + const result = await session.run('RETURN 4242') + expect(result.records[0].get(0)).toEqual(4242) + expect(result.summary.server.address).toEqual('localhost:7474') } finally { - session.close(); + session.close() } - }); + }) it('should terminate query waiting on a lock when session is closed', async () => { - if (testUtils.isServer() || !databaseSupportsTransactionTerminationInLocks()) { - return; + if ( + testUtils.isServer() || + !databaseSupportsTransactionTerminationInLocks() + ) { + return } - const boltSession = boltDriver.session(); - let boltTx = null; + const boltSession = boltDriver.session() + let boltTx = null try { - await boltSession.run(`CREATE (:Node {name: 'foo'})`); + await boltSession.run(`CREATE (:Node {name: 'foo'})`) - boltTx = boltSession.beginTransaction(); - await boltTx.run(`MATCH (n:Node {name: 'foo'}) SET n.name = 'bar'`); + boltTx = boltSession.beginTransaction() + await boltTx.run(`MATCH (n:Node {name: 'foo'}) SET n.name = 'bar'`) // node should now be locked - const httpSession = httpDriver.session(); + const httpSession = httpDriver.session() setTimeout(() => { - httpSession.close(); - }, 2000); + httpSession.close() + }, 2000) - let failed = false; + let failed = false try { - await httpSession.run(`MATCH (n:Node {name: 'foo'}) SET n.name = 'baz'`); + await httpSession.run(`MATCH (n:Node {name: 'foo'}) SET n.name = 'baz'`) } catch (error) { - failed = true; - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual('Neo.DatabaseError.Statement.ExecutionFailed'); - expect(error.message.indexOf('transaction has been terminated')).not.toBeLessThan(0); + failed = true + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual( + 'Neo.DatabaseError.Statement.ExecutionFailed' + ) + expect( + error.message.indexOf('transaction has been terminated') + ).not.toBeLessThan(0) } if (!failed) { - throw new Error('HTTP query was successful but failure expected'); + throw new Error('HTTP query was successful but failure expected') } } finally { if (boltTx) { try { - await boltTx.rollback(); - } catch (ignore) { - } + await boltTx.rollback() + } catch (ignore) {} } - boltSession.close(); + boltSession.close() } - }); + }) it('should fail to pass node as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Node(neo4j.int(1), ['Person'], {name: 'Bob'})); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Node(neo4j.int(1), ['Person'], { name: 'Bob' }) + ) + }) it('should fail to pass relationship as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Relationship(neo4j.int(1), neo4j.int(2), neo4j.int(3), 'KNOWS', {since: 42})); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Relationship( + neo4j.int(1), + neo4j.int(2), + neo4j.int(3), + 'KNOWS', + { since: 42 } + ) + ) + }) it('should fail to pass path as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - const node1 = new neo4j.types.Node(neo4j.int(1), ['Person'], {name: 'Alice'}); - const node2 = new neo4j.types.Node(neo4j.int(2), ['Person'], {name: 'Bob'}); - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Path(node1, node2, [])); - }); + const node1 = new neo4j.types.Node(neo4j.int(1), ['Person'], { + name: 'Alice' + }) + const node2 = new neo4j.types.Node(neo4j.int(2), ['Person'], { + name: 'Bob' + }) + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Path(node1, node2, []) + ) + }) it('should fail to pass point as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Point(neo4j.int(42), 1, 2, 3)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Point(neo4j.int(42), 1, 2, 3) + ) + }) it('should fail to pass date as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Date(2000, 10, 12)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Date(2000, 10, 12) + ) + }) it('should fail to pass date-time as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.DateTime(2000, 10, 12, 12, 12, 0, 0, 0, null)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.DateTime(2000, 10, 12, 12, 12, 0, 0, 0, null) + ) + }) it('should fail to pass duration as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Duration(1, 1, 1, 1)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Duration(1, 1, 1, 1) + ) + }) it('should fail to pass local date-time as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.LocalDateTime(2000, 10, 12, 10, 10, 10, 10)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.LocalDateTime(2000, 10, 12, 10, 10, 10, 10) + ) + }) it('should fail to pass local time as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.LocalTime(12, 12, 12, 0)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.LocalTime(12, 12, 12, 0) + ) + }) it('should fail to pass time as a query parameter', async () => { if (testUtils.isServer()) { - return; + return } - await testUnsupportedQueryParameterWithHttpDriver(new neo4j.types.Time(12, 12, 12, 0, 0)); - }); + await testUnsupportedQueryParameterWithHttpDriver( + new neo4j.types.Time(12, 12, 12, 0, 0) + ) + }) it('should receive points', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceivingOfResults([ @@ -363,233 +466,252 @@ describe('http driver', () => { 'RETURN point({x: 13.2, y: 22.2, z: 33.3})', 'RETURN point({x: 92.3, y: 71.2, z: 2.12345, crs: "wgs-84-3d"})', 'RETURN point({longitude: 56.7, latitude: 12.78})' - ]); - }); + ]) + }) it('should receive date', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN date({year: 2019, month: 9, day: 28})', - '2019-09-28'); - }); + '2019-09-28' + ) + }) it('should receive date-time with time zone id', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN datetime({year: 1976, month: 11, day: 1, hour: 19, minute: 20, second: 55, nanosecond: 999111, timezone: "UTC"})', - '1976-11-01T19:20:55.000999111Z[UTC]'); - }); + '1976-11-01T19:20:55.000999111Z[UTC]' + ) + }) it('should receive date-time with time zone name', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN datetime({year: 2012, month: 12, day: 12, hour: 1, minute: 9, second: 2, nanosecond: 123, timezone: "-08:30"})', - '2012-12-12T01:09:02.000000123-08:30'); - }); + '2012-12-12T01:09:02.000000123-08:30' + ) + }) it('should receive duration', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN duration({months: 3, days: 35, seconds: 19, nanoseconds: 937139})', - 'P3M35DT19.000937139S'); - }); + 'P3M35DT19.000937139S' + ) + }) it('should receive local date-time', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN localdatetime({year: 2032, month: 5, day: 17, hour: 13, minute: 56, second: 51, nanosecond: 999888111})', - '2032-05-17T13:56:51.999888111'); - }); + '2032-05-17T13:56:51.999888111' + ) + }) it('should receive local time', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN localtime({hour: 17, minute: 2, second: 21, nanosecond: 123456789})', - '17:02:21.123456789'); - }); + '17:02:21.123456789' + ) + }) it('should receive time', async () => { if (testUtils.isServer() || !databaseSupportsSpatialAndTemporalTypes()) { - return; + return } await testReceiveSingleValueWithHttpDriver( 'RETURN time({hour: 21, minute: 19, second: 1, nanosecond: 111, timezone: "+03:15"})', - '21:19:01.000000111+03:15'); - }); + '21:19:01.000000111+03:15' + ) + }) it('should close all open sessions when closed', async () => { if (testUtils.isServer()) { - return; + return } - const session1 = withFakeClose(httpDriver.session()); - const session2 = withFakeClose(httpDriver.session()); - const session3 = withFakeClose(httpDriver.session()); + const session1 = withFakeClose(httpDriver.session()) + const session2 = withFakeClose(httpDriver.session()) + const session3 = withFakeClose(httpDriver.session()) - expect(session1.closed).toBeFalsy(); - expect(session2.closed).toBeFalsy(); - expect(session3.closed).toBeFalsy(); + expect(session1.closed).toBeFalsy() + expect(session2.closed).toBeFalsy() + expect(session3.closed).toBeFalsy() - await httpDriver.close(); + await httpDriver.close() - expect(session1.closed).toBeTruthy(); - expect(session2.closed).toBeTruthy(); - expect(session3.closed).toBeTruthy(); - }); + expect(session1.closed).toBeTruthy() + expect(session2.closed).toBeTruthy() + expect(session3.closed).toBeTruthy() + }) - async function testReceiveSingleValueWithHttpDriver(query, expectedValue) { - const results = await runQueryAndGetResults(query, {}, httpDriver); - const receivedValue = results[0][0]; - expect(expectedValue).toEqual(receivedValue); + async function testReceiveSingleValueWithHttpDriver (query, expectedValue) { + const results = await runQueryAndGetResults(query, {}, httpDriver) + const receivedValue = results[0][0] + expect(expectedValue).toEqual(receivedValue) } - async function testSendAndReceiveWithReturnQuery(values) { - const query = 'RETURN $value'; + async function testSendAndReceiveWithReturnQuery (values) { + const query = 'RETURN $value' - const boltResults = []; + const boltResults = [] for (const value of values) { - const boltResult = await runQueryAndGetResults(query, {value: value}, boltDriver); - boltResults.push(boltResult); + const boltResult = await runQueryAndGetResults( + query, + { value: value }, + boltDriver + ) + boltResults.push(boltResult) } - const httpResults = []; + const httpResults = [] for (const value of values) { - const httpResult = await runQueryAndGetResults(query, {value: value}, httpDriver); - httpResults.push(httpResult); + const httpResult = await runQueryAndGetResults( + query, + { value: value }, + httpDriver + ) + httpResults.push(httpResult) } - assertResultsAreEqual(boltResults, httpResults, values); + assertResultsAreEqual(boltResults, httpResults, values) } - async function testReceivingOfResults(queries) { - const boltResults = []; + async function testReceivingOfResults (queries) { + const boltResults = [] for (const query of queries) { - const boltResult = await runQueryAndGetResults(query, {}, boltDriver); - boltResults.push(boltResult); + const boltResult = await runQueryAndGetResults(query, {}, boltDriver) + boltResults.push(boltResult) } - const httpResults = []; + const httpResults = [] for (const query of queries) { - const httpResult = await runQueryAndGetResults(query, {}, httpDriver); - httpResults.push(httpResult); + const httpResult = await runQueryAndGetResults(query, {}, httpDriver) + httpResults.push(httpResult) } - assertResultsAreEqual(boltResults, httpResults, queries); + assertResultsAreEqual(boltResults, httpResults, queries) } - function assertResultsAreEqual(boltResults, httpResults, testInputs) { - expect(boltResults.length).toEqual(testInputs.length); - expect(httpResults.length).toEqual(testInputs.length); + function assertResultsAreEqual (boltResults, httpResults, testInputs) { + expect(boltResults.length).toEqual(testInputs.length) + expect(httpResults.length).toEqual(testInputs.length) for (let i = 0; i < testInputs.length; i++) { - const testInput = testInputs[i]; - const boltResultRow = boltResults[i]; - const httpResultRow = httpResults[i]; - expect(boltResultRow).toEqual(httpResultRow, 'Failed for: ' + JSON.stringify(testInput)); + const testInput = testInputs[i] + const boltResultRow = boltResults[i] + const httpResultRow = httpResults[i] + expect(boltResultRow).toEqual( + httpResultRow, + 'Failed for: ' + JSON.stringify(testInput) + ) } } - async function runQueryAndGetResults(query, params, driver) { - const session = driver.session(); + async function runQueryAndGetResults (query, params, driver) { + const session = driver.session() try { - const result = await session.run(query, params); - return result.records.map(record => record.keys.map(key => record.get(key))); + const result = await session.run(query, params) + return result.records.map(record => + record.keys.map(key => record.get(key)) + ) } finally { - session.close(); + session.close() } } - async function runQueryAndGetError(query, driver) { - const session = driver.session(); + async function runQueryAndGetError (query, driver) { + const session = driver.session() try { - await session.run(query); + await session.run(query) } catch (e) { - return e; + return e } finally { - session.close(); + session.close() } } - async function runQueryAndGetStatementStatistics(query, driver) { - const summary = await runQueryAndGetSummary(query, driver); - return summary.counters; + async function runQueryAndGetStatementStatistics (query, driver) { + const summary = await runQueryAndGetSummary(query, driver) + return summary.counters } - async function runQueryAndGetSummary(query, driver) { - const session = driver.session(); + async function runQueryAndGetSummary (query, driver) { + const session = driver.session() try { - const result = await session.run(query); - return result.summary; + const result = await session.run(query) + return result.summary } finally { - session.close(); + session.close() } } - async function runSetupQueries(queries) { - const session = boltDriver.session(); + async function runSetupQueries (queries) { + const session = boltDriver.session() try { await session.writeTransaction(tx => { - queries.forEach(query => tx.run(query)); - return null; - }); + queries.forEach(query => tx.run(query)) + return null + }) } finally { - session.close(); + session.close() } } - async function testUnsupportedQueryParameterWithHttpDriver(value) { - const session = httpDriver.session(); - let failed = false; + async function testUnsupportedQueryParameterWithHttpDriver (value) { + const session = httpDriver.session() + let failed = false try { - await session.run('RETURN $value', {value: value}); + await session.run('RETURN $value', { value: value }) } catch (error) { - failed = true; - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual(neo4j.error.PROTOCOL_ERROR); + failed = true + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual(neo4j.error.PROTOCOL_ERROR) } finally { - session.close(); + session.close() } if (!failed) { - throw new Error('Should not be possible to send ' + value); + throw new Error('Should not be possible to send ' + value) } } - function databaseSupportsTransactionTerminationInLocks() { - return serverVersion.compareTo(VERSION_3_1_0) >= 0; + function databaseSupportsTransactionTerminationInLocks () { + return serverVersion.compareTo(VERSION_3_1_0) >= 0 } - function databaseSupportsSpatialAndTemporalTypes() { - return serverVersion.compareTo(VERSION_3_4_0) >= 0; + function databaseSupportsSpatialAndTemporalTypes () { + return serverVersion.compareTo(VERSION_3_4_0) >= 0 } - function withFakeClose(httpSession) { - httpSession.closed = false; - const originalClose = httpSession.close.bind(httpSession); + function withFakeClose (httpSession) { + httpSession.closed = false + const originalClose = httpSession.close.bind(httpSession) httpSession.close = callback => { - httpSession.closed = true; - originalClose(callback); - }; - return httpSession; + httpSession.closed = true + originalClose(callback) + } + return httpSession } - -}); +}) diff --git a/test/internal/http/http-request-runner.test.js b/test/internal/http/http-request-runner.test.js index a284674d2..76eb1b38b 100644 --- a/test/internal/http/http-request-runner.test.js +++ b/test/internal/http/http-request-runner.test.js @@ -17,296 +17,378 @@ * limitations under the License. */ -import HttpRequestRunner from '../../../src/v1/internal/http/http-request-runner'; -import neo4j from '../../../src/v1'; -import sharedNeo4j from '../../internal/shared-neo4j'; -import urlUtil from '../../../src/v1/internal/url-util'; -import testUtils from '.././test-utils'; -import _ from 'lodash'; +import HttpRequestRunner from '../../../src/v1/internal/http/http-request-runner' +import neo4j from '../../../src/v1' +import sharedNeo4j from '../../internal/shared-neo4j' +import urlUtil from '../../../src/v1/internal/url-util' +import testUtils from '.././test-utils' +import _ from 'lodash' -const VALID_URI = 'http://localhost'; -const INVALID_URI = 'http://not-localhost'; +const VALID_URI = 'http://localhost' +const INVALID_URI = 'http://not-localhost' describe('http request runner', () => { - it('should begin transaction', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(VALID_URI); + const runner = newRunner(VALID_URI) - runner.beginTransaction().then(transactionId => { - verifyTransactionId(transactionId); - done(); - }).catch(error => { - done.fail(error); - }); - }); + runner + .beginTransaction() + .then(transactionId => { + verifyTransactionId(transactionId) + done() + }) + .catch(error => { + done.fail(error) + }) + }) it('should begin and commit transaction', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(VALID_URI); - - runner.beginTransaction().then(transactionId => { - verifyTransactionId(transactionId); - runner.commitTransaction(transactionId).then(() => { - done(); - }).catch(error => { - done.fail(error); - }); - }).catch(error => { - done.fail(error); - }); - }); + const runner = newRunner(VALID_URI) + + runner + .beginTransaction() + .then(transactionId => { + verifyTransactionId(transactionId) + runner + .commitTransaction(transactionId) + .then(() => { + done() + }) + .catch(error => { + done.fail(error) + }) + }) + .catch(error => { + done.fail(error) + }) + }) it('should begin and rollback transaction', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(VALID_URI); - - runner.beginTransaction().then(transactionId => { - verifyTransactionId(transactionId); - runner.rollbackTransaction(transactionId).then(() => { - done(); - }).catch(error => { - done.fail(error); - }); - }).catch(error => { - done.fail(error); - }); - }); + const runner = newRunner(VALID_URI) + + runner + .beginTransaction() + .then(transactionId => { + verifyTransactionId(transactionId) + runner + .rollbackTransaction(transactionId) + .then(() => { + done() + }) + .catch(error => { + done.fail(error) + }) + }) + .catch(error => { + done.fail(error) + }) + }) it('should fail to begin transaction with invalid uri', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(INVALID_URI); - - runner.beginTransaction().then(transactionId => { - done.fail(new Error('Should not be possible to begin a transaction with invalid URI, received transactionId: ' + transactionId)); - }).catch(error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - }); - }); + const runner = newRunner(INVALID_URI) + + runner + .beginTransaction() + .then(transactionId => { + done.fail( + new Error( + 'Should not be possible to begin a transaction with invalid URI, received transactionId: ' + + transactionId + ) + ) + }) + .catch(error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() + }) + }) it('should fail to commit transaction with invalid uri', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(INVALID_URI); - - runner.commitTransaction(42).then(() => { - done.fail(new Error('Should not be possible to commit a transaction with invalid URI')); - }).catch(error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - }); - }); + const runner = newRunner(INVALID_URI) + + runner + .commitTransaction(42) + .then(() => { + done.fail( + new Error( + 'Should not be possible to commit a transaction with invalid URI' + ) + ) + }) + .catch(error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() + }) + }) it('should fail to rollback transaction with invalid uri', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(INVALID_URI); - - runner.rollbackTransaction(42).then(() => { - done.fail(new Error('Should not be possible to rollback a transaction with invalid URI')); - }).catch(error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - }); - }); + const runner = newRunner(INVALID_URI) + + runner + .rollbackTransaction(42) + .then(() => { + done.fail( + new Error( + 'Should not be possible to rollback a transaction with invalid URI' + ) + ) + }) + .catch(error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() + }) + }) it('should fail to commit transaction with invalid id', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(VALID_URI); - - runner.commitTransaction(424242).then(() => { - done.fail(new Error('Should not be possible to commit a transaction with invalid id')); - }).catch(error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual('Neo.ClientError.Transaction.TransactionNotFound'); - done(); - }); - }); + const runner = newRunner(VALID_URI) + + runner + .commitTransaction(424242) + .then(() => { + done.fail( + new Error( + 'Should not be possible to commit a transaction with invalid id' + ) + ) + }) + .catch(error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual( + 'Neo.ClientError.Transaction.TransactionNotFound' + ) + done() + }) + }) it('should fail to rollback transaction with invalid id', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(VALID_URI); - - runner.rollbackTransaction(424242).then(() => { - done.fail(new Error('Should not be possible to rollback a transaction with invalid id')); - }).catch(error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual('Neo.ClientError.Transaction.TransactionNotFound'); - done(); - }); - }); + const runner = newRunner(VALID_URI) + + runner + .rollbackTransaction(424242) + .then(() => { + done.fail( + new Error( + 'Should not be possible to rollback a transaction with invalid id' + ) + ) + }) + .catch(error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual( + 'Neo.ClientError.Transaction.TransactionNotFound' + ) + done() + }) + }) it('should run query in transaction', done => { if (testUtils.isServer()) { - done(); - return; + done() + return + } + + const runner = newRunner(VALID_URI) + + runner + .beginTransaction() + .then(transactionId => { + verifyTransactionId(transactionId) + runner + .runQuery(transactionId, 'RETURN 42', {}) + .then(streamObserver => { + streamObserver.subscribe({ + onNext: record => { + expect(record.get(0)).toEqual(42) + }, + onError: error => { + done.fail(error) + }, + onCompleted: () => { + runner + .rollbackTransaction(transactionId) + .catch(() => {}) + .then(() => { + done() + }) + } + }) + }) + .catch(error => { + done.fail(error) + }) + done() + }) + .catch(error => { + done.fail(error) + }) + }) + + it('should fail to run invalid query in transaction', done => { + if (testUtils.isServer()) { + done() + return + } + + const runner = newRunner(VALID_URI) + + runner + .beginTransaction() + .then(transactionId => { + verifyTransactionId(transactionId) + runner + .runQuery(transactionId, 'WRONG QUERY', {}) + .then(streamObserver => { + streamObserver.subscribe({ + onNext: () => { + done.fail(new Error('Should not receive records')) + }, + onError: error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual( + 'Neo.ClientError.Statement.SyntaxError' + ) + + runner + .rollbackTransaction(transactionId) + .catch(() => {}) + .then(() => { + done() + }) + }, + onCompleted: () => { + done.fail(new Error('Should not complete')) + } + }) + }) + .catch(error => { + done.fail(error) + }) + done() + }) + .catch(error => { + done.fail(error) + }) + }) + + it('should fail to run query in transaction with invalid uri', done => { + if (testUtils.isServer()) { + done() + return } - const runner = newRunner(VALID_URI); + const runner = newRunner(INVALID_URI) - runner.beginTransaction().then(transactionId => { - verifyTransactionId(transactionId); - runner.runQuery(transactionId, 'RETURN 42', {}).then(streamObserver => { + runner + .runQuery(424242, 'RETURN 42', {}) + .then(streamObserver => { + expect(streamObserver.hasFailed()).toBeTruthy() streamObserver.subscribe({ - onNext: record => { - expect(record.get(0)).toEqual(42); + onNext: () => { + done.fail(new Error('Should not receive records')) }, onError: error => { - done.fail(error); + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() }, onCompleted: () => { - runner.rollbackTransaction(transactionId).catch(error => { - }).then(() => { - done(); - }); + done.fail(new Error('Should not complete')) } - }); - }).catch(error => { - done.fail(error); - }); - done(); - }).catch(error => { - done.fail(error); - }); - }); + }) + }) + .catch(error => { + done.fail(error) + }) + }) - it('should fail to run invalid query in transaction', done => { + it('should fail to run query in transaction with invalid id', done => { if (testUtils.isServer()) { - done(); - return; + done() + return } - const runner = newRunner(VALID_URI); + const runner = newRunner(VALID_URI) - runner.beginTransaction().then(transactionId => { - verifyTransactionId(transactionId); - runner.runQuery(transactionId, 'WRONG QUERY', {}).then(streamObserver => { + runner + .runQuery(424242, 'RETURN 42', {}) + .then(streamObserver => { + expect(streamObserver.hasFailed()).toBeTruthy() streamObserver.subscribe({ onNext: () => { - done.fail(new Error('Should not receive records')); + done.fail(new Error('Should not receive records')) }, onError: error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError'); - - runner.rollbackTransaction(transactionId).catch(error => { - }).then(() => { - done(); - }); + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual( + 'Neo.ClientError.Transaction.TransactionNotFound' + ) + done() }, onCompleted: () => { - done.fail(new Error('Should not complete')); + done.fail(new Error('Should not complete')) } - }); - }).catch(error => { - done.fail(error); - }); - done(); - }).catch(error => { - done.fail(error); - }); - }); - - it('should fail to run query in transaction with invalid uri', done => { - if (testUtils.isServer()) { - done(); - return; - } - - const runner = newRunner(INVALID_URI); - - runner.runQuery(424242, 'RETURN 42', {}).then(streamObserver => { - expect(streamObserver.hasFailed()).toBeTruthy(); - streamObserver.subscribe({ - onNext: () => { - done.fail(new Error('Should not receive records')); - }, - onError: error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - }, - onCompleted: () => { - done.fail(new Error('Should not complete')); - } - }); - }).catch(error => { - done.fail(error); - }); - }); - - it('should fail to run query in transaction with invalid id', done => { - if (testUtils.isServer()) { - done(); - return; - } - - const runner = newRunner(VALID_URI); - - runner.runQuery(424242, 'RETURN 42', {}).then(streamObserver => { - expect(streamObserver.hasFailed()).toBeTruthy(); - streamObserver.subscribe({ - onNext: () => { - done.fail(new Error('Should not receive records')); - }, - onError: error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual('Neo.ClientError.Transaction.TransactionNotFound'); - done(); - }, - onCompleted: () => { - done.fail(new Error('Should not complete')); - } - }); - }).catch(error => { - done.fail(error); - }); - }); - -}); - -function verifyTransactionId(transactionId) { - expect(transactionId).toBeDefined(); - expect(transactionId).not.toBeNull(); - expect(_.isNumber(transactionId)).toBeTruthy(); + }) + }) + .catch(error => { + done.fail(error) + }) + }) +}) + +function verifyTransactionId (transactionId) { + expect(transactionId).toBeDefined() + expect(transactionId).not.toBeNull() + expect(_.isNumber(transactionId)).toBeTruthy() } -function newRunner(url, username, password) { - username = username ? username : sharedNeo4j.username; - password = password ? password : sharedNeo4j.password; - return new HttpRequestRunner(urlUtil.parseDatabaseUrl(url), neo4j.auth.basic(username, password)); +function newRunner (url, username, password) { + username = username || sharedNeo4j.username + password = password || sharedNeo4j.password + return new HttpRequestRunner( + urlUtil.parseDatabaseUrl(url), + neo4j.auth.basic(username, password) + ) } diff --git a/test/internal/http/http-session-tracker.test.js b/test/internal/http/http-session-tracker.test.js index 037c763c1..30f1b3506 100644 --- a/test/internal/http/http-session-tracker.test.js +++ b/test/internal/http/http-session-tracker.test.js @@ -16,68 +16,70 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import sharedNeo4j from '../../internal/shared-neo4j'; -import HttpSession from '../../../src/v1/internal/http/http-session'; -import urlUtil from '../../../src/v1/internal/url-util'; -import HttpSessionTracker from '../../../src/v1/internal/http/http-session-tracker'; +import sharedNeo4j from '../../internal/shared-neo4j' +import HttpSession from '../../../src/v1/internal/http/http-session' +import urlUtil from '../../../src/v1/internal/url-util' +import HttpSessionTracker from '../../../src/v1/internal/http/http-session-tracker' describe('http session tracker', () => { - it('should close open sessions', done => { - const tracker = new HttpSessionTracker(); + const tracker = new HttpSessionTracker() - const session1 = new FakeHttpSession(tracker); - const session2 = new FakeHttpSession(tracker); - const session3 = new FakeHttpSession(tracker); + const session1 = new FakeHttpSession(tracker) + const session2 = new FakeHttpSession(tracker) + const session3 = new FakeHttpSession(tracker) - tracker.sessionOpened(session1); - tracker.sessionOpened(session2); - tracker.sessionOpened(session3); + tracker.sessionOpened(session1) + tracker.sessionOpened(session2) + tracker.sessionOpened(session3) tracker.close().then(() => { - expect(session1.timesClosed).toEqual(1); - expect(session2.timesClosed).toEqual(1); - expect(session3.timesClosed).toEqual(1); - done(); - }); - }); + expect(session1.timesClosed).toEqual(1) + expect(session2.timesClosed).toEqual(1) + expect(session3.timesClosed).toEqual(1) + done() + }) + }) it('should not close closed sessions', done => { - const tracker = new HttpSessionTracker(); + const tracker = new HttpSessionTracker() - const session1 = new FakeHttpSession(tracker); - const session2 = new FakeHttpSession(tracker); - const session3 = new FakeHttpSession(tracker); - const session4 = new FakeHttpSession(tracker); + const session1 = new FakeHttpSession(tracker) + const session2 = new FakeHttpSession(tracker) + const session3 = new FakeHttpSession(tracker) + const session4 = new FakeHttpSession(tracker) - tracker.sessionOpened(session1); - tracker.sessionOpened(session2); - tracker.sessionOpened(session3); - tracker.sessionOpened(session4); + tracker.sessionOpened(session1) + tracker.sessionOpened(session2) + tracker.sessionOpened(session3) + tracker.sessionOpened(session4) - tracker.sessionClosed(session2); - tracker.sessionClosed(session4); + tracker.sessionClosed(session2) + tracker.sessionClosed(session4) tracker.close().then(() => { - expect(session1.timesClosed).toEqual(1); - expect(session2.timesClosed).toEqual(0); - expect(session3.timesClosed).toEqual(1); - expect(session4.timesClosed).toEqual(0); - done(); - }); - }); - -}); + expect(session1.timesClosed).toEqual(1) + expect(session2.timesClosed).toEqual(0) + expect(session3.timesClosed).toEqual(1) + expect(session4.timesClosed).toEqual(0) + done() + }) + }) +}) class FakeHttpSession extends HttpSession { - - constructor(sessionTracker) { - super(urlUtil.parseDatabaseUrl('http://localhost:7474'), sharedNeo4j.authToken, {}, sessionTracker); - this.timesClosed = 0; + constructor (sessionTracker) { + super( + urlUtil.parseDatabaseUrl('http://localhost:7474'), + sharedNeo4j.authToken, + {}, + sessionTracker + ) + this.timesClosed = 0 } - close(callback) { - this.timesClosed++; - callback(); + close (callback) { + this.timesClosed++ + callback() } } diff --git a/test/internal/http/http-session.test.js b/test/internal/http/http-session.test.js index 849f9d524..540cf4caf 100644 --- a/test/internal/http/http-session.test.js +++ b/test/internal/http/http-session.test.js @@ -16,27 +16,34 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import sharedNeo4j from '../../internal/shared-neo4j'; -import urlUtil from '../../../src/v1/internal/url-util'; -import testUtil from '../test-utils'; -import HttpSession from '../../../src/v1/internal/http/http-session'; -import HttpSessionTracker from '../../../src/v1/internal/http/http-session-tracker'; +import sharedNeo4j from '../../internal/shared-neo4j' +import urlUtil from '../../../src/v1/internal/url-util' +import testUtil from '../test-utils' +import HttpSession from '../../../src/v1/internal/http/http-session' +import HttpSessionTracker from '../../../src/v1/internal/http/http-session-tracker' describe('http session', () => { - it('should fail for invalid query parameters', done => { if (testUtil.isServer()) { - done(); - return; + done() + return } - const session = new HttpSession(urlUtil.parseDatabaseUrl('http://localhost:7474'), sharedNeo4j.authToken, {}, new HttpSessionTracker()); - - expect(() => session.run('RETURN $value', [1, 2, 3])).toThrowError(TypeError); - expect(() => session.run('RETURN $value', '123')).toThrowError(TypeError); - expect(() => session.run('RETURN $value', () => [123])).toThrowError(TypeError); + const session = new HttpSession( + urlUtil.parseDatabaseUrl('http://localhost:7474'), + sharedNeo4j.authToken, + {}, + new HttpSessionTracker() + ) - session.close(() => done()); - }); + expect(() => session.run('RETURN $value', [1, 2, 3])).toThrowError( + TypeError + ) + expect(() => session.run('RETURN $value', '123')).toThrowError(TypeError) + expect(() => session.run('RETURN $value', () => [123])).toThrowError( + TypeError + ) -}); + session.close(() => done()) + }) +}) diff --git a/test/internal/least-connected-load-balancing-strategy.test.js b/test/internal/least-connected-load-balancing-strategy.test.js index c1892fc8f..d58b71bb8 100644 --- a/test/internal/least-connected-load-balancing-strategy.test.js +++ b/test/internal/least-connected-load-balancing-strategy.test.js @@ -17,119 +17,134 @@ * limitations under the License. */ -import LeastConnectedLoadBalancingStrategy from '../../src/v1/internal/least-connected-load-balancing-strategy'; -import Pool from '../../src/v1/internal/pool'; +import LeastConnectedLoadBalancingStrategy from '../../src/v1/internal/least-connected-load-balancing-strategy' +import Pool from '../../src/v1/internal/pool' describe('LeastConnectedLoadBalancingStrategy', () => { - it('should return null when no readers', () => { - const knownReaders = []; - const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({})); + const knownReaders = [] + const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({})) - expect(strategy.selectReader(knownReaders)).toBeNull(); - }); + expect(strategy.selectReader(knownReaders)).toBeNull() + }) it('should return null when no writers', () => { - const knownWriters = []; - const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({})); + const knownWriters = [] + const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({})) - expect(strategy.selectWriter(knownWriters)).toBeNull(); - }); + expect(strategy.selectWriter(knownWriters)).toBeNull() + }) it('should return same reader when it is the only one available and has no connections', () => { - const knownReaders = ['reader-1']; - const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({'reader-1': 0})); + const knownReaders = ['reader-1'] + const strategy = new LeastConnectedLoadBalancingStrategy( + new DummyPool({ 'reader-1': 0 }) + ) - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - }); + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + }) it('should return same writer when it is the only one available and has no connections', () => { - const knownWriters = ['writer-1']; - const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({'writer-1': 0})); + const knownWriters = ['writer-1'] + const strategy = new LeastConnectedLoadBalancingStrategy( + new DummyPool({ 'writer-1': 0 }) + ) - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - }); + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + }) it('should return same reader when it is the only one available and has active connections', () => { - const knownReaders = ['reader-1']; - const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({'reader-1': 14})); + const knownReaders = ['reader-1'] + const strategy = new LeastConnectedLoadBalancingStrategy( + new DummyPool({ 'reader-1': 14 }) + ) - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - }); + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + }) it('should return same writer when it is the only one available and has active connections', () => { - const knownWriters = ['writer-1']; - const strategy = new LeastConnectedLoadBalancingStrategy(new DummyPool({'writer-1': 3})); + const knownWriters = ['writer-1'] + const strategy = new LeastConnectedLoadBalancingStrategy( + new DummyPool({ 'writer-1': 3 }) + ) - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - }); + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + }) it('should return readers in round robin order when no active connections', () => { - const knownReaders = ['reader-1', 'reader-2', 'reader-3']; - const pool = new DummyPool({'reader-1': 0, 'reader-2': 0, 'reader-3': 0}); - const strategy = new LeastConnectedLoadBalancingStrategy(pool); - - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-3'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-3'); - }); + const knownReaders = ['reader-1', 'reader-2', 'reader-3'] + const pool = new DummyPool({ 'reader-1': 0, 'reader-2': 0, 'reader-3': 0 }) + const strategy = new LeastConnectedLoadBalancingStrategy(pool) + + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + expect(strategy.selectReader(knownReaders)).toEqual('reader-3') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + expect(strategy.selectReader(knownReaders)).toEqual('reader-3') + }) it('should return writers in round robin order when no active connections', () => { - const knownWriters = ['writer-1', 'writer-2', 'writer-3', 'writer-4']; - const pool = new DummyPool({'writer-1': 0, 'writer-2': 0, 'writer-3': 0, 'writer-4': 0}); - const strategy = new LeastConnectedLoadBalancingStrategy(pool); - - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-2'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-3'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-2'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-3'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - }); + const knownWriters = ['writer-1', 'writer-2', 'writer-3', 'writer-4'] + const pool = new DummyPool({ + 'writer-1': 0, + 'writer-2': 0, + 'writer-3': 0, + 'writer-4': 0 + }) + const strategy = new LeastConnectedLoadBalancingStrategy(pool) + + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-2') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-3') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-2') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-3') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + }) it('should return least connected reader', () => { - const knownReaders = ['reader-1', 'reader-2', 'reader-3']; - const pool = new DummyPool({'reader-1': 7, 'reader-2': 3, 'reader-3': 8}); - const strategy = new LeastConnectedLoadBalancingStrategy(pool); + const knownReaders = ['reader-1', 'reader-2', 'reader-3'] + const pool = new DummyPool({ 'reader-1': 7, 'reader-2': 3, 'reader-3': 8 }) + const strategy = new LeastConnectedLoadBalancingStrategy(pool) - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - }); + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + }) it('should return least connected writer', () => { - const knownWriters = ['writer-1', 'writer-2', 'writer-3', 'writer-4']; - const pool = new DummyPool({'writer-1': 5, 'writer-2': 4, 'writer-3': 6, 'writer-4': 2}); - const strategy = new LeastConnectedLoadBalancingStrategy(pool); - - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - }); - -}); + const knownWriters = ['writer-1', 'writer-2', 'writer-3', 'writer-4'] + const pool = new DummyPool({ + 'writer-1': 5, + 'writer-2': 4, + 'writer-3': 6, + 'writer-4': 2 + }) + const strategy = new LeastConnectedLoadBalancingStrategy(pool) + + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + }) +}) class DummyPool extends Pool { - - constructor(activeConnections) { - super(() => 42); - this._activeConnections = activeConnections; + constructor (activeConnections) { + super(() => 42) + this._activeConnections = activeConnections } - activeResourceCount(key) { - return this._activeConnections[key]; + activeResourceCount (key) { + return this._activeConnections[key] } } diff --git a/test/internal/logger.test.js b/test/internal/logger.test.js index 17a5b392b..8e7fba124 100644 --- a/test/internal/logger.test.js +++ b/test/internal/logger.test.js @@ -17,168 +17,189 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../../test/internal/shared-neo4j'; -import Logger from '../../src/v1/internal/logger'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../../test/internal/shared-neo4j' +import Logger from '../../src/v1/internal/logger' describe('Logger', () => { - - let originalConsoleLog; + let originalConsoleLog beforeEach(() => { - originalConsoleLog = console.log; - }); + originalConsoleLog = console.log + }) afterEach(() => { - console.log = originalConsoleLog; - }); + console.log = originalConsoleLog + }) it('should create no-op logger when not configured', () => { - const log = Logger.create({logging: null}); + const log = Logger.create({ logging: null }) - log.error('Error! This should be a no-op'); - log.warn('Warn! This should be a no-op'); - log.info('Info! This should be a no-op'); - log.debug('Debug! This should be a no-op'); + log.error('Error! This should be a no-op') + log.warn('Warn! This should be a no-op') + log.info('Info! This should be a no-op') + log.debug('Debug! This should be a no-op') - expect(log.isErrorEnabled()).toBeFalsy(); - expect(log.isWarnEnabled()).toBeFalsy(); - expect(log.isInfoEnabled()).toBeFalsy(); - expect(log.isDebugEnabled()).toBeFalsy(); - }); + expect(log.isErrorEnabled()).toBeFalsy() + expect(log.isWarnEnabled()).toBeFalsy() + expect(log.isInfoEnabled()).toBeFalsy() + expect(log.isDebugEnabled()).toBeFalsy() + }) it('should create Logger when configured', () => { - const logged = []; - const log = memorizingLogger(logged); + const logged = [] + const log = memorizingLogger(logged) - log.error('Error! One'); - log.warn('Warn! Two'); - log.info('Info! Three'); - log.debug('Debug! Four'); + log.error('Error! One') + log.warn('Warn! Two') + log.info('Info! Three') + log.debug('Debug! Four') - expect(log.isErrorEnabled()).toBeTruthy(); - expect(log.isWarnEnabled()).toBeTruthy(); - expect(log.isInfoEnabled()).toBeTruthy(); - expect(log.isDebugEnabled()).toBeTruthy(); + expect(log.isErrorEnabled()).toBeTruthy() + expect(log.isWarnEnabled()).toBeTruthy() + expect(log.isInfoEnabled()).toBeTruthy() + expect(log.isDebugEnabled()).toBeTruthy() expect(logged).toEqual([ - {level: 'error', message: 'Error! One'}, - {level: 'warn', message: 'Warn! Two'}, - {level: 'info', message: 'Info! Three'}, - {level: 'debug', message: 'Debug! Four'} - ]); - }); + { level: 'error', message: 'Error! One' }, + { level: 'warn', message: 'Warn! Two' }, + { level: 'info', message: 'Info! Three' }, + { level: 'debug', message: 'Debug! Four' } + ]) + }) it('should log according to the configured log level', () => { - const logged = []; - const log = memorizingLogger(logged, 'warn'); + const logged = [] + const log = memorizingLogger(logged, 'warn') - log.error('Error! One'); - log.warn('Warn! Two'); - log.info('Info! Three'); - log.debug('Debug! Four'); + log.error('Error! One') + log.warn('Warn! Two') + log.info('Info! Three') + log.debug('Debug! Four') expect(logged).toEqual([ - {level: 'error', message: 'Error! One'}, - {level: 'warn', message: 'Warn! Two'} - ]); - }); + { level: 'error', message: 'Error! One' }, + { level: 'warn', message: 'Warn! Two' } + ]) + }) it('should log when logger configured in the driver', done => { - const logged = []; - const config = memorizingLoggerConfig(logged); - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, config); - - const session = driver.session(); - session.run('RETURN 42') + const logged = [] + const config = memorizingLoggerConfig(logged) + const driver = neo4j.driver( + 'bolt://localhost', + sharedNeo4j.authToken, + config + ) + + const session = driver.session() + session + .run('RETURN 42') .then(() => { - expect(logged.length).toBeGreaterThan(0); + expect(logged.length).toBeGreaterThan(0) - const seenLevels = logged.map(log => log.level); - const seenMessages = logged.map(log => log.message); + const seenLevels = logged.map(log => log.level) + const seenMessages = logged.map(log => log.message) // at least info and debug should've been used - expect(seenLevels).toContain('info'); - expect(seenLevels).toContain('debug'); + expect(seenLevels).toContain('info') + expect(seenLevels).toContain('debug') // the executed statement should've been logged - const statementLogged = seenMessages.find(message => message.indexOf('RETURN 42') !== -1); - expect(statementLogged).toBeTruthy(); + const statementLogged = seenMessages.find( + message => message.indexOf('RETURN 42') !== -1 + ) + expect(statementLogged).toBeTruthy() }) .catch(error => { - done.fail(error); + done.fail(error) }) .then(() => { - driver.close(); - done(); - }); - }); + driver.close() + done() + }) + }) it('should log debug to console when configured in the driver', done => { - const logged = []; - console.log = message => logged.push(message); - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {logging: neo4j.logging.console('debug')}); - - const session = driver.session(); - session.run('RETURN 123456789') + const logged = [] + console.log = message => logged.push(message) + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + logging: neo4j.logging.console('debug') + }) + + const session = driver.session() + session + .run('RETURN 123456789') .then(() => { - expect(logged.length).toBeGreaterThan(0); + expect(logged.length).toBeGreaterThan(0) // the executed statement should've been logged - const statementLogged = logged.find(log => log.indexOf('DEBUG') !== -1 && log.indexOf('RETURN 123456789') !== -1); - expect(statementLogged).toBeTruthy(); + const statementLogged = logged.find( + log => + log.indexOf('DEBUG') !== -1 && + log.indexOf('RETURN 123456789') !== -1 + ) + expect(statementLogged).toBeTruthy() // driver creation should've been logged because it is on info level - const driverCreationLogged = logged.find(log => log.indexOf('driver') !== -1 && log.indexOf('created') !== -1); - expect(driverCreationLogged).toBeTruthy(); + const driverCreationLogged = logged.find( + log => log.indexOf('driver') !== -1 && log.indexOf('created') !== -1 + ) + expect(driverCreationLogged).toBeTruthy() }) .catch(error => { - done.fail(error); + done.fail(error) }) .then(() => { - driver.close(); - done(); - }); - }); + driver.close() + done() + }) + }) it('should log info to console when configured in the driver', done => { - const logged = []; - console.log = message => logged.push(message); - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {logging: neo4j.logging.console()}); // info is the default level - - const session = driver.session(); - session.run('RETURN 123456789') + const logged = [] + console.log = message => logged.push(message) + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + logging: neo4j.logging.console() + }) // info is the default level + + const session = driver.session() + session + .run('RETURN 123456789') .then(() => { - expect(logged.length).toBeGreaterThan(0); + expect(logged.length).toBeGreaterThan(0) // the executed statement should not be logged because it is in debug level - const statementLogged = logged.find(log => log.indexOf('RETURN 123456789') !== -1); - expect(statementLogged).toBeFalsy(); + const statementLogged = logged.find( + log => log.indexOf('RETURN 123456789') !== -1 + ) + expect(statementLogged).toBeFalsy() // driver creation should've been logged because it is on info level - const driverCreationLogged = logged.find(log => log.indexOf('driver') !== -1 && log.indexOf('created') !== -1); - expect(driverCreationLogged).toBeTruthy(); + const driverCreationLogged = logged.find( + log => log.indexOf('driver') !== -1 && log.indexOf('created') !== -1 + ) + expect(driverCreationLogged).toBeTruthy() }) .catch(error => { - done.fail(error); + done.fail(error) }) .then(() => { - driver.close(); - done(); - }); - }); - -}); + driver.close() + done() + }) + }) +}) -function memorizingLogger(logged, level = 'debug') { - return Logger.create(memorizingLoggerConfig(logged, level)); +function memorizingLogger (logged, level = 'debug') { + return Logger.create(memorizingLoggerConfig(logged, level)) } -function memorizingLoggerConfig(logged, level = 'debug') { +function memorizingLoggerConfig (logged, level = 'debug') { return { logging: { level: level, - logger: (level, message) => logged.push({level, message}) + logger: (level, message) => logged.push({ level, message }) } - }; + } } diff --git a/test/internal/node/direct.driver.boltkit.test.js b/test/internal/node/direct.driver.boltkit.test.js index 30b45a56d..c1ea11d3a 100644 --- a/test/internal/node/direct.driver.boltkit.test.js +++ b/test/internal/node/direct.driver.boltkit.test.js @@ -17,401 +17,469 @@ * limitations under the License. */ -import neo4j from '../../../src/v1'; -import {READ, WRITE} from '../../../src/v1/driver'; -import boltStub from '../bolt-stub'; -import { SERVICE_UNAVAILABLE } from '../../../src/v1/error'; +import neo4j from '../../../src/v1' +import { READ, WRITE } from '../../../src/v1/driver' +import boltStub from '../bolt-stub' +import { SERVICE_UNAVAILABLE } from '../../../src/v1/error' describe('direct driver with stub server', () => { - - let originalTimeout; + let originalTimeout beforeAll(() => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; - }); + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000 + }) afterAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + }) it('should run query', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const server = boltStub.start('./test/resources/boltstub/return_x.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/return_x.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') // When - const session = driver.session(); + const session = driver.session() // Then - session.run('RETURN {x}', {'x': 1}).then(res => { - expect(res.records[0].get('x').toInt()).toEqual(1); - session.close(); - driver.close(); + session.run('RETURN {x}', { x: 1 }).then(res => { + expect(res.records[0].get('x').toInt()).toEqual(1) + session.close() + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should send and receive bookmark for read transaction', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/read_tx_with_bookmarks.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/read_tx_with_bookmarks.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(READ, 'neo4j:bookmark:v1:tx42'); - const tx = session.beginTransaction(); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session(READ, 'neo4j:bookmark:v1:tx42') + const tx = session.beginTransaction() tx.run('MATCH (n) RETURN n.name AS name').then(result => { - const records = result.records; - expect(records.length).toEqual(2); - expect(records[0].get('name')).toEqual('Bob'); - expect(records[1].get('name')).toEqual('Alice'); + const records = result.records + expect(records.length).toEqual(2) + expect(records[0].get('name')).toEqual('Bob') + expect(records[1].get('name')).toEqual('Alice') tx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') session.close(() => { - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should send and receive bookmark for write transaction', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/write_tx_with_bookmarks.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/write_tx_with_bookmarks.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42'); - const tx = session.beginTransaction(); - tx.run('CREATE (n {name:\'Bob\'})').then(result => { - const records = result.records; - expect(records.length).toEqual(0); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42') + const tx = session.beginTransaction() + tx.run("CREATE (n {name:'Bob'})").then(result => { + const records = result.records + expect(records.length).toEqual(0) tx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') session.close(() => { - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should send and receive bookmark between write and read transactions', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/write_read_tx_with_bookmarks.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/write_read_tx_with_bookmarks.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42'); - const writeTx = session.beginTransaction(); - writeTx.run('CREATE (n {name:\'Bob\'})').then(result => { - const records = result.records; - expect(records.length).toEqual(0); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42') + const writeTx = session.beginTransaction() + writeTx.run("CREATE (n {name:'Bob'})").then(result => { + const records = result.records + expect(records.length).toEqual(0) writeTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - const readTx = session.beginTransaction(); + const readTx = session.beginTransaction() readTx.run('MATCH (n) RETURN n.name AS name').then(result => { - const records = result.records; - expect(records.length).toEqual(1); - expect(records[0].get('name')).toEqual('Bob'); + const records = result.records + expect(records.length).toEqual(1) + expect(records[0].get('name')).toEqual('Bob') readTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx424242'); + expect(session.lastBookmark()).toEqual( + 'neo4j:bookmark:v1:tx424242' + ) session.close(() => { - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should be possible to override bookmark', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/write_read_tx_with_bookmark_override.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/write_read_tx_with_bookmark_override.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42'); - const writeTx = session.beginTransaction(); - writeTx.run('CREATE (n {name:\'Bob\'})').then(result => { - const records = result.records; - expect(records.length).toEqual(0); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42') + const writeTx = session.beginTransaction() + writeTx.run("CREATE (n {name:'Bob'})").then(result => { + const records = result.records + expect(records.length).toEqual(0) writeTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - const readTx = session.beginTransaction('neo4j:bookmark:v1:tx99'); + const readTx = session.beginTransaction('neo4j:bookmark:v1:tx99') readTx.run('MATCH (n) RETURN n.name AS name').then(result => { - const records = result.records; - expect(records.length).toEqual(1); - expect(records[0].get('name')).toEqual('Bob'); + const records = result.records + expect(records.length).toEqual(1) + expect(records[0].get('name')).toEqual('Bob') readTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx424242'); + expect(session.lastBookmark()).toEqual( + 'neo4j:bookmark:v1:tx424242' + ) session.close(() => { - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should not be possible to override bookmark with null', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/write_read_tx_with_bookmarks.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/write_read_tx_with_bookmarks.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42'); - const writeTx = session.beginTransaction(); - writeTx.run('CREATE (n {name:\'Bob\'})').then(result => { - const records = result.records; - expect(records.length).toEqual(0); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session(WRITE, 'neo4j:bookmark:v1:tx42') + const writeTx = session.beginTransaction() + writeTx.run("CREATE (n {name:'Bob'})").then(result => { + const records = result.records + expect(records.length).toEqual(0) writeTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - const readTx = session.beginTransaction(null); + const readTx = session.beginTransaction(null) readTx.run('MATCH (n) RETURN n.name AS name').then(result => { - const records = result.records; - expect(records.length).toEqual(1); - expect(records[0].get('name')).toEqual('Bob'); + const records = result.records + expect(records.length).toEqual(1) + expect(records[0].get('name')).toEqual('Bob') readTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx424242'); + expect(session.lastBookmark()).toEqual( + 'neo4j:bookmark:v1:tx424242' + ) session.close(() => { - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should throw service unavailable when server dies', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session() session.run('MATCH (n) RETURN n.name').catch(error => { - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should close connection when RESET fails', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/reset_error.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/reset_error.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(); - - session.run('RETURN 42 AS answer').then(result => { - const records = result.records; - expect(records.length).toEqual(1); - expect(records[0].get(0).toNumber()).toEqual(42); - session.close(() => { - - expect(driver._pool._pools['127.0.0.1:9001'].length).toEqual(0); - driver.close(); - server.exit(code => { - expect(code).toEqual(0); - done(); - }); - - }); - }).catch(error => done.fail(error)); - }); - }); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session() + + session + .run('RETURN 42 AS answer') + .then(result => { + const records = result.records + expect(records.length).toEqual(1) + expect(records[0].get(0).toNumber()).toEqual(42) + session.close(() => { + expect(driver._pool._pools['127.0.0.1:9001'].length).toEqual(0) + driver.close() + server.exit(code => { + expect(code).toEqual(0) + done() + }) + }) + }) + .catch(error => done.fail(error)) + }) + }) it('should send RESET on error', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/query_with_error.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/query_with_error.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(); - - session.run('RETURN 10 / 0').then(result => { - done.fail('Should fail but received a result: ' + JSON.stringify(result)); - }).catch(error => { - expect(error.code).toEqual('Neo.ClientError.Statement.ArithmeticError'); - expect(error.message).toEqual('/ by zero'); - - session.close(() => { - driver.close(); - server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session() + + session + .run('RETURN 10 / 0') + .then(result => { + done.fail( + 'Should fail but received a result: ' + JSON.stringify(result) + ) + }) + .catch(error => { + expect(error.code).toEqual( + 'Neo.ClientError.Statement.ArithmeticError' + ) + expect(error.message).toEqual('/ by zero') + + session.close(() => { + driver.close() + server.exit(code => { + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) it('should include database connection id in logs', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/hello_run_exit.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/hello_run_exit.script', + 9001 + ) boltStub.run(() => { - const messages = []; + const messages = [] const logging = { level: 'debug', logger: (level, message) => messages.push(message) - }; - - const driver = boltStub.newDriver('bolt://127.0.0.1:9001', {logging: logging}); - const session = driver.session(); - - session.run('MATCH (n) RETURN n.name').then(result => { - const names = result.records.map(record => record.get(0)); - expect(names).toEqual(['Foo', 'Bar']); - session.close(() => { - driver.close(); - server.exit(code => { - expect(code).toEqual(0); - - // logged messages should contain connection_id supplied by the database - const containsDbConnectionIdMessage = messages.find(message => message.match(/Connection \[[0-9]+]\[bolt-123456789]/)); - if (!containsDbConnectionIdMessage) { - console.log(messages); - } - expect(containsDbConnectionIdMessage).toBeTruthy(); + } - done(); - }); - }); - }).catch(error => done.fail(error)); - }); - }); + const driver = boltStub.newDriver('bolt://127.0.0.1:9001', { + logging: logging + }) + const session = driver.session() + + session + .run('MATCH (n) RETURN n.name') + .then(result => { + const names = result.records.map(record => record.get(0)) + expect(names).toEqual(['Foo', 'Bar']) + session.close(() => { + driver.close() + server.exit(code => { + expect(code).toEqual(0) + + // logged messages should contain connection_id supplied by the database + const containsDbConnectionIdMessage = messages.find(message => + message.match(/Connection \[[0-9]+]\[bolt-123456789]/) + ) + if (!containsDbConnectionIdMessage) { + console.log(messages) + } + expect(containsDbConnectionIdMessage).toBeTruthy() + + done() + }) + }) + }) + .catch(error => done.fail(error)) + }) + }) describe('should fail if commit fails due to broken connection', () => { it('v1', done => { - verifyFailureOnConnectionFailureWhenExplicitTransactionIsCommitted('v1', done); - }); + verifyFailureOnConnectionFailureWhenExplicitTransactionIsCommitted( + 'v1', + done + ) + }) it('v3', done => { - verifyFailureOnConnectionFailureWhenExplicitTransactionIsCommitted('v3', done); - }); - }); - - function verifyFailureOnConnectionFailureWhenExplicitTransactionIsCommitted(version, done) { + verifyFailureOnConnectionFailureWhenExplicitTransactionIsCommitted( + 'v3', + done + ) + }) + }) + + function verifyFailureOnConnectionFailureWhenExplicitTransactionIsCommitted ( + version, + done + ) { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start(`./test/resources/boltstub/connection_error_on_commit_${version}.script`, 9001); + const server = boltStub.start( + `./test/resources/boltstub/connection_error_on_commit_${version}.script`, + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt://127.0.0.1:9001'); - const session = driver.session(); - - const writeTx = session.beginTransaction(); - - writeTx.run('CREATE (n {name: \'Bob\'})').then(() => - writeTx.commit().then(result => fail('expected an error'), (error) => { - expect(error.code).toBe(SERVICE_UNAVAILABLE); - }) - ).finally(() => + const driver = boltStub.newDriver('bolt://127.0.0.1:9001') + const session = driver.session() + + const writeTx = session.beginTransaction() + + writeTx + .run("CREATE (n {name: 'Bob'})") + .then(() => + writeTx.commit().then( + result => fail('expected an error'), + error => { + expect(error.code).toBe(SERVICE_UNAVAILABLE) + } + ) + ) + .finally(() => session.close(() => { - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - })).catch(error => done.fail(error)); - } - ); + expect(code).toEqual(0) + done() + }) + }) + ) + .catch(error => done.fail(error)) + }) } -}); +}) diff --git a/test/internal/node/node-host-name-resolver.test.js b/test/internal/node/node-host-name-resolver.test.js index 94c26f9f3..2fc1ed893 100644 --- a/test/internal/node/node-host-name-resolver.test.js +++ b/test/internal/node/node-host-name-resolver.test.js @@ -17,96 +17,94 @@ * limitations under the License. */ -import NodeHostNameResolver from '../../../src/v1/internal/node/node-host-name-resolver'; -import urlUtil from '../../../src/v1/internal/url-util'; -import ServerAddress from '../../../src/v1/internal/server-address'; +import NodeHostNameResolver from '../../../src/v1/internal/node/node-host-name-resolver' +import ServerAddress from '../../../src/v1/internal/server-address' describe('NodeHostNameResolver', () => { - - let originalTimeout; + let originalTimeout beforeEach(() => { // it sometimes takes couple seconds to perform dns lookup, increase the async test timeout - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; - }); + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000 + }) afterEach(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + }) it('should resolve address', done => { - const seedRouter = ServerAddress.fromUrl('neo4j.com'); - const resolver = new NodeHostNameResolver(); + const seedRouter = ServerAddress.fromUrl('neo4j.com') + const resolver = new NodeHostNameResolver() resolver.resolve(seedRouter).then(addresses => { - expect(addresses.length).toBeGreaterThan(0); + expect(addresses.length).toBeGreaterThan(0) addresses.forEach(address => { - expectToBeDefined(address); - expect(address.host()).toEqual('neo4j.com'); - expect(address.resolvedHost()).not.toEqual('neo4j.com'); - expect(address.port()).toEqual(7687); // default port should be appended - }); + expectToBeDefined(address) + expect(address.host()).toEqual('neo4j.com') + expect(address.resolvedHost()).not.toEqual('neo4j.com') + expect(address.port()).toEqual(7687) // default port should be appended + }) - done(); - }); - }); + done() + }) + }) it('should resolve address with port', done => { - const seedRouter = ServerAddress.fromUrl('neo4j.com:7474'); - const resolver = new NodeHostNameResolver(); + const seedRouter = ServerAddress.fromUrl('neo4j.com:7474') + const resolver = new NodeHostNameResolver() resolver.resolve(seedRouter).then(addresses => { - expect(addresses.length).toBeGreaterThan(0); + expect(addresses.length).toBeGreaterThan(0) addresses.forEach(address => { - expectToBeDefined(address); - expect(address.host()).toEqual('neo4j.com'); - expect(address.resolvedHost()).not.toEqual('neo4j.com'); - expect(address.port()).toEqual(7474); // default port should be appended - }); + expectToBeDefined(address) + expect(address.host()).toEqual('neo4j.com') + expect(address.resolvedHost()).not.toEqual('neo4j.com') + expect(address.port()).toEqual(7474) // default port should be appended + }) - done(); - }); - }); + done() + }) + }) it('should resolve IPv4 address to itself', done => { - const addressToResolve = ServerAddress.fromUrl('127.0.0.1'); - const expectedResolvedAddress = '127.0.0.1:7687'; // includes default port - testIpAddressResolution(addressToResolve, expectedResolvedAddress, done); - }); + const addressToResolve = ServerAddress.fromUrl('127.0.0.1') + const expectedResolvedAddress = '127.0.0.1:7687' // includes default port + testIpAddressResolution(addressToResolve, expectedResolvedAddress, done) + }) it('should resolve IPv4 address with port to itself', done => { - const address = ServerAddress.fromUrl('127.0.0.1:7474'); - const expectedResolvedAddress = '127.0.0.1:7474'; // includes default port - testIpAddressResolution(address, expectedResolvedAddress, done); - }); + const address = ServerAddress.fromUrl('127.0.0.1:7474') + const expectedResolvedAddress = '127.0.0.1:7474' // includes default port + testIpAddressResolution(address, expectedResolvedAddress, done) + }) it('should resolve IPv6 address to itself', done => { - const addressToResolve = ServerAddress.fromUrl('[2001:4860:4860::8888]'); - const expectedResolvedAddress = '[2001:4860:4860::8888]:7687'; // includes default port - testIpAddressResolution(addressToResolve, expectedResolvedAddress, done); - }); + const addressToResolve = ServerAddress.fromUrl('[2001:4860:4860::8888]') + const expectedResolvedAddress = '[2001:4860:4860::8888]:7687' // includes default port + testIpAddressResolution(addressToResolve, expectedResolvedAddress, done) + }) it('should resolve IPv6 address with port to itself', done => { - const address = ServerAddress.fromUrl('[2001:4860:4860::8888]:7474'); - const expectedResolvedAddress = '[2001:4860:4860::8888]:7474'; - testIpAddressResolution(address, expectedResolvedAddress, done); - }); -}); + const address = ServerAddress.fromUrl('[2001:4860:4860::8888]:7474') + const expectedResolvedAddress = '[2001:4860:4860::8888]:7474' + testIpAddressResolution(address, expectedResolvedAddress, done) + }) +}) -function testIpAddressResolution(address, expectedResolvedAddress, done) { - const resolver = new NodeHostNameResolver(); +function testIpAddressResolution (address, expectedResolvedAddress, done) { + const resolver = new NodeHostNameResolver() resolver.resolve(address).then(addresses => { - expect(addresses.length).toEqual(1); - expect(addresses[0].asHostPort()).toEqual(expectedResolvedAddress); - done(); - }); + expect(addresses.length).toEqual(1) + expect(addresses[0].asHostPort()).toEqual(expectedResolvedAddress) + done() + }) } -function expectToBeDefined(value) { - expect(value).toBeDefined(); - expect(value).not.toBeNull(); +function expectToBeDefined (value) { + expect(value).toBeDefined() + expect(value).not.toBeNull() } diff --git a/test/internal/node/package.test.js b/test/internal/node/package.test.js index 883e52cf1..1a8344781 100644 --- a/test/internal/node/package.test.js +++ b/test/internal/node/package.test.js @@ -17,43 +17,49 @@ * limitations under the License. */ -var path = require('path'); -var fs = require('fs'); -var webpack = require('webpack'); -var sharedNeo4j = require('../shared-neo4j').default; +var path = require('path') +var fs = require('fs') +var webpack = require('webpack') +var sharedNeo4j = require('../shared-neo4j').default describe('Package', function () { - - var driver; + var driver afterAll(function () { if (driver) { - driver.close(); + driver.close() } - }); + }) it('should work in NodeJS', function (done) { - var neo4j; + var neo4j try { - neo4j = require(sandboxPath('node_modules', 'neo4j-driver', 'lib')).v1; + neo4j = require(sandboxPath('node_modules', 'neo4j-driver', 'lib')).v1 } catch (e) { - done.fail('Could not load sandbox package', e); + done.fail('Could not load sandbox package', e) } - driver = neo4j.driver('bolt://localhost', neo4j.auth.basic(sharedNeo4j.username, sharedNeo4j.password)); - var session = driver.session(); - session.run('RETURN 1 AS answer').then(function (result) { - expect(result.records.length).toBe(1); - expect(result.records[0].get('answer').toNumber()).toBe(1); - session.close(); - done(); - }).catch(function (e) { - done.fail(e); - }); - }); + driver = neo4j.driver( + 'bolt://localhost', + neo4j.auth.basic(sharedNeo4j.username, sharedNeo4j.password) + ) + var session = driver.session() + session + .run('RETURN 1 AS answer') + .then(function (result) { + expect(result.records.length).toBe(1) + expect(result.records[0].get('answer').toNumber()).toBe(1) + session.close() + done() + }) + .catch(function (e) { + done.fail(e) + }) + }) it('should work with Webpack', function (done) { + /* eslint-disable no-irregular-whitespace */ // test project structure: // build/sandbox/ // ├── dist @@ -64,15 +70,15 @@ describe('Package', function () { // └── src // └── index.js - var projectDir = sandboxPath(); - var srcDir = path.join(projectDir, 'src'); - var distDir = path.join(projectDir, 'dist'); - var indexJsFile = path.join(srcDir, 'index.js'); + var projectDir = sandboxPath() + var srcDir = path.join(projectDir, 'src') + var distDir = path.join(projectDir, 'dist') + var indexJsFile = path.join(srcDir, 'index.js') // create src directory - fs.mkdirSync(srcDir); + fs.mkdirSync(srcDir) // create a single index.js that just requires the driver - fs.writeFileSync(indexJsFile, 'require("neo4j-driver");\n'); + fs.writeFileSync(indexJsFile, 'require("neo4j-driver");\n') // configuration for Webpack var webpackOptions = { @@ -81,28 +87,28 @@ describe('Package', function () { output: { path: distDir } - }; + } // function to invoke when Webpack compiler is done var webpackCallback = function (error, stats) { if (error) { - done.fail(error); + done.fail(error) } if (stats.hasErrors()) { - done.fail(stats.toString()); + done.fail(stats.toString()) } - done(); - }; + done() + } // execute Webpack - webpack(webpackOptions, webpackCallback); - }); -}); + webpack(webpackOptions, webpackCallback) + }) +}) -function sandboxPath() { - var parts = [__dirname, '..', '..', '..', 'build', 'sandbox']; +function sandboxPath () { + var parts = [__dirname, '..', '..', '..', 'build', 'sandbox'] for (var i = 0; i < arguments.length; i++) { - parts.push(arguments[i]); + parts.push(arguments[i]) } - return path.join.apply(null, parts); + return path.join.apply(null, parts) } diff --git a/test/internal/node/routing.driver.boltkit.test.js b/test/internal/node/routing.driver.boltkit.test.js index bd30958a5..b037d4b9a 100644 --- a/test/internal/node/routing.driver.boltkit.test.js +++ b/test/internal/node/routing.driver.boltkit.test.js @@ -17,31 +17,30 @@ * limitations under the License. */ -import neo4j from '../../../src/v1'; -import {READ, WRITE} from '../../../src/v1/driver'; -import boltStub from '../bolt-stub'; -import RoutingTable from '../../../src/v1/internal/routing-table'; -import {SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../../../src/v1/error'; -import lolex from 'lolex'; -import ServerAddress from '../../../src/v1/internal/server-address'; +import neo4j from '../../../src/v1' +import { READ, WRITE } from '../../../src/v1/driver' +import boltStub from '../bolt-stub' +import RoutingTable from '../../../src/v1/internal/routing-table' +import { SERVICE_UNAVAILABLE, SESSION_EXPIRED } from '../../../src/v1/error' +import lolex from 'lolex' +import ServerAddress from '../../../src/v1/internal/server-address' describe('routing driver with stub server', () => { - - let originalTimeout; - let clock; + let originalTimeout + let clock beforeAll(() => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; - }); + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000 + }) afterAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + }) it('should discover servers with bolt+routing scheme', done => { testDiscovery('bolt+routing', done) - }); + }) it('should discover servers with neo4j scheme', done => { testDiscovery('neo4j', done) @@ -49,922 +48,1153 @@ describe('routing driver with stub server', () => { it('should discover IPv6 servers', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/discover_ipv6_servers_and_read.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/discover_ipv6_servers_and_read.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); - const session = driver.session(READ); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') + const session = driver.session(READ) session.run('MATCH (n) RETURN n.name').then(() => { + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9001') + ).toBeTruthy() + assertHasReaders(driver, ['127.0.0.1:9001', '[::1]:9001']) + assertHasWriters(driver, [ + '[2001:db8:a0b:12f0::1]:9002', + '[3731:54:65fe:2::a7]:9003' + ]) + assertHasRouters(driver, [ + '[ff02::1]:9001', + '[684d:1111:222:3333:4444:5555:6:77]:9002', + '[::1]:9003' + ]) - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9001')).toBeTruthy(); - assertHasReaders(driver, ['127.0.0.1:9001', '[::1]:9001']); - assertHasWriters(driver, ['[2001:db8:a0b:12f0::1]:9002', '[3731:54:65fe:2::a7]:9003']); - assertHasRouters(driver, ['[ff02::1]:9001', '[684d:1111:222:3333:4444:5555:6:77]:9002', '[::1]:9003']); - - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should purge connections to stale servers after routing table refresh', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9042); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9042 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9042'); - const session = driver.session(neo4j.session.READ); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9042') + const session = driver.session(neo4j.session.READ) session.run('MATCH (n) RETURN n.name').then(() => { - session.close(); + session.close() - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9042')).toBeFalsy(); - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9005')).toBeTruthy(); + expect(hasAddressInConnectionPool(driver, '127.0.0.1:9042')).toBeFalsy() + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9005') + ).toBeTruthy() - driver.close(); + driver.close() router.exit(routerCode => { reader.exit(readerCode => { - expect(routerCode).toEqual(0); - expect(readerCode).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(routerCode).toEqual(0) + expect(readerCode).toEqual(0) + done() + }) + }) + }) + }) + }) it('should discover new servers', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const server = boltStub.start('./test/resources/boltstub/discover_new_servers.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/discover_new_servers.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(); - session.run("MATCH (n) RETURN n.name").then(() => { - + const session = driver.session() + session.run('MATCH (n) RETURN n.name').then(() => { // Then - assertHasRouters(driver, ["127.0.0.1:9004", "127.0.0.1:9002", "127.0.0.1:9003"]); - assertHasReaders(driver, ["127.0.0.1:9005", "127.0.0.1:9003"]); - assertHasWriters(driver, ["127.0.0.1:9001"]); + assertHasRouters(driver, [ + '127.0.0.1:9004', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) + assertHasReaders(driver, ['127.0.0.1:9005', '127.0.0.1:9003']) + assertHasWriters(driver, ['127.0.0.1:9001']) - driver.close(); + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should discover new servers using subscribe', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const server = boltStub.start('./test/resources/boltstub/discover_new_servers.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/discover_new_servers.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(); - session.run("MATCH (n) RETURN n.name").subscribe({ + const session = driver.session() + session.run('MATCH (n) RETURN n.name').subscribe({ onCompleted: () => { - // Then - assertHasRouters(driver, ["127.0.0.1:9004", "127.0.0.1:9002", "127.0.0.1:9003"]); - assertHasReaders(driver, ["127.0.0.1:9005", "127.0.0.1:9003"]); - assertHasWriters(driver, ["127.0.0.1:9001"]); - - driver.close(); + assertHasRouters(driver, [ + '127.0.0.1:9004', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) + assertHasReaders(driver, ['127.0.0.1:9005', '127.0.0.1:9003']) + assertHasWriters(driver, ['127.0.0.1:9001']) + + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); + expect(code).toEqual(0) + done() + }) } - }); - }); - }); + }) + }) + }) it('should handle empty response from server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const server = boltStub.start('./test/resources/boltstub/empty_get_servers_response.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/empty_get_servers_response.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.READ); - session.run("MATCH (n) RETURN n.name").catch(err => { - expect(err.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - - session.close(); - driver.close(); - server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }).catch(err => { - console.log(err) - }); - }); - }); + const session = driver.session(neo4j.READ) + session + .run('MATCH (n) RETURN n.name') + .catch(err => { + expect(err.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + + session.close() + driver.close() + server.exit(code => { + expect(code).toEqual(0) + done() + }) + }) + .catch(err => { + console.log(err) + }) + }) + }) it('should acquire read server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.run("MATCH (n) RETURN n.name").then(res => { - - session.close(); + const session = driver.session(neo4j.session.READ) + session.run('MATCH (n) RETURN n.name').then(res => { + session.close() - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9001')).toBeTruthy(); - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9005')).toBeTruthy(); + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9001') + ).toBeTruthy() + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9005') + ).toBeTruthy() // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - driver.close(); + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should pick first available route-server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/short_ttl.script', 9999); - const nextRouter = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9003); - const readServer1 = boltStub.start('./test/resources/boltstub/read_server.script', 9004); - const readServer2 = boltStub.start('./test/resources/boltstub/read_server.script', 9006); + const seedServer = boltStub.start( + './test/resources/boltstub/short_ttl.script', + 9999 + ) + const nextRouter = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9003 + ) + const readServer1 = boltStub.start( + './test/resources/boltstub/read_server.script', + 9004 + ) + const readServer2 = boltStub.start( + './test/resources/boltstub/read_server.script', + 9006 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9999'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9999') // When - const session1 = driver.session(neo4j.session.READ); - session1.run("MATCH (n) RETURN n.name").then(res => { + const session1 = driver.session(neo4j.session.READ) + session1.run('MATCH (n) RETURN n.name').then(res => { // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - session1.close(); + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + session1.close() - const session2 = driver.session(neo4j.session.READ); - session2.run("MATCH (n) RETURN n.name").then(res => { + const session2 = driver.session(neo4j.session.READ) + session2.run('MATCH (n) RETURN n.name').then(res => { // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - session2.close(); - driver.close(); + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + session2.close() + driver.close() seedServer.exit(code1 => { nextRouter.exit(code2 => { readServer1.exit(code3 => { readServer2.exit(code4 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should round-robin among read servers', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer1 = boltStub.start('./test/resources/boltstub/read_server.script', 9005); - const readServer2 = boltStub.start('./test/resources/boltstub/read_server.script', 9006); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer1 = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) + const readServer2 = boltStub.start( + './test/resources/boltstub/read_server.script', + 9006 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session1 = driver.session(neo4j.session.READ); - session1.run("MATCH (n) RETURN n.name").then(res => { + const session1 = driver.session(neo4j.session.READ) + session1.run('MATCH (n) RETURN n.name').then(res => { // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - session1.close(); - const session2 = driver.session(neo4j.session.READ); - session2.run("MATCH (n) RETURN n.name").then(res => { + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + session1.close() + const session2 = driver.session(neo4j.session.READ) + session2.run('MATCH (n) RETURN n.name').then(res => { // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - session2.close(); + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + session2.close() - driver.close(); + driver.close() seedServer.exit(code1 => { readServer1.exit(code2 => { readServer2.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should handle missing read server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.run("MATCH (n) RETURN n.name").catch(err => { - expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED); - driver.close(); + const session = driver.session(neo4j.session.READ) + session.run('MATCH (n) RETURN n.name').catch(err => { + expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED) + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should acquire write server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const writeServer = boltStub.start('./test/resources/boltstub/write_server.script', 9007); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const writeServer = boltStub.start( + './test/resources/boltstub/write_server.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.WRITE); + const session = driver.session(neo4j.session.WRITE) session.run("CREATE (n {name:'Bob'})").then(() => { - // Then - driver.close(); + driver.close() seedServer.exit(code1 => { writeServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should round-robin among write servers', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer1 = boltStub.start('./test/resources/boltstub/write_server.script', 9007); - const readServer2 = boltStub.start('./test/resources/boltstub/write_server.script', 9008); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer1 = boltStub.start( + './test/resources/boltstub/write_server.script', + 9007 + ) + const readServer2 = boltStub.start( + './test/resources/boltstub/write_server.script', + 9008 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session1 = driver.session(neo4j.session.WRITE); + const session1 = driver.session(neo4j.session.WRITE) session1.run("CREATE (n {name:'Bob'})").then(() => { - const session2 = driver.session(neo4j.session.WRITE); + const session2 = driver.session(neo4j.session.WRITE) session2.run("CREATE (n {name:'Bob'})").then(() => { // Then - driver.close(); + driver.close() seedServer.exit(code1 => { readServer1.exit(code2 => { readServer2.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should handle missing write server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9007); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.WRITE); - session.run("MATCH (n) RETURN n.name").catch(err => { - expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED); - driver.close(); + const session = driver.session(neo4j.session.WRITE) + session.run('MATCH (n) RETURN n.name').catch(err => { + expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED) + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should remember endpoints', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.run("MATCH (n) RETURN n.name").then(() => { - + const session = driver.session(neo4j.session.READ) + session.run('MATCH (n) RETURN n.name').then(() => { // Then - assertHasRouters(driver, ['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003']); - assertHasReaders(driver, ['127.0.0.1:9005', '127.0.0.1:9006']); - assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']); - driver.close(); + assertHasRouters(driver, [ + '127.0.0.1:9001', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) + assertHasReaders(driver, ['127.0.0.1:9005', '127.0.0.1:9006']) + assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']) + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should forget endpoints on failure', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.run("MATCH (n) RETURN n.name").catch(() => { - session.close(); + const session = driver.session(neo4j.session.READ) + session.run('MATCH (n) RETURN n.name').catch(() => { + session.close() // Then - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9001')).toBeTruthy(); - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9005')).toBeFalsy(); - assertHasRouters(driver, ['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003']); - assertHasReaders(driver, ['127.0.0.1:9006']); - assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']); - driver.close(); + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9001') + ).toBeTruthy() + expect(hasAddressInConnectionPool(driver, '127.0.0.1:9005')).toBeFalsy() + assertHasRouters(driver, [ + '127.0.0.1:9001', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) + assertHasReaders(driver, ['127.0.0.1:9006']) + assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']) + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should forget endpoints on session acquisition failure', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.run("MATCH (n) RETURN n.name").catch(() => { - session.close(); + const session = driver.session(neo4j.session.READ) + session.run('MATCH (n) RETURN n.name').catch(() => { + session.close() // Then - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9001')).toBeTruthy(); - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9005')).toBeFalsy(); - assertHasRouters(driver, ['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003']); - assertHasReaders(driver, ['127.0.0.1:9006']); - assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']); - driver.close(); + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9001') + ).toBeTruthy() + expect(hasAddressInConnectionPool(driver, '127.0.0.1:9005')).toBeFalsy() + assertHasRouters(driver, [ + '127.0.0.1:9001', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) + assertHasReaders(driver, ['127.0.0.1:9006']) + assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']) + driver.close() seedServer.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should rediscover if necessary', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/rediscover.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/rediscover.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session1 = driver.session(neo4j.session.READ); - session1.run("MATCH (n) RETURN n.name").catch(() => { - const session2 = driver.session(neo4j.session.READ); + const session1 = driver.session(neo4j.session.READ) + session1.run('MATCH (n) RETURN n.name').catch(() => { + const session2 = driver.session(neo4j.session.READ) session2.run('MATCH (n) RETURN n.name').then(() => { - driver.close(); + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should handle server not able to do routing', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const server = boltStub.start('./test/resources/boltstub/non_discovery.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/non_discovery.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(); - session.run("MATCH (n) RETURN n.name").catch(err => { - expect(err.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - expect(err.message).toContain('Could not perform discovery'); - assertHasRouters(driver, []); - session.close(); - driver.close(); + const session = driver.session() + session.run('MATCH (n) RETURN n.name').catch(err => { + expect(err.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + expect(err.message).toContain('Could not perform discovery') + assertHasRouters(driver, []) + session.close() + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should handle leader switch while writing', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/not_able_to_write.script', 9007); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/not_able_to_write.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(); - session.run("CREATE ()").catch(err => { - //the server at 9007 should have been removed - assertHasWriters(driver, ['127.0.0.1:9008']); - expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED); - session.close(); - driver.close(); + const session = driver.session() + session.run('CREATE ()').catch(err => { + // the server at 9007 should have been removed + assertHasWriters(driver, ['127.0.0.1:9008']) + expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED) + session.close() + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should handle leader switch while writing on transaction', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/not_able_to_write_in_transaction.script', 9007); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/not_able_to_write_in_transaction.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(); - const tx = session.beginTransaction(); - tx.run("CREATE ()"); + const session = driver.session() + const tx = session.beginTransaction() + tx.run('CREATE ()') tx.commit().catch(err => { - //the server at 9007 should have been removed - assertHasWriters(driver, ['127.0.0.1:9008']); - expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED); - session.close(); - driver.close(); + // the server at 9007 should have been removed + assertHasWriters(driver, ['127.0.0.1:9008']) + expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED) + session.close() + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) it('should fail if missing write server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/no_writers.script', 9001); + const seedServer = boltStub.start( + './test/resources/boltstub/no_writers.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.WRITE); - session.run("MATCH (n) RETURN n.name").catch(err => { - expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED); - driver.close(); + const session = driver.session(neo4j.session.WRITE) + session.run('MATCH (n) RETURN n.name').catch(err => { + expect(err.code).toEqual(neo4j.error.SESSION_EXPIRED) + driver.close() seedServer.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) it('should try next router when current router fails to return a routing table', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server1 = boltStub.start('./test/resources/boltstub/routing_table_with_zero_ttl.script', 9999); - const server2 = boltStub.start('./test/resources/boltstub/dead_routing_server.script', 9091); - const server3 = boltStub.start('./test/resources/boltstub/dead_routing_server.script', 9092); - const server4 = boltStub.start('./test/resources/boltstub/dead_routing_server.script', 9093); + const server1 = boltStub.start( + './test/resources/boltstub/routing_table_with_zero_ttl.script', + 9999 + ) + const server2 = boltStub.start( + './test/resources/boltstub/dead_routing_server.script', + 9091 + ) + const server3 = boltStub.start( + './test/resources/boltstub/dead_routing_server.script', + 9092 + ) + const server4 = boltStub.start( + './test/resources/boltstub/dead_routing_server.script', + 9093 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9999'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9999') - const session1 = driver.session(); + const session1 = driver.session() session1.run('MATCH (n) RETURN n').then(result1 => { - expect(result1.summary.server.address).toEqual('127.0.0.1:9999'); - session1.close(); - - assertHasRouters(driver, ['127.0.0.1:9091', '127.0.0.1:9092', '127.0.0.1:9093', '127.0.0.1:9999']); - const memorizingRoutingTable = setUpMemorizingRoutingTable(driver); - - const session2 = driver.session(); + expect(result1.summary.server.address).toEqual('127.0.0.1:9999') + session1.close() + + assertHasRouters(driver, [ + '127.0.0.1:9091', + '127.0.0.1:9092', + '127.0.0.1:9093', + '127.0.0.1:9999' + ]) + const memorizingRoutingTable = setUpMemorizingRoutingTable(driver) + + const session2 = driver.session() session2.run('MATCH (n) RETURN n').then(result2 => { - expect(result2.summary.server.address).toEqual('127.0.0.1:9999'); - session2.close(); + expect(result2.summary.server.address).toEqual('127.0.0.1:9999') + session2.close() // returned routers failed to respond and should have been forgotten - memorizingRoutingTable.assertForgotRouters(['127.0.0.1:9091', '127.0.0.1:9092', '127.0.0.1:9093']); - assertHasRouters(driver, ['127.0.0.1:9999']); - driver.close(); + memorizingRoutingTable.assertForgotRouters([ + '127.0.0.1:9091', + '127.0.0.1:9092', + '127.0.0.1:9093' + ]) + assertHasRouters(driver, ['127.0.0.1:9999']) + driver.close() server1.exit(code1 => { server2.exit(code2 => { server3.exit(code3 => { server4.exit(code4 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should re-use connections', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/single_write_server.script', 9002); - const writeServer = boltStub.start('./test/resources/boltstub/two_write_responses_server.script', 9001); + const seedServer = boltStub.start( + './test/resources/boltstub/single_write_server.script', + 9002 + ) + const writeServer = boltStub.start( + './test/resources/boltstub/two_write_responses_server.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9002'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9002') // When - const session1 = driver.session(neo4j.session.WRITE); + const session1 = driver.session(neo4j.session.WRITE) session1.run("CREATE (n {name:'Bob'})").then(() => { session1.close(() => { - const openConnectionsCount = numberOfOpenConnections(driver); - const session2 = driver.session(neo4j.session.WRITE); - session2.run("CREATE ()").then(() => { + const openConnectionsCount = numberOfOpenConnections(driver) + const session2 = driver.session(neo4j.session.WRITE) + session2.run('CREATE ()').then(() => { // driver should have same amount of open connections at this point; // no new connections should be created, existing connections should be reused - expect(numberOfOpenConnections(driver)).toEqual(openConnectionsCount); - driver.close(); + expect(numberOfOpenConnections(driver)).toEqual( + openConnectionsCount + ) + driver.close() // all connections should be closed when driver is closed - expect(numberOfOpenConnections(driver)).toEqual(0); + expect(numberOfOpenConnections(driver)).toEqual(0) seedServer.exit(code1 => { writeServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should expose server info in cluster', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const routingServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const writeServer = boltStub.start('./test/resources/boltstub/write_server_with_version.script', 9007); - const readServer = boltStub.start('./test/resources/boltstub/read_server_with_version.script', 9005); + const routingServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const writeServer = boltStub.start( + './test/resources/boltstub/write_server_with_version.script', + 9007 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server_with_version.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const readSession = driver.session(neo4j.session.READ); + const readSession = driver.session(neo4j.session.READ) readSession.run('MATCH (n) RETURN n.name').then(readResult => { - const writeSession = driver.session(neo4j.session.WRITE); + const writeSession = driver.session(neo4j.session.WRITE) writeSession.run("CREATE (n {name:'Bob'})").then(writeResult => { - const readServerInfo = readResult.summary.server; - const writeServerInfo = writeResult.summary.server; + const readServerInfo = readResult.summary.server + const writeServerInfo = writeResult.summary.server - readSession.close(); - writeSession.close(); - driver.close(); + readSession.close() + writeSession.close() + driver.close() routingServer.exit(routingServerExitCode => { writeServer.exit(writeServerExitCode => { readServer.exit(readServerExitCode => { + expect(readServerInfo.address).toBe('127.0.0.1:9005') + expect(readServerInfo.version).toBe('Neo4j/8.8.8') - expect(readServerInfo.address).toBe('127.0.0.1:9005'); - expect(readServerInfo.version).toBe('Neo4j/8.8.8'); - - expect(writeServerInfo.address).toBe('127.0.0.1:9007'); - expect(writeServerInfo.version).toBe('Neo4j/9.9.9'); + expect(writeServerInfo.address).toBe('127.0.0.1:9007') + expect(writeServerInfo.version).toBe('Neo4j/9.9.9') - expect(routingServerExitCode).toEqual(0); - expect(writeServerExitCode).toEqual(0); - expect(readServerExitCode).toEqual(0); + expect(routingServerExitCode).toEqual(0) + expect(writeServerExitCode).toEqual(0) + expect(readServerExitCode).toEqual(0) - done(); - }); - }); - }); + done() + }) + }) + }) }) - }); - }); - }); + }) + }) + }) it('should expose server info in cluster using observer', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const routingServer = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const writeServer = boltStub.start('./test/resources/boltstub/write_server_with_version.script', 9007); - const readServer = boltStub.start('./test/resources/boltstub/read_server_with_version.script', 9005); + const routingServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const writeServer = boltStub.start( + './test/resources/boltstub/write_server_with_version.script', + 9007 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server_with_version.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const readSession = driver.session(neo4j.session.READ); + const readSession = driver.session(neo4j.session.READ) readSession.run('MATCH (n) RETURN n.name').subscribe({ - onNext: () => { - }, - onError: () => { - }, + onNext: () => {}, + onError: () => {}, onCompleted: readSummary => { - const writeSession = driver.session(neo4j.session.WRITE); + const writeSession = driver.session(neo4j.session.WRITE) writeSession.run("CREATE (n {name:'Bob'})").subscribe({ - onNext: () => { - }, - onError: () => { - }, + onNext: () => {}, + onError: () => {}, onCompleted: writeSummary => { - readSession.close(); - writeSession.close(); - driver.close(); + readSession.close() + writeSession.close() + driver.close() routingServer.exit(routingServerExitCode => { writeServer.exit(writeServerExitCode => { readServer.exit(readServerExitCode => { + expect(readSummary.server.address).toBe('127.0.0.1:9005') + expect(readSummary.server.version).toBe('Neo4j/8.8.8') - expect(readSummary.server.address).toBe('127.0.0.1:9005'); - expect(readSummary.server.version).toBe('Neo4j/8.8.8'); + expect(writeSummary.server.address).toBe('127.0.0.1:9007') + expect(writeSummary.server.version).toBe('Neo4j/9.9.9') - expect(writeSummary.server.address).toBe('127.0.0.1:9007'); - expect(writeSummary.server.version).toBe('Neo4j/9.9.9'); + expect(routingServerExitCode).toEqual(0) + expect(writeServerExitCode).toEqual(0) + expect(readServerExitCode).toEqual(0) - expect(routingServerExitCode).toEqual(0); - expect(writeServerExitCode).toEqual(0); - expect(readServerExitCode).toEqual(0); - - done(); - }); - }); - }); + done() + }) + }) + }) } }) } - }); - }); - }); + }) + }) + }) it('should forget routers when fails to connect', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start('./test/resources/boltstub/routing_table_with_zero_ttl.script', 9999); + const server = boltStub.start( + './test/resources/boltstub/routing_table_with_zero_ttl.script', + 9999 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9999'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9999') - const session1 = driver.session(); + const session1 = driver.session() session1.run('MATCH (n) RETURN n').then(result1 => { - expect(result1.summary.server.address).toEqual('127.0.0.1:9999'); - session1.close(); - - assertHasRouters(driver, ['127.0.0.1:9091', '127.0.0.1:9092', '127.0.0.1:9093', '127.0.0.1:9999']); - const memorizingRoutingTable = setUpMemorizingRoutingTable(driver); - - const session2 = driver.session(); + expect(result1.summary.server.address).toEqual('127.0.0.1:9999') + session1.close() + + assertHasRouters(driver, [ + '127.0.0.1:9091', + '127.0.0.1:9092', + '127.0.0.1:9093', + '127.0.0.1:9999' + ]) + const memorizingRoutingTable = setUpMemorizingRoutingTable(driver) + + const session2 = driver.session() session2.run('MATCH (n) RETURN n').then(result2 => { - expect(result2.summary.server.address).toEqual('127.0.0.1:9999'); - session2.close(); + expect(result2.summary.server.address).toEqual('127.0.0.1:9999') + session2.close() - memorizingRoutingTable.assertForgotRouters(['127.0.0.1:9091', '127.0.0.1:9092', '127.0.0.1:9093']); - assertHasRouters(driver, ['127.0.0.1:9999']); - driver.close(); + memorizingRoutingTable.assertForgotRouters([ + '127.0.0.1:9091', + '127.0.0.1:9092', + '127.0.0.1:9093' + ]) + assertHasRouters(driver, ['127.0.0.1:9999']) + driver.close() server.exit(code1 => { - expect(code1).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + done() + }) + }) + }) + }) + }) it('should close connection used for routing table refreshing', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // server is both router and writer - const server = boltStub.start('./test/resources/boltstub/discover_new_servers.script', 9001); + const server = boltStub.start( + './test/resources/boltstub/discover_new_servers.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') - const acquiredConnections = []; - const releasedConnections = []; - setUpPoolToMemorizeAllAcquiredAndReleasedConnections(driver, acquiredConnections, releasedConnections); + const acquiredConnections = [] + const releasedConnections = [] + setUpPoolToMemorizeAllAcquiredAndReleasedConnections( + driver, + acquiredConnections, + releasedConnections + ) - const session = driver.session(); - session.run('MATCH (n) RETURN n.name').then(() => { - session.close(() => { - driver.close(); - server.exit(code => { - expect(code).toEqual(0); - - // two connections should have been acquired: one for rediscovery and one for the query - expect(acquiredConnections.length).toEqual(2); - // same two connections should have been released - expect(releasedConnections.length).toEqual(2); - - // verify that acquired connections are those that we released - for (let i = 0; i < acquiredConnections.length; i++) { - expect(acquiredConnections[i]).toBe(releasedConnections[i]); - } - done(); - }); - }); - }).catch(console.log); - }); - }); + const session = driver.session() + session + .run('MATCH (n) RETURN n.name') + .then(() => { + session.close(() => { + driver.close() + server.exit(code => { + expect(code).toEqual(0) + + // two connections should have been acquired: one for rediscovery and one for the query + expect(acquiredConnections.length).toEqual(2) + // same two connections should have been released + expect(releasedConnections.length).toEqual(2) + + // verify that acquired connections are those that we released + for (let i = 0; i < acquiredConnections.length; i++) { + expect(acquiredConnections[i]).toBe(releasedConnections[i]) + } + done() + }) + }) + }) + .catch(console.log) + }) + }) it('should throw error when no records', done => { - testForProtocolError('./test/resources/boltstub/empty_get_servers_response.script', done); - }); + testForProtocolError( + './test/resources/boltstub/empty_get_servers_response.script', + done + ) + }) it('should throw error when no TTL entry', done => { - testForProtocolError('./test/resources/boltstub/no_ttl_entry_get_servers.script', done); - }); + testForProtocolError( + './test/resources/boltstub/no_ttl_entry_get_servers.script', + done + ) + }) it('should throw error when no servers entry', done => { - testForProtocolError('./test/resources/boltstub/no_servers_entry_get_servers.script', done); - }); + testForProtocolError( + './test/resources/boltstub/no_servers_entry_get_servers.script', + done + ) + }) it('should throw error when multiple records', done => { - testForProtocolError('./test/resources/boltstub/unparsable_ttl_get_servers.script', done); - }); + testForProtocolError( + './test/resources/boltstub/unparsable_ttl_get_servers.script', + done + ) + }) it('should throw error on unparsable record', done => { - testForProtocolError('./test/resources/boltstub/unparsable_servers_get_servers.script', done); - }); + testForProtocolError( + './test/resources/boltstub/unparsable_servers_get_servers.script', + done + ) + }) it('should throw error when no routers', done => { - testForProtocolError('./test/resources/boltstub/no_routers_get_servers.script', done); - }); + testForProtocolError( + './test/resources/boltstub/no_routers_get_servers.script', + done + ) + }) it('should throw error when no readers', done => { - testForProtocolError('./test/resources/boltstub/no_readers_get_servers.script', done); - }); + testForProtocolError( + './test/resources/boltstub/no_readers_get_servers.script', + done + ) + }) it('should accept routing table with 1 router, 1 reader and 1 writer', done => { testRoutingTableAcceptance( @@ -973,8 +1203,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9092'], writers: ['127.0.0.1:9999'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 2 routers, 1 reader and 1 writer', done => { testRoutingTableAcceptance( @@ -983,8 +1215,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9092'], writers: ['127.0.0.1:9999'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 1 router, 2 readers and 1 writer', done => { testRoutingTableAcceptance( @@ -993,8 +1227,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9092', '127.0.0.1:9093'], writers: ['127.0.0.1:9999'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 2 routers, 2 readers and 1 writer', done => { testRoutingTableAcceptance( @@ -1003,8 +1239,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9093', '127.0.0.1:9094'], writers: ['127.0.0.1:9999'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 1 router, 1 reader and 2 writers', done => { testRoutingTableAcceptance( @@ -1013,8 +1251,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9092'], writers: ['127.0.0.1:9999', '127.0.0.1:9093'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 2 routers, 1 reader and 2 writers', done => { testRoutingTableAcceptance( @@ -1023,8 +1263,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9093'], writers: ['127.0.0.1:9999', '127.0.0.1:9094'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 1 router, 2 readers and 2 writers', done => { testRoutingTableAcceptance( @@ -1033,8 +1275,10 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9092', '127.0.0.1:9093'], writers: ['127.0.0.1:9999', '127.0.0.1:9094'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should accept routing table with 2 routers, 2 readers and 2 writers', done => { testRoutingTableAcceptance( @@ -1043,1127 +1287,1448 @@ describe('routing driver with stub server', () => { readers: ['127.0.0.1:9093', '127.0.0.1:9094'], writers: ['127.0.0.1:9999', '127.0.0.1:9095'] }, - 9999, done); - }); + 9999, + done + ) + }) it('should send and receive bookmark', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const writer = boltStub.start('./test/resources/boltstub/write_tx_with_bookmarks.script', 9007); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_tx_with_bookmarks.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') - const session = driver.session(); - const tx = session.beginTransaction('neo4j:bookmark:v1:tx42'); - tx.run('CREATE (n {name:\'Bob\'})').then(() => { + const session = driver.session() + const tx = session.beginTransaction('neo4j:bookmark:v1:tx42') + tx.run("CREATE (n {name:'Bob'})").then(() => { tx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - session.close(); - driver.close(); + session.close() + driver.close() router.exit(code1 => { writer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should send initial bookmark without access mode', done => { - testWriteSessionWithAccessModeAndBookmark(null, 'neo4j:bookmark:v1:tx42', done); - }); + testWriteSessionWithAccessModeAndBookmark( + null, + 'neo4j:bookmark:v1:tx42', + done + ) + }) it('should use write session mode and initial bookmark', done => { - testWriteSessionWithAccessModeAndBookmark(WRITE, 'neo4j:bookmark:v1:tx42', done); - }); + testWriteSessionWithAccessModeAndBookmark( + WRITE, + 'neo4j:bookmark:v1:tx42', + done + ) + }) it('should use read session mode and initial bookmark', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const writer = boltStub.start('./test/resources/boltstub/read_tx_with_bookmarks.script', 9005); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const writer = boltStub.start( + './test/resources/boltstub/read_tx_with_bookmarks.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') - const session = driver.session(READ, 'neo4j:bookmark:v1:tx42'); - const tx = session.beginTransaction(); + const session = driver.session(READ, 'neo4j:bookmark:v1:tx42') + const tx = session.beginTransaction() tx.run('MATCH (n) RETURN n.name AS name').then(result => { - const records = result.records; - expect(records.length).toEqual(2); - expect(records[0].get('name')).toEqual('Bob'); - expect(records[1].get('name')).toEqual('Alice'); + const records = result.records + expect(records.length).toEqual(2) + expect(records[0].get('name')).toEqual('Bob') + expect(records[1].get('name')).toEqual('Alice') tx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - session.close(); - driver.close(); + session.close() + driver.close() router.exit(code1 => { writer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should pass bookmark from transaction to transaction', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints_with_one_of_each.script', 9001); - const writer = boltStub.start('./test/resources/boltstub/write_read_tx_with_bookmarks.script', 9007); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints_with_one_of_each.script', + 9001 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_read_tx_with_bookmarks.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') - const session = driver.session(null, 'neo4j:bookmark:v1:tx42'); - const writeTx = session.beginTransaction(); - writeTx.run('CREATE (n {name:\'Bob\'})').then(() => { + const session = driver.session(null, 'neo4j:bookmark:v1:tx42') + const writeTx = session.beginTransaction() + writeTx.run("CREATE (n {name:'Bob'})").then(() => { writeTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - const readTx = session.beginTransaction(); + const readTx = session.beginTransaction() readTx.run('MATCH (n) RETURN n.name AS name').then(result => { - const records = result.records; - expect(records.length).toEqual(1); - expect(records[0].get('name')).toEqual('Bob'); + const records = result.records + expect(records.length).toEqual(1) + expect(records[0].get('name')).toEqual('Bob') readTx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx424242'); + expect(session.lastBookmark()).toEqual( + 'neo4j:bookmark:v1:tx424242' + ) - session.close(); - driver.close(); + session.close() + driver.close() router.exit(code1 => { writer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should retry read transaction until success', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const brokenReader = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9005); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9006); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const brokenReader = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9005 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9006 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') + const session = driver.session() - let invocations = 0; + let invocations = 0 const resultPromise = session.readTransaction(tx => { - invocations++; - return tx.run('MATCH (n) RETURN n.name'); - }); + invocations++ + return tx.run('MATCH (n) RETURN n.name') + }) resultPromise.then(result => { - expect(result.records.length).toEqual(3); - expect(invocations).toEqual(2); + expect(result.records.length).toEqual(3) + expect(invocations).toEqual(2) session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { brokenReader.exit(code2 => { reader.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should retry write transaction until success', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const brokenWriter = boltStub.start('./test/resources/boltstub/dead_write_server.script', 9007); - const writer = boltStub.start('./test/resources/boltstub/write_server.script', 9008); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const brokenWriter = boltStub.start( + './test/resources/boltstub/dead_write_server.script', + 9007 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_server.script', + 9008 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') + const session = driver.session() - let invocations = 0; + let invocations = 0 const resultPromise = session.writeTransaction(tx => { - invocations++; - return tx.run('CREATE (n {name:\'Bob\'})'); - }); + invocations++ + return tx.run("CREATE (n {name:'Bob'})") + }) resultPromise.then(result => { - expect(result.records.length).toEqual(0); - expect(invocations).toEqual(2); + expect(result.records.length).toEqual(0) + expect(invocations).toEqual(2) session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { brokenWriter.exit(code2 => { writer.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should retry read transaction until failure', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const brokenReader1 = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9005); - const brokenReader2 = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9006); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const brokenReader1 = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9005 + ) + const brokenReader2 = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9006 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') + const session = driver.session() - let invocations = 0; + let invocations = 0 const resultPromise = session.readTransaction(tx => { - invocations++; + invocations++ if (invocations === 2) { // make retries stop after two invocations - moveTime30SecondsForward(); + moveTime30SecondsForward() } - return tx.run('MATCH (n) RETURN n.name'); - }); + return tx.run('MATCH (n) RETURN n.name') + }) resultPromise.catch(error => { - removeTimeMocking(); // uninstall lolex mocking to make test complete, boltkit uses timers + removeTimeMocking() // uninstall lolex mocking to make test complete, boltkit uses timers - expect(error.code).toEqual(SESSION_EXPIRED); - expect(invocations).toEqual(2); + expect(error.code).toEqual(SESSION_EXPIRED) + expect(invocations).toEqual(2) session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { brokenReader1.exit(code2 => { brokenReader2.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should retry write transaction until failure', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const brokenWriter1 = boltStub.start('./test/resources/boltstub/dead_write_server.script', 9007); - const brokenWriter2 = boltStub.start('./test/resources/boltstub/dead_write_server.script', 9008); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const brokenWriter1 = boltStub.start( + './test/resources/boltstub/dead_write_server.script', + 9007 + ) + const brokenWriter2 = boltStub.start( + './test/resources/boltstub/dead_write_server.script', + 9008 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') + const session = driver.session() - let invocations = 0; + let invocations = 0 const resultPromise = session.writeTransaction(tx => { - invocations++; + invocations++ if (invocations === 2) { // make retries stop after two invocations - moveTime30SecondsForward(); + moveTime30SecondsForward() } - return tx.run('CREATE (n {name:\'Bob\'})'); - }); + return tx.run("CREATE (n {name:'Bob'})") + }) resultPromise.catch(error => { - removeTimeMocking(); // uninstall lolex mocking to make test complete, boltStub uses timers + removeTimeMocking() // uninstall lolex mocking to make test complete, boltStub uses timers - expect(error.code).toEqual(SESSION_EXPIRED); - expect(invocations).toEqual(2); + expect(error.code).toEqual(SESSION_EXPIRED) + expect(invocations).toEqual(2) session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { brokenWriter1.exit(code2 => { brokenWriter2.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) it('should retry read transaction and perform rediscovery until success', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router1 = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9010); - const brokenReader1 = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9005); - const brokenReader2 = boltStub.start('./test/resources/boltstub/dead_read_server.script', 9006); - const router2 = boltStub.start('./test/resources/boltstub/discover_servers.script', 9001); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9002); + const router1 = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9010 + ) + const brokenReader1 = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9005 + ) + const brokenReader2 = boltStub.start( + './test/resources/boltstub/dead_read_server.script', + 9006 + ) + const router2 = boltStub.start( + './test/resources/boltstub/discover_servers.script', + 9001 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9002 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') + const session = driver.session() - let invocations = 0; + let invocations = 0 const resultPromise = session.readTransaction(tx => { - invocations++; - return tx.run('MATCH (n) RETURN n.name'); - }); + invocations++ + return tx.run('MATCH (n) RETURN n.name') + }) resultPromise.then(result => { - expect(result.records.length).toEqual(3); - expect(invocations).toEqual(3); + expect(result.records.length).toEqual(3) + expect(invocations).toEqual(3) session.close(() => { - driver.close(); + driver.close() router1.exit(code1 => { brokenReader1.exit(code2 => { brokenReader2.exit(code3 => { router2.exit(code4 => { reader.exit(code5 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - expect(code5).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + expect(code5).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) + }) it('should retry write transaction and perform rediscovery until success', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router1 = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9010); - const brokenWriter1 = boltStub.start('./test/resources/boltstub/dead_write_server.script', 9007); - const brokenWriter2 = boltStub.start('./test/resources/boltstub/dead_write_server.script', 9008); - const router2 = boltStub.start('./test/resources/boltstub/discover_servers.script', 9002); - const writer = boltStub.start('./test/resources/boltstub/write_server.script', 9009); + const router1 = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9010 + ) + const brokenWriter1 = boltStub.start( + './test/resources/boltstub/dead_write_server.script', + 9007 + ) + const brokenWriter2 = boltStub.start( + './test/resources/boltstub/dead_write_server.script', + 9008 + ) + const router2 = boltStub.start( + './test/resources/boltstub/discover_servers.script', + 9002 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_server.script', + 9009 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') + const session = driver.session() - let invocations = 0; + let invocations = 0 const resultPromise = session.writeTransaction(tx => { - invocations++; - return tx.run('CREATE (n {name:\'Bob\'})'); - }); + invocations++ + return tx.run("CREATE (n {name:'Bob'})") + }) resultPromise.then(result => { - expect(result.records.length).toEqual(0); - expect(invocations).toEqual(3); + expect(result.records.length).toEqual(0) + expect(invocations).toEqual(3) session.close(() => { - driver.close(); + driver.close() router1.exit(code1 => { brokenWriter1.exit(code2 => { brokenWriter2.exit(code3 => { router2.exit(code4 => { writer.exit(code5 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - expect(code5).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + expect(code5).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) + }) it('should use seed router for rediscovery when all other routers are dead', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // use scripts that exit eagerly when they are executed to simulate failed servers - const router1 = boltStub.start('./test/resources/boltstub/acquire_endpoints_and_exit.script', 9010); - const tmpReader = boltStub.start('./test/resources/boltstub/read_server_and_exit.script', 9005); + const router1 = boltStub.start( + './test/resources/boltstub/acquire_endpoints_and_exit.script', + 9010 + ) + const tmpReader = boltStub.start( + './test/resources/boltstub/read_server_and_exit.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') // run a dummy query to force routing table initialization - const session = driver.session(READ); + const session = driver.session(READ) session.run('MATCH (n) RETURN n.name').then(result => { - expect(result.records.length).toEqual(3); + expect(result.records.length).toEqual(3) session.close(() => { // stop existing router and reader router1.exit(code1 => { tmpReader.exit(code2 => { // at this point previously used router and reader should be dead - expect(code1).toEqual(0); - expect(code2).toEqual(0); + expect(code1).toEqual(0) + expect(code2).toEqual(0) // start new router on the same port with different script that contains itself as reader - const router2 = boltStub.start('./test/resources/boltstub/rediscover_using_initial_router.script', 9010); + const router2 = boltStub.start( + './test/resources/boltstub/rediscover_using_initial_router.script', + 9010 + ) boltStub.run(() => { - session.readTransaction(tx => tx.run('MATCH (n) RETURN n.name AS name')).then(result => { - const records = result.records; - expect(records.length).toEqual(2); - expect(records[0].get('name')).toEqual('Bob'); - expect(records[1].get('name')).toEqual('Alice'); - - session.close(() => { - driver.close(); - router2.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); + session + .readTransaction(tx => + tx.run('MATCH (n) RETURN n.name AS name') + ) + .then(result => { + const records = result.records + expect(records.length).toEqual(2) + expect(records[0].get('name')).toEqual('Bob') + expect(records[1].get('name')).toEqual('Alice') + + session.close(() => { + driver.close() + router2.exit(code => { + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) it('should use resolved seed router addresses for rediscovery when all other routers are dead', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router1 = boltStub.start('./test/resources/boltstub/acquire_endpoints_and_exit.script', 9011); + const router1 = boltStub.start( + './test/resources/boltstub/acquire_endpoints_and_exit.script', + 9011 + ) // start new router on a different port to emulate host name resolution // this router uses different script that contains itself as reader - const router2 = boltStub.start('./test/resources/boltstub/rediscover_using_initial_router.script', 9009); + const router2 = boltStub.start( + './test/resources/boltstub/rediscover_using_initial_router.script', + 9009 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') // make seed address resolve to 3 different addresses (only last one has backing stub server): - setupFakeHostNameResolution(driver, '127.0.0.1:9010', ['127.0.0.1:9011', '127.0.0.1:9012', '127.0.0.1:9009']); - const session = driver.session(); + setupFakeHostNameResolution(driver, '127.0.0.1:9010', [ + '127.0.0.1:9011', + '127.0.0.1:9012', + '127.0.0.1:9009' + ]) + const session = driver.session() - session.readTransaction(tx => tx.run('MATCH (n) RETURN n.name AS name')).then(result => { - const records = result.records; - expect(records.length).toEqual(2); - expect(records[0].get('name')).toEqual('Bob'); - expect(records[1].get('name')).toEqual('Alice'); + session + .readTransaction(tx => tx.run('MATCH (n) RETURN n.name AS name')) + .then(result => { + const records = result.records + expect(records.length).toEqual(2) + expect(records[0].get('name')).toEqual('Bob') + expect(records[1].get('name')).toEqual('Alice') - session.close(() => { - driver.close(); - router1.exit(code1 => { - router2.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + session.close(() => { + driver.close() + router1.exit(code1 => { + router2.exit(code2 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should invoke procedure get routing table when server version permits', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/get_routing_table.script', 9001); + const router = boltStub.start( + './test/resources/boltstub/get_routing_table.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') + const session = driver.session() session.run('MATCH (n) RETURN n.name AS name').then(result => { - const names = result.records.map(record => record.get('name')); - expect(names).toEqual(['Alice', 'Bob', 'Eve']); + const names = result.records.map(record => record.get('name')) + expect(names).toEqual(['Alice', 'Bob', 'Eve']) session.close(() => { - driver.close(); + driver.close() router.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) it('should send routing context to server', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/get_routing_table_with_context.script', 9001); + const router = boltStub.start( + './test/resources/boltstub/get_routing_table_with_context.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001/?policy=my_policy®ion=china'); - const session = driver.session(); + const driver = boltStub.newDriver( + 'bolt+routing://127.0.0.1:9001/?policy=my_policy®ion=china' + ) + const session = driver.session() session.run('MATCH (n) RETURN n.name AS name').then(result => { - const names = result.records.map(record => record.get('name')); - expect(names).toEqual(['Alice', 'Bob']); + const names = result.records.map(record => record.get('name')) + expect(names).toEqual(['Alice', 'Bob']) session.close(() => { - driver.close(); + driver.close() router.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) it('should ignore routing context when server does not support it', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/rediscover_and_read_with_init.script', 9001); + const router = boltStub.start( + './test/resources/boltstub/rediscover_and_read_with_init.script', + 9001 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001/?policy=my_policy'); - const session = driver.session(); + const driver = boltStub.newDriver( + 'bolt+routing://127.0.0.1:9001/?policy=my_policy' + ) + const session = driver.session() session.run('MATCH (n) RETURN n.name').then(result => { - const names = result.records.map(record => record.get(0)); - expect(names).toEqual(['Bob', 'Tina']); + const names = result.records.map(record => record.get(0)) + expect(names).toEqual(['Bob', 'Tina']) session.close(() => { - driver.close(); + driver.close() router.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) it('should treat routing table with single router as valid', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/discover_one_router.script', 9010); - const reader1 = boltStub.start('./test/resources/boltstub/read_server.script', 9003); - const reader2 = boltStub.start('./test/resources/boltstub/read_server.script', 9004); + const router = boltStub.start( + './test/resources/boltstub/discover_one_router.script', + 9010 + ) + const reader1 = boltStub.start( + './test/resources/boltstub/read_server.script', + 9003 + ) + const reader2 = boltStub.start( + './test/resources/boltstub/read_server.script', + 9004 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); - const session = driver.session(READ); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') + const session = driver.session(READ) session.run('MATCH (n) RETURN n.name').then(result1 => { - expect(result1.records.length).toEqual(3); - expect(result1.summary.server.address).toEqual('127.0.0.1:9003'); + expect(result1.records.length).toEqual(3) + expect(result1.summary.server.address).toEqual('127.0.0.1:9003') session.run('MATCH (n) RETURN n.name').then(result2 => { - expect(result2.records.length).toEqual(3); - expect(result2.summary.server.address).toEqual('127.0.0.1:9004'); + expect(result2.records.length).toEqual(3) + expect(result2.summary.server.address).toEqual('127.0.0.1:9004') session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { - reader1.exit(code2 => { reader2.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should use routing table without writers for reads', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/discover_no_writers.script', 9010); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9002); + const router = boltStub.start( + './test/resources/boltstub/discover_no_writers.script', + 9010 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9002 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') - const session = driver.session(READ); + const session = driver.session(READ) session.run('MATCH (n) RETURN n.name').then(result => { session.close(() => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) - driver.close(); + driver.close() router.exit(code1 => { reader.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should serve reads but fail writes when no writers available', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router1 = boltStub.start('./test/resources/boltstub/discover_no_writers.script', 9010); - const router2 = boltStub.start('./test/resources/boltstub/discover_no_writers.script', 9004); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9003); + const router1 = boltStub.start( + './test/resources/boltstub/discover_no_writers.script', + 9010 + ) + const router2 = boltStub.start( + './test/resources/boltstub/discover_no_writers.script', + 9004 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9003 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') - const readSession = driver.session(); + const readSession = driver.session() - readSession.readTransaction(tx => tx.run('MATCH (n) RETURN n.name')).then(result => { - readSession.close(() => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); + readSession + .readTransaction(tx => tx.run('MATCH (n) RETURN n.name')) + .then(result => { + readSession.close(() => { + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) - const writeSession = driver.session(WRITE); - writeSession.run('CREATE (n {name:\'Bob\'})').catch(error => { - expect(error.code).toEqual(neo4j.error.SESSION_EXPIRED); + const writeSession = driver.session(WRITE) + writeSession.run("CREATE (n {name:'Bob'})").catch(error => { + expect(error.code).toEqual(neo4j.error.SESSION_EXPIRED) - driver.close(); + driver.close() - router1.exit(code1 => { - router2.exit(code2 => { - reader.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); + router1.exit(code1 => { + router2.exit(code2 => { + reader.exit(code3 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) it('should accept routing table without writers and then rediscover', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - // first router does not have itself in the resulting routing table so connection // towards it will be closed after rediscovery - const router1 = boltStub.start('./test/resources/boltstub/discover_no_writers.script', 9010); - let router2 = null; - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9003); - const writer = boltStub.start('./test/resources/boltstub/write_server.script', 9007); + const router1 = boltStub.start( + './test/resources/boltstub/discover_no_writers.script', + 9010 + ) + let router2 = null + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9003 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_server.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') - const readSession = driver.session(); + const readSession = driver.session() - readSession.readTransaction(tx => tx.run('MATCH (n) RETURN n.name')).then(result => { - readSession.close(() => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); - - // start another router which knows about writes, use same address as the initial router - router2 = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9010); - boltStub.run(() => { - const writeSession = driver.session(WRITE); - writeSession.run('CREATE (n {name:\'Bob\'})').then(result => { - writeSession.close(() => { - expect(result.records).toEqual([]); - - driver.close(); - - router1.exit(code1 => { - router2.exit(code2 => { - reader.exit(code3 => { - writer.exit(code4 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); + readSession + .readTransaction(tx => tx.run('MATCH (n) RETURN n.name')) + .then(result => { + readSession.close(() => { + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) + + // start another router which knows about writes, use same address as the initial router + router2 = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9010 + ) + boltStub.run(() => { + const writeSession = driver.session(WRITE) + writeSession.run("CREATE (n {name:'Bob'})").then(result => { + writeSession.close(() => { + expect(result.records).toEqual([]) + + driver.close() + + router1.exit(code1 => { + router2.exit(code2 => { + reader.exit(code3 => { + writer.exit(code4 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) it('should use resolved seed router for discovery after accepting a table without writers', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const seedRouter = boltStub.start('./test/resources/boltstub/no_writers.script', 9010); - const resolvedSeedRouter = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9020); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9005); - const writer = boltStub.start('./test/resources/boltstub/write_server.script', 9007); + const seedRouter = boltStub.start( + './test/resources/boltstub/no_writers.script', + 9010 + ) + const resolvedSeedRouter = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9020 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_server.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') - const readSession = driver.session(READ); + const readSession = driver.session(READ) readSession.run('MATCH (n) RETURN n.name').then(result => { readSession.close(() => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); - - setupFakeHostNameResolution(driver, '127.0.0.1:9010', ['127.0.0.1:9020']); - - const writeSession = driver.session(WRITE); - writeSession.run('CREATE (n {name:\'Bob\'})').then(result => { + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) + + setupFakeHostNameResolution(driver, '127.0.0.1:9010', [ + '127.0.0.1:9020' + ]) + + const writeSession = driver.session(WRITE) + writeSession.run("CREATE (n {name:'Bob'})").then(result => { writeSession.close(() => { - expect(result.records).toEqual([]); + expect(result.records).toEqual([]) - driver.close(); + driver.close() seedRouter.exit(code1 => { resolvedSeedRouter.exit(code2 => { reader.exit(code3 => { writer.exit(code4 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + done() + }) + }) + }) + }) + }) + }) + }) + }) + }) + }) it('should fail rediscovery on auth error', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/failed_auth.script', 9010); + const router = boltStub.start( + './test/resources/boltstub/failed_auth.script', + 9010 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') + const session = driver.session() session.run('RETURN 1').catch(error => { - expect(error.code).toEqual('Neo.ClientError.Security.Unauthorized'); - expect(error.message).toEqual('Some server auth error message'); + expect(error.code).toEqual('Neo.ClientError.Security.Unauthorized') + expect(error.message).toEqual('Some server auth error message') session.close(() => { - driver.close(); + driver.close() router.exit(code => { - expect(code).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code).toEqual(0) + done() + }) + }) + }) + }) + }) it('should send multiple bookmarks', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9010); - const writer = boltStub.start('./test/resources/boltstub/multiple_bookmarks.script', 9007); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9010 + ) + const writer = boltStub.start( + './test/resources/boltstub/multiple_bookmarks.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); - - const bookmarks = ['neo4j:bookmark:v1:tx5', 'neo4j:bookmark:v1:tx29', 'neo4j:bookmark:v1:tx94', - 'neo4j:bookmark:v1:tx56', 'neo4j:bookmark:v1:tx16', 'neo4j:bookmark:v1:tx68']; - const session = driver.session(WRITE, bookmarks); - const tx = session.beginTransaction(); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') + + const bookmarks = [ + 'neo4j:bookmark:v1:tx5', + 'neo4j:bookmark:v1:tx29', + 'neo4j:bookmark:v1:tx94', + 'neo4j:bookmark:v1:tx56', + 'neo4j:bookmark:v1:tx16', + 'neo4j:bookmark:v1:tx68' + ] + const session = driver.session(WRITE, bookmarks) + const tx = session.beginTransaction() tx.run(`CREATE (n {name:'Bob'})`).then(() => { tx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx95'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx95') - session.close(); - driver.close(); + session.close() + driver.close() router.exit(code1 => { writer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) + }) it('should forget writer on database unavailable error', done => { - testAddressPurgeOnDatabaseError(`CREATE (n {name:'Bob'})`, WRITE, done); - }); + testAddressPurgeOnDatabaseError(`CREATE (n {name:'Bob'})`, WRITE, done) + }) it('should forget reader on database unavailable error', done => { - testAddressPurgeOnDatabaseError(`RETURN 1`, READ, done); - }); + testAddressPurgeOnDatabaseError(`RETURN 1`, READ, done) + }) it('should use resolver function that returns array during first discovery', done => { - testResolverFunctionDuringFirstDiscovery(['127.0.0.1:9010'], done); - }); + testResolverFunctionDuringFirstDiscovery(['127.0.0.1:9010'], done) + }) it('should use resolver function that returns promise during first discovery', done => { - testResolverFunctionDuringFirstDiscovery(Promise.resolve(['127.0.0.1:9010']), done); - }); + testResolverFunctionDuringFirstDiscovery( + Promise.resolve(['127.0.0.1:9010']), + done + ) + }) it('should fail first discovery when configured resolver function throws', done => { const failureFunction = () => { - throw new Error('Broken resolver'); - }; - testResolverFunctionFailureDuringFirstDiscovery(failureFunction, null, 'Broken resolver', done); - }); + throw new Error('Broken resolver') + } + testResolverFunctionFailureDuringFirstDiscovery( + failureFunction, + null, + 'Broken resolver', + done + ) + }) it('should fail first discovery when configured resolver function returns no addresses', done => { const failureFunction = () => { - return []; - }; - testResolverFunctionFailureDuringFirstDiscovery(failureFunction, SERVICE_UNAVAILABLE, 'No routing servers available', done); - }); + return [] + } + testResolverFunctionFailureDuringFirstDiscovery( + failureFunction, + SERVICE_UNAVAILABLE, + 'No routing servers available', + done + ) + }) it('should fail first discovery when configured resolver function returns a string instead of array of addresses', done => { const failureFunction = () => { - return 'Hello'; - }; - testResolverFunctionFailureDuringFirstDiscovery(failureFunction, null, 'Configured resolver function should either return an array of addresses', done); - }); + return 'Hello' + } + testResolverFunctionFailureDuringFirstDiscovery( + failureFunction, + null, + 'Configured resolver function should either return an array of addresses', + done + ) + }) it('should use resolver function during rediscovery when existing routers fail', done => { if (!boltStub.supported) { - done(); - return; + done() + return } - const router1 = boltStub.start('./test/resources/boltstub/get_routing_table.script', 9001); - const router2 = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9042); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const router1 = boltStub.start( + './test/resources/boltstub/get_routing_table.script', + 9001 + ) + const router2 = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9042 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { const resolverFunction = address => { if (address === '127.0.0.1:9000') { - return ['127.0.0.1:9010', '127.0.0.1:9001', '127.0.0.1:9042']; + return ['127.0.0.1:9010', '127.0.0.1:9001', '127.0.0.1:9042'] } - throw new Error(`Unexpected address ${address}`); - }; + throw new Error(`Unexpected address ${address}`) + } - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9000', { resolver: resolverFunction }); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9000', { + resolver: resolverFunction + }) - const session = driver.session(READ); + const session = driver.session(READ) // run a query that should trigger discovery against 9001 and then read from it - session.run('MATCH (n) RETURN n.name AS name') + session + .run('MATCH (n) RETURN n.name AS name') .then(result => { - expect(result.records.map(record => record.get(0))).toEqual(['Alice', 'Bob', 'Eve']); + expect(result.records.map(record => record.get(0))).toEqual([ + 'Alice', + 'Bob', + 'Eve' + ]) // 9001 should now exit and read transaction should fail to read from all existing readers // it should then rediscover using addresses from resolver, only 9042 of them works and can respond with table containing reader 9005 - session.readTransaction(tx => tx.run('MATCH (n) RETURN n.name')) + session + .readTransaction(tx => tx.run('MATCH (n) RETURN n.name')) .then(result => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); - - assertHasRouters(driver, ['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003']); - assertHasReaders(driver, ['127.0.0.1:9005', '127.0.0.1:9006']); - assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']); + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) + + assertHasRouters(driver, [ + '127.0.0.1:9001', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) + assertHasReaders(driver, ['127.0.0.1:9005', '127.0.0.1:9006']) + assertHasWriters(driver, ['127.0.0.1:9007', '127.0.0.1:9008']) session.close(() => { - driver.close(); + driver.close() router1.exit(code1 => { router2.exit(code2 => { reader.exit(code3 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - done(); - }); - }); - }); - }); - }).catch(done.fail); - }).catch(done.fail); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + done() + }) + }) + }) + }) + }) + .catch(done.fail) + }) + .catch(done.fail) + }) + }) it('should rediscover using older getServers procedure when server is old', done => { - testDiscoveryAndReadQueryInAutoCommitTx('./test/resources/boltstub/acquire_endpoints_old_routing_procedure.script', {}, done); - }); + testDiscoveryAndReadQueryInAutoCommitTx( + './test/resources/boltstub/acquire_endpoints_old_routing_procedure.script', + {}, + done + ) + }) it('should connect to cluster when disableLosslessIntegers is on', done => { - testDiscoveryAndReadQueryInAutoCommitTx('./test/resources/boltstub/acquire_endpoints.script', {disableLosslessIntegers: true}, done); - }); + testDiscoveryAndReadQueryInAutoCommitTx( + './test/resources/boltstub/acquire_endpoints.script', + { disableLosslessIntegers: true }, + done + ) + }) it('should send read access mode on statement metadata', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/read_server_v3_read.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server_v3_read.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.run("MATCH (n) RETURN n.name").then(res => { - session.close(); + const session = driver.session(neo4j.session.READ) + session.run('MATCH (n) RETURN n.name').then(res => { + session.close() // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - driver.close(); + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + driver.close() seedServer.exit(code1 => { readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) }) it('should send read access mode on statement metadata with read transaction', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3.script', 9001); - const readServer = boltStub.start('./test/resources/boltstub/read_server_v3_read_tx.script', 9005); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3.script', + 9001 + ) + const readServer = boltStub.start( + './test/resources/boltstub/read_server_v3_read_tx.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.READ); - session.readTransaction(tx => tx.run("MATCH (n) RETURN n.name")).then(res => { - session.close(); + const session = driver.session(neo4j.session.READ) + session + .readTransaction(tx => tx.run('MATCH (n) RETURN n.name')) + .then(res => { + session.close() - // Then - expect(res.records[0].get('n.name')).toEqual('Bob'); - expect(res.records[1].get('n.name')).toEqual('Alice'); - expect(res.records[2].get('n.name')).toEqual('Tina'); - driver.close(); - seedServer.exit(code1 => { - readServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); + // Then + expect(res.records[0].get('n.name')).toEqual('Bob') + expect(res.records[1].get('n.name')).toEqual('Alice') + expect(res.records[2].get('n.name')).toEqual('Tina') + driver.close() + seedServer.exit(code1 => { + readServer.exit(code2 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) }) it('should not send write access mode on statement metadata', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3.script', 9001); - const writeServer = boltStub.start('./test/resources/boltstub/write_server_v3_write.script', 9007); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3.script', + 9001 + ) + const writeServer = boltStub.start( + './test/resources/boltstub/write_server_v3_write.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.WRITE); + const session = driver.session(neo4j.session.WRITE) session.run("CREATE (n {name:'Bob'})").then(res => { - session.close(); - driver.close(); + session.close() + driver.close() seedServer.exit(code1 => { writeServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) }) it('should not send write access mode on statement metadata with write transaction', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // Given - const seedServer = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3.script', 9001); - const writeServer = boltStub.start('./test/resources/boltstub/write_server_v3_write_tx.script', 9007); + const seedServer = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3.script', + 9001 + ) + const writeServer = boltStub.start( + './test/resources/boltstub/write_server_v3_write_tx.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') // When - const session = driver.session(neo4j.session.WRITE); - session.writeTransaction(tx => tx.run("CREATE (n {name:'Bob'})")).then(res => { - session.close(); - driver.close(); - seedServer.exit(code1 => { - writeServer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); + const session = driver.session(neo4j.session.WRITE) + session + .writeTransaction(tx => tx.run("CREATE (n {name:'Bob'})")) + .then(res => { + session.close() + driver.close() + seedServer.exit(code1 => { + writeServer.exit(code2 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) }) it('should revert to initial router if the only known router returns invalid routing table', done => { if (!boltStub.supported) { - done(); - return; + done() + return } // the first seed to get the routing table // the returned routing table includes a non-reachable read-server and points to only one router // which will return an invalid routing table - const router1 = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3_point_to_empty_router_and_exit.script', 9001); + const router1 = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3_point_to_empty_router_and_exit.script', + 9001 + ) // returns an empty routing table - const router2 = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3_empty.script', 9004); + const router2 = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3_empty.script', + 9004 + ) // returns a normal routing table - const router3 = boltStub.start('./test/resources/boltstub/acquire_endpoints_v3_three_servers_and_exit.script', 9003); + const router3 = boltStub.start( + './test/resources/boltstub/acquire_endpoints_v3_three_servers_and_exit.script', + 9003 + ) // ordinary read server - const reader = boltStub.start('./test/resources/boltstub/read_server_v3_read_tx.script', 9002); + const reader = boltStub.start( + './test/resources/boltstub/read_server_v3_read_tx.script', + 9002 + ) boltStub.run(() => { const driver = boltStub.newDriver('bolt+routing://my.virtual.host:8080', { resolver: address => ['127.0.0.1:9001', '127.0.0.1:9003'] - }); - - const session = driver.session(neo4j.session.READ); - session.readTransaction(tx => tx.run('MATCH (n) RETURN n.name')).then(res => { - session.close(); - driver.close(); - router1.exit(code1 => { - router2.exit(code2 => { - router3.exit(code3 => { - reader.exit(code4 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - expect(code3).toEqual(0); - expect(code4).toEqual(0); - done(); - }); - }); - }); - }); - }).catch(error => done.fail(error)); - }); - }); - - function testDiscovery(scheme, done) { + }) + + const session = driver.session(neo4j.session.READ) + session + .readTransaction(tx => tx.run('MATCH (n) RETURN n.name')) + .then(res => { + session.close() + driver.close() + router1.exit(code1 => { + router2.exit(code2 => { + router3.exit(code3 => { + reader.exit(code4 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + expect(code3).toEqual(0) + expect(code4).toEqual(0) + done() + }) + }) + }) + }) + }) + .catch(error => done.fail(error)) + }) + }) + + function testDiscovery (scheme, done) { if (!boltStub.supported) { done() return } // Given - const server = boltStub.start('./test/resources/boltstub/discover_servers_and_read.script', 9001) + const server = boltStub.start( + './test/resources/boltstub/discover_servers_and_read.script', + 9001 + ) boltStub.run(() => { const driver = boltStub.newDriver(`${scheme}://127.0.0.1:9001`) // When const session = driver.session() session.run('MATCH (n) RETURN n.name').then(() => { - session.close() // Then - expect(hasAddressInConnectionPool(driver, '127.0.0.1:9001')).toBeTruthy() - assertHasRouters(driver, ['127.0.0.1:9001', '127.0.0.1:9002', '127.0.0.1:9003']) + expect( + hasAddressInConnectionPool(driver, '127.0.0.1:9001') + ).toBeTruthy() + assertHasRouters(driver, [ + '127.0.0.1:9001', + '127.0.0.1:9002', + '127.0.0.1:9003' + ]) assertHasReaders(driver, ['127.0.0.1:9002', '127.0.0.1:9003']) assertHasWriters(driver, ['127.0.0.1:9001']) @@ -2176,352 +2741,444 @@ describe('routing driver with stub server', () => { }) } - function testAddressPurgeOnDatabaseError(query, accessMode, done) { + function testAddressPurgeOnDatabaseError (query, accessMode, done) { if (!boltStub.supported) { - done(); - return; + done() + return } + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9010 + ) - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9010); - - const serverPort = accessMode === READ ? 9005 : 9007; - const serverAddress = '127.0.0.1:' + serverPort; - const serverTemplateScript = './test/resources/boltstub/address_unavailable_template.script.mst'; - const server = boltStub.startWithTemplate(serverTemplateScript, {query: query}, serverPort); + const serverPort = accessMode === READ ? 9005 : 9007 + const serverAddress = '127.0.0.1:' + serverPort + const serverTemplateScript = + './test/resources/boltstub/address_unavailable_template.script.mst' + const server = boltStub.startWithTemplate( + serverTemplateScript, + { query: query }, + serverPort + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9010') - const session = driver.session(accessMode); + const session = driver.session(accessMode) session.run(query).catch(error => { - expect(error.message).toEqual('Database is busy doing store copy'); - expect(error.code).toEqual('Neo.TransientError.General.DatabaseUnavailable'); + expect(error.message).toEqual('Database is busy doing store copy') + expect(error.code).toEqual( + 'Neo.TransientError.General.DatabaseUnavailable' + ) - expect(hasAddressInConnectionPool(driver, serverAddress)).toBeFalsy(); - expect(hasRouterInRoutingTable(driver, serverAddress)).toBeFalsy(); - expect(hasReaderInRoutingTable(driver, serverAddress)).toBeFalsy(); - expect(hasWriterInRoutingTable(driver, serverAddress)).toBeFalsy(); + expect(hasAddressInConnectionPool(driver, serverAddress)).toBeFalsy() + expect(hasRouterInRoutingTable(driver, serverAddress)).toBeFalsy() + expect(hasReaderInRoutingTable(driver, serverAddress)).toBeFalsy() + expect(hasWriterInRoutingTable(driver, serverAddress)).toBeFalsy() session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { server.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) } - function moveTime30SecondsForward() { - const currentTime = Date.now(); - clock = lolex.install(); - clock.setSystemTime(currentTime + 30 * 1000 + 1); + function moveTime30SecondsForward () { + const currentTime = Date.now() + clock = lolex.install() + clock.setSystemTime(currentTime + 30 * 1000 + 1) } - function removeTimeMocking() { + function removeTimeMocking () { if (clock) { - clock.uninstall(); - clock = null; + clock.uninstall() + clock = null } } - function testWriteSessionWithAccessModeAndBookmark(accessMode, bookmark, done) { + function testWriteSessionWithAccessModeAndBookmark ( + accessMode, + bookmark, + done + ) { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9001); - const writer = boltStub.start('./test/resources/boltstub/write_tx_with_bookmarks.script', 9007); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9001 + ) + const writer = boltStub.start( + './test/resources/boltstub/write_tx_with_bookmarks.script', + 9007 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') - const session = driver.session(accessMode, bookmark); - const tx = session.beginTransaction(); - tx.run('CREATE (n {name:\'Bob\'})').then(() => { + const session = driver.session(accessMode, bookmark) + const tx = session.beginTransaction() + tx.run("CREATE (n {name:'Bob'})").then(() => { tx.commit().then(() => { - expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242'); + expect(session.lastBookmark()).toEqual('neo4j:bookmark:v1:tx4242') - session.close(); - driver.close(); + session.close() + driver.close() router.exit(code1 => { writer.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + }) + }) } - function testDiscoveryAndReadQueryInAutoCommitTx(routerScript, driverConfig, done) { + function testDiscoveryAndReadQueryInAutoCommitTx ( + routerScript, + driverConfig, + done + ) { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start(routerScript, 9001); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const router = boltStub.start(routerScript, 9001) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001', driverConfig); - - const session = driver.session(READ); - session.run('MATCH (n) RETURN n.name').then(result => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); - session.close(); - driver.close(); - router.exit(code1 => { - reader.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }).catch(done.fail); - }); + const driver = boltStub.newDriver( + 'bolt+routing://127.0.0.1:9001', + driverConfig + ) + + const session = driver.session(READ) + session + .run('MATCH (n) RETURN n.name') + .then(result => { + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) + session.close() + driver.close() + router.exit(code1 => { + reader.exit(code2 => { + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) + .catch(done.fail) + }) } - function testForProtocolError(scriptFile, done) { + function testForProtocolError (scriptFile, done) { if (!boltStub.supported) { - done(); - return; + done() + return } - const server = boltStub.start(scriptFile, 9001); + const server = boltStub.start(scriptFile, 9001) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001'); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:9001') - const session = driver.session(); + const session = driver.session() session.run('MATCH (n) RETURN n.name').catch(error => { - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) - session.close(); - driver.close(); + session.close() + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); + expect(code).toEqual(0) + done() }) - }); - }); + }) + }) } - function testRoutingTableAcceptance(clusterMembers, port, done) { + function testRoutingTableAcceptance (clusterMembers, port, done) { if (!boltStub.supported) { - done(); - return; + done() + return } - const {routers, readers, writers} = clusterMembers; + const { routers, readers, writers } = clusterMembers const params = { routers: joinStrings(routers), readers: joinStrings(readers), writers: joinStrings(writers) - }; - const server = boltStub.startWithTemplate('./test/resources/boltstub/one_of_each_template.script.mst', params, port); + } + const server = boltStub.startWithTemplate( + './test/resources/boltstub/one_of_each_template.script.mst', + params, + port + ) boltStub.run(() => { - const driver = boltStub.newDriver('bolt+routing://127.0.0.1:' + port); + const driver = boltStub.newDriver('bolt+routing://127.0.0.1:' + port) - const session = driver.session(); + const session = driver.session() session.run('MATCH (n) RETURN n.name').then(result => { + expect(result.summary.server.address).toEqual('127.0.0.1:' + port) - expect(result.summary.server.address).toEqual('127.0.0.1:' + port); - - session.close(); - driver.close(); + session.close() + driver.close() server.exit(code => { - expect(code).toEqual(0); - done(); + expect(code).toEqual(0) + done() }) - }); - }); + }) + }) } - function setUpPoolToMemorizeAllAcquiredAndReleasedConnections(driver, acquiredConnections, releasedConnections) { + function setUpPoolToMemorizeAllAcquiredAndReleasedConnections ( + driver, + acquiredConnections, + releasedConnections + ) { // make connection pool remember all acquired connections - const connectionPool = getConnectionPool(driver); + const connectionPool = getConnectionPool(driver) - const originalAcquire = connectionPool.acquire.bind(connectionPool); + const originalAcquire = connectionPool.acquire.bind(connectionPool) const memorizingAcquire = (...args) => { return originalAcquire(...args).then(connection => { - acquiredConnections.push(connection); - return connection; - }); - }; - connectionPool.acquire = memorizingAcquire; + acquiredConnections.push(connection) + return connection + }) + } + connectionPool.acquire = memorizingAcquire // make connection pool remember all released connections - const originalRelease = connectionPool._release; + const originalRelease = connectionPool._release const rememberingRelease = (key, resource) => { - originalRelease(key, resource); - releasedConnections.push(resource); - }; - connectionPool._release = rememberingRelease; + originalRelease(key, resource) + releasedConnections.push(resource) + } + connectionPool._release = rememberingRelease } - function hasAddressInConnectionPool(driver, address) { - return getConnectionPool(driver).has(ServerAddress.fromUrl(address)); + function hasAddressInConnectionPool (driver, address) { + return getConnectionPool(driver).has(ServerAddress.fromUrl(address)) } - function hasRouterInRoutingTable(driver, expectedRouter) { - return getRoutingTable(driver).routers.indexOf(ServerAddress.fromUrl(expectedRouter)) > -1; + function hasRouterInRoutingTable (driver, expectedRouter) { + return ( + getRoutingTable(driver).routers.indexOf( + ServerAddress.fromUrl(expectedRouter) + ) > -1 + ) } - function hasReaderInRoutingTable(driver, expectedReader) { - return getRoutingTable(driver).readers.indexOf(ServerAddress.fromUrl(expectedReader)) > -1; + function hasReaderInRoutingTable (driver, expectedReader) { + return ( + getRoutingTable(driver).readers.indexOf( + ServerAddress.fromUrl(expectedReader) + ) > -1 + ) } - function hasWriterInRoutingTable(driver, expectedWriter) { - return getRoutingTable(driver).writers.indexOf(ServerAddress.fromUrl(expectedWriter)) > -1; + function hasWriterInRoutingTable (driver, expectedWriter) { + return ( + getRoutingTable(driver).writers.indexOf( + ServerAddress.fromUrl(expectedWriter) + ) > -1 + ) } - function assertHasRouters(driver, expectedRouters) { - expect(getRoutingTable(driver).routers.map(s => s.asHostPort())).toEqual(expectedRouters); + function assertHasRouters (driver, expectedRouters) { + expect(getRoutingTable(driver).routers.map(s => s.asHostPort())).toEqual( + expectedRouters + ) } - function assertHasReaders(driver, expectedReaders) { - expect(getRoutingTable(driver).readers.map(s => s.asHostPort())).toEqual(expectedReaders); + function assertHasReaders (driver, expectedReaders) { + expect(getRoutingTable(driver).readers.map(s => s.asHostPort())).toEqual( + expectedReaders + ) } - function assertHasWriters(driver, expectedWriters) { - expect(getRoutingTable(driver).writers.map(s => s.asHostPort())).toEqual(expectedWriters); + function assertHasWriters (driver, expectedWriters) { + expect(getRoutingTable(driver).writers.map(s => s.asHostPort())).toEqual( + expectedWriters + ) } - function setUpMemorizingRoutingTable(driver) { - const memorizingRoutingTable = new MemorizingRoutingTable(getRoutingTable(driver)); - setRoutingTable(driver, memorizingRoutingTable); - return memorizingRoutingTable; + function setUpMemorizingRoutingTable (driver) { + const memorizingRoutingTable = new MemorizingRoutingTable( + getRoutingTable(driver) + ) + setRoutingTable(driver, memorizingRoutingTable) + return memorizingRoutingTable } - function setupFakeHostNameResolution(driver, seedRouter, resolvedAddresses) { - const connectionProvider = driver._getOrCreateConnectionProvider(); + function setupFakeHostNameResolution (driver, seedRouter, resolvedAddresses) { + const connectionProvider = driver._getOrCreateConnectionProvider() connectionProvider._hostNameResolver._resolverFunction = function (address) { if (address === seedRouter) { - return Promise.resolve(resolvedAddresses); + return Promise.resolve(resolvedAddresses) } - return Promise.reject(new Error('Unexpected seed router address ' + address)); - }; + return Promise.reject( + new Error('Unexpected seed router address ' + address) + ) + } } - function getConnectionPool(driver) { - const connectionProvider = driver._getOrCreateConnectionProvider(); - return connectionProvider._connectionPool; + function getConnectionPool (driver) { + const connectionProvider = driver._getOrCreateConnectionProvider() + return connectionProvider._connectionPool } - function getRoutingTable(driver) { - const connectionProvider = driver._getOrCreateConnectionProvider(); - return connectionProvider._routingTable; + function getRoutingTable (driver) { + const connectionProvider = driver._getOrCreateConnectionProvider() + return connectionProvider._routingTable } - function setRoutingTable(driver, newRoutingTable) { - const connectionProvider = driver._getOrCreateConnectionProvider(); - connectionProvider._routingTable = newRoutingTable; + function setRoutingTable (driver, newRoutingTable) { + const connectionProvider = driver._getOrCreateConnectionProvider() + connectionProvider._routingTable = newRoutingTable } - function joinStrings(array) { - return '[' + array.map(s => '"' + s + '"').join(',') + ']'; + function joinStrings (array) { + return '[' + array.map(s => '"' + s + '"').join(',') + ']' } - function numberOfOpenConnections(driver) { - return Object.keys(driver._openConnections).length; + function numberOfOpenConnections (driver) { + return Object.keys(driver._openConnections).length } - function testResolverFunctionDuringFirstDiscovery(resolutionResult, done) { + function testResolverFunctionDuringFirstDiscovery (resolutionResult, done) { if (!boltStub.supported) { - done(); - return; + done() + return } - const router = boltStub.start('./test/resources/boltstub/acquire_endpoints.script', 9010); - const reader = boltStub.start('./test/resources/boltstub/read_server.script', 9005); + const router = boltStub.start( + './test/resources/boltstub/acquire_endpoints.script', + 9010 + ) + const reader = boltStub.start( + './test/resources/boltstub/read_server.script', + 9005 + ) boltStub.run(() => { const resolverFunction = address => { if (address === 'neo4j.com:7687') { - return resolutionResult; + return resolutionResult } - throw new Error(`Unexpected address ${address}`); - }; + throw new Error(`Unexpected address ${address}`) + } - const driver = boltStub.newDriver('bolt+routing://neo4j.com', {resolver: resolverFunction}); + const driver = boltStub.newDriver('bolt+routing://neo4j.com', { + resolver: resolverFunction + }) - const session = driver.session(READ); - session.run('MATCH (n) RETURN n.name') + const session = driver.session(READ) + session + .run('MATCH (n) RETURN n.name') .then(result => { - expect(result.records.map(record => record.get(0))).toEqual(['Bob', 'Alice', 'Tina']); + expect(result.records.map(record => record.get(0))).toEqual([ + 'Bob', + 'Alice', + 'Tina' + ]) session.close(() => { - driver.close(); + driver.close() router.exit(code1 => { reader.exit(code2 => { - expect(code1).toEqual(0); - expect(code2).toEqual(0); - done(); - }); - }); - }); + expect(code1).toEqual(0) + expect(code2).toEqual(0) + done() + }) + }) + }) }) - .catch(done.fail); - }); + .catch(done.fail) + }) } - function testResolverFunctionFailureDuringFirstDiscovery(failureFunction, expectedCode, expectedMessage, done) { + function testResolverFunctionFailureDuringFirstDiscovery ( + failureFunction, + expectedCode, + expectedMessage, + done + ) { if (!boltStub.supported) { - done(); - return; + done() + return } const resolverFunction = address => { if (address === 'neo4j.com:8989') { - return failureFunction(); + return failureFunction() } - throw new Error('Unexpected address'); - }; + throw new Error('Unexpected address') + } - const driver = boltStub.newDriver('bolt+routing://neo4j.com:8989', {resolver: resolverFunction}); - const session = driver.session(); + const driver = boltStub.newDriver('bolt+routing://neo4j.com:8989', { + resolver: resolverFunction + }) + const session = driver.session() - session.run('RETURN 1') + session + .run('RETURN 1') .then(result => done.fail(result)) .catch(error => { if (expectedCode) { - expect(error.code).toEqual(expectedCode); + expect(error.code).toEqual(expectedCode) } if (expectedMessage) { - expect(error.message.indexOf(expectedMessage)).toBeGreaterThan(-1); + expect(error.message.indexOf(expectedMessage)).toBeGreaterThan(-1) } - done(); - }); + done() + }) } class MemorizingRoutingTable extends RoutingTable { - - constructor(initialTable) { - super(initialTable.routers, initialTable.readers, initialTable.writers, initialTable.expirationTime); - this._forgottenRouters = []; + constructor (initialTable) { + super( + initialTable.routers, + initialTable.readers, + initialTable.writers, + initialTable.expirationTime + ) + this._forgottenRouters = [] } - forgetRouter(address) { - super.forgetRouter(address); - this._forgottenRouters.push(address); + forgetRouter (address) { + super.forgetRouter(address) + this._forgottenRouters.push(address) } - assertForgotRouters(expectedRouters) { - expect(this._forgottenRouters.map(s => s.asHostPort())).toEqual(expectedRouters); + assertForgotRouters (expectedRouters) { + expect(this._forgottenRouters.map(s => s.asHostPort())).toEqual( + expectedRouters + ) } } -}); +}) diff --git a/test/internal/node/tls.test.js b/test/internal/node/tls.test.js index 275bdbbc3..d244e77ef 100644 --- a/test/internal/node/tls.test.js +++ b/test/internal/node/tls.test.js @@ -17,376 +17,408 @@ * limitations under the License. */ -import neo4j from '../../../src/v1'; -import fs from 'fs'; -import path from 'path'; -import sharedNeo4j from '../shared-neo4j'; +import neo4j from '../../../src/v1' +import fs from 'fs' +import path from 'path' +import sharedNeo4j from '../shared-neo4j' describe('trust-signed-certificates', () => { - - let driver; - let log; + let driver + let log beforeEach(() => { - log = muteConsoleLog(); - }); + log = muteConsoleLog() + }) afterEach(() => { if (driver) { - driver.close(); + driver.close() } - unMuteConsoleLog(log); - }); + unMuteConsoleLog(log) + }) it('should reject unknown certificates', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { - encrypted: "ENCRYPTION_ON", - trust: "TRUST_SIGNED_CERTIFICATES", - trustedCertificates: ["test/resources/random.certificate"] - }); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_SIGNED_CERTIFICATES', + trustedCertificates: ['test/resources/random.certificate'] + }) // When - driver.session().run('RETURN 1').catch(err => { - expect( err.message ).toContain( "Server certificate is not trusted" ); - done(); - }); - }); + driver + .session() + .run('RETURN 1') + .catch(err => { + expect(err.message).toContain('Server certificate is not trusted') + done() + }) + }) it('should accept known certificates', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { - encrypted: "ENCRYPTION_ON", - trust: "TRUST_SIGNED_CERTIFICATES", + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_SIGNED_CERTIFICATES', trustedCertificates: [neo4jCertPath()] - }); + }) // When - driver.session().run( "RETURN 1").then( done ); - }); + driver + .session() + .run('RETURN 1') + .then(done) + }) it('should handle multiple certificates', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_SIGNED_CERTIFICATES", + trust: 'TRUST_SIGNED_CERTIFICATES', trustedCertificates: [neo4jCertPath(), neo4jCertPath()] - }); + }) // When - driver.session().run( "RETURN 1").then( done ); - }); -}); + driver + .session() + .run('RETURN 1') + .then(done) + }) +}) describe('trust-all-certificates', () => { - - let driver; + let driver afterEach(() => { if (driver) { - driver.close(); + driver.close() } - }); + }) it('should work with default certificate', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { - encrypted: "ENCRYPTION_ON", - trust: "TRUST_ALL_CERTIFICATES" - }); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_ALL_CERTIFICATES' + }) // When - driver.session().run('RETURN 1').then(result => { - expect(result.records[0].get(0).toNumber()).toBe(1); - done(); - }); - }); -}); + driver + .session() + .run('RETURN 1') + .then(result => { + expect(result.records[0].get(0).toNumber()).toBe(1) + done() + }) + }) +}) describe('trust-custom-ca-signed-certificates', () => { - - let driver; + let driver afterEach(() => { if (driver) { - driver.close(); + driver.close() } - }); + }) it('should reject unknown certificates', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES", - trustedCertificates: ["test/resources/random.certificate"] - }); + trust: 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES', + trustedCertificates: ['test/resources/random.certificate'] + }) // When - driver.session().run('RETURN 1').catch(err => { - expect( err.message ).toContain( "Server certificate is not trusted" ); - done(); - }); - }); + driver + .session() + .run('RETURN 1') + .catch(err => { + expect(err.message).toContain('Server certificate is not trusted') + done() + }) + }) it('should accept known certificates', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES", + trust: 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES', trustedCertificates: [neo4jCertPath()] - }); + }) // When - driver.session().run( "RETURN 1").then( done ); - }); -}); + driver + .session() + .run('RETURN 1') + .then(done) + }) +}) describe('trust-system-ca-signed-certificates', () => { - - let driver; + let driver afterEach(() => { if (driver) { - driver.close(); + driver.close() } - }); + }) it('should reject unknown certificates', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES" - }); + trust: 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES' + }) // When - driver.session().run('RETURN 1').catch(err => { - expect( err.message ).toContain( "Server certificate is not trusted" ); - done(); - }); - }); -}); + driver + .session() + .run('RETURN 1') + .catch(err => { + expect(err.message).toContain('Server certificate is not trusted') + done() + }) + }) +}) describe('trust-on-first-use', () => { - - let driver; - let log; + let driver + let log beforeEach(() => { - log = muteConsoleLog(); - }); + log = muteConsoleLog() + }) afterEach(() => { - unMuteConsoleLog(log); - if( driver ) { - driver.close(); + unMuteConsoleLog(log) + if (driver) { + driver.close() } - }); + }) - it('should create known_hosts file including full path if it doesn\'t exist', done => { + it("should create known_hosts file including full path if it doesn't exist", done => { // Assuming we only run this test on NodeJS with TOFU support if (!trustOnFirstUseAvailable()) { - done(); - return; + done() + return } // Given // Non existing directory - const knownHostsDir = path.join('build', 'hosts'); - const knownHostsPath = path.join(knownHostsDir, 'known_hosts'); + const knownHostsDir = path.join('build', 'hosts') + const knownHostsPath = path.join(knownHostsDir, 'known_hosts') try { - fs.unlinkSync(knownHostsPath); - } catch (_) { } + fs.unlinkSync(knownHostsPath) + } catch (_) {} try { - fs.rmdirSync(knownHostsDir); - } catch (_) { } + fs.rmdirSync(knownHostsDir) + } catch (_) {} - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_ON_FIRST_USE", + trust: 'TRUST_ON_FIRST_USE', knownHosts: knownHostsPath - }); + }) // When - driver.session().run('RETURN 1').then(() => { - // Then we get to here. - // And then the known_hosts file should have been created - expect(() => { - fs.accessSync(knownHostsPath); - }).not.toThrow(); - done(); - }).catch(() => { - // Just here to gracefully exit test on failure so we don't get timeouts - // when done() isn't called. - expect( 'this' ).toBe( 'to never happen' ); - done(); - }); - }); + driver + .session() + .run('RETURN 1') + .then(() => { + // Then we get to here. + // And then the known_hosts file should have been created + expect(() => { + fs.accessSync(knownHostsPath) + }).not.toThrow() + done() + }) + .catch(() => { + // Just here to gracefully exit test on failure so we don't get timeouts + // when done() isn't called. + expect('this').toBe('to never happen') + done() + }) + }) it('should not throw an error if the host file contains two host duplicates', done => { // Assuming we only run this test on NodeJS with TOFU support if (!trustOnFirstUseAvailable()) { - done(); - return; + done() + return } // Given - const knownHostsPath = 'build/known_hosts'; - if( fs.existsSync(knownHostsPath) ) { - fs.unlinkSync(knownHostsPath); + const knownHostsPath = 'build/known_hosts' + if (fs.existsSync(knownHostsPath)) { + fs.unlinkSync(knownHostsPath) } - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_ON_FIRST_USE", + trust: 'TRUST_ON_FIRST_USE', knownHosts: knownHostsPath - }); + }) // create session and transaction to force creation of new connection and writing into the knownHost file - const session = driver.session(); - expect(session.beginTransaction()).toBeDefined(); + const session = driver.session() + expect(session.beginTransaction()).toBeDefined() // duplicate the same serverId twice setTimeout(() => { - const text = fs.readFileSync(knownHostsPath, 'utf8'); - fs.writeFileSync(knownHostsPath, text + text); - }, 1000); + const text = fs.readFileSync(knownHostsPath, 'utf8') + fs.writeFileSync(knownHostsPath, text + text) + }, 1000) // When setTimeout(() => { - driver.session().run('RETURN true AS a').then(data => { - // Then we get to here. - expect( data.records[0].get('a') ).toBe( true ); - done(); - }); - }, 2000); - }); + driver + .session() + .run('RETURN true AS a') + .then(data => { + // Then we get to here. + expect(data.records[0].get('a')).toBe(true) + done() + }) + }, 2000) + }) it('should accept previously un-seen hosts', done => { // Assuming we only run this test on NodeJS with TOFU support if (!trustOnFirstUseAvailable()) { - done(); - return; + done() + return } // Given - const knownHostsPath = 'build/known_hosts'; - if( fs.existsSync(knownHostsPath) ) { - fs.unlinkSync(knownHostsPath); + const knownHostsPath = 'build/known_hosts' + if (fs.existsSync(knownHostsPath)) { + fs.unlinkSync(knownHostsPath) } - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { - encrypted: "ENCRYPTION_ON", - trust: "TRUST_ON_FIRST_USE", + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_ON_FIRST_USE', knownHosts: knownHostsPath - }); + }) // When - driver.session().run('RETURN 1').then(() => { - // Then we get to here. - // And then the known_hosts file should have correct contents - expect( fs.readFileSync(knownHostsPath, 'utf8') ).toContain( "localhost:7687" ); - done(); - }); - }); + driver + .session() + .run('RETURN 1') + .then(() => { + // Then we get to here. + // And then the known_hosts file should have correct contents + expect(fs.readFileSync(knownHostsPath, 'utf8')).toContain( + 'localhost:7687' + ) + done() + }) + }) it('should not duplicate fingerprint entries', done => { // Assuming we only run this test on NodeJS with TOFU support if (!trustOnFirstUseAvailable()) { - done(); - return; + done() + return } // Given - const knownHostsPath = 'build/known_hosts'; - if( fs.existsSync(knownHostsPath) ) { - fs.unlinkSync(knownHostsPath); + const knownHostsPath = 'build/known_hosts' + if (fs.existsSync(knownHostsPath)) { + fs.unlinkSync(knownHostsPath) } - fs.writeFileSync(knownHostsPath, ''); + fs.writeFileSync(knownHostsPath, '') - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { encrypted: true, - trust: "TRUST_ON_FIRST_USE", + trust: 'TRUST_ON_FIRST_USE', knownHosts: knownHostsPath - }); + }) // When - driver.session(); - driver.session(); + driver.session() + driver.session() // Then setTimeout(() => { - const lines = {}; + const lines = {} fs.readFileSync(knownHostsPath, 'utf8') - .split('\n') - .filter(line => !!(line.trim())) + .split('\n') + .filter(line => !!line.trim()) .forEach(line => { - if (!lines[line]) { - lines[line] = 0; - } - lines[line]++; - }); - - const duplicatedLines = Object - .keys(lines) + if (!lines[line]) { + lines[line] = 0 + } + lines[line]++ + }) + + const duplicatedLines = Object.keys(lines) .map(line => lines[line]) - .filter(count => count > 1) - .length; + .filter(count => count > 1).length - expect( duplicatedLines ).toBe( 0 ); - done(); - }, 1000); - }); + expect(duplicatedLines).toBe(0) + done() + }, 1000) + }) it('should should give helpful error if database cert does not match stored certificate', done => { // Assuming we only run this test on NodeJS with TOFU support if (!trustOnFirstUseAvailable()) { - done(); - return; + done() + return } // Given - const knownHostsPath = 'test/resources/random_known_hosts'; + const knownHostsPath = 'test/resources/random_known_hosts' - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken, { - encrypted: "ENCRYPTION_ON", - trust: "TRUST_ON_FIRST_USE", + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_ON_FIRST_USE', knownHosts: knownHostsPath - }); + }) // When - driver.session().run('RETURN 1').catch(error => { - expect(error.message).toContain("Database encryption certificate has changed, " + - "and no longer matches the certificate stored for localhost:7687"); - done(); - }); - }); -}); + driver + .session() + .run('RETURN 1') + .catch(error => { + expect(error.message).toContain( + 'Database encryption certificate has changed, ' + + 'and no longer matches the certificate stored for localhost:7687' + ) + done() + }) + }) +}) // To mute deprecation message in test output -function muteConsoleLog() { - const originalLog = console.log; - console.log = () => {}; - return originalLog; +function muteConsoleLog () { + const originalLog = console.log + console.log = () => {} + return originalLog } -function unMuteConsoleLog(originalLog) { - console.log = originalLog; +function unMuteConsoleLog (originalLog) { + console.log = originalLog } -function neo4jCertPath() { - return sharedNeo4j.neo4jCertPath(path.join('build', 'neo4j')); +function neo4jCertPath () { + return sharedNeo4j.neo4jCertPath(path.join('build', 'neo4j')) } -function trustOnFirstUseAvailable() { +function trustOnFirstUseAvailable () { try { // We are verifying that we have a version of getPeerCertificate // that supports reading the whole certificate, eg this commit: // https://github.com/nodejs/node/commit/345c40b6 - require.resolve('tls'); - const getPeerCertificateFunction = require('tls').TLSSocket.prototype.getPeerCertificate; - const numberOfParameters = getPeerCertificateFunction.length; - return numberOfParameters >= 1; + require.resolve('tls') + const getPeerCertificateFunction = require('tls').TLSSocket.prototype + .getPeerCertificate + const numberOfParameters = getPeerCertificateFunction.length + return numberOfParameters >= 1 } catch (e) { - return false; + return false } } diff --git a/test/internal/packstream-v1.test.js b/test/internal/packstream-v1.test.js index abd8f121a..45a3c3858 100644 --- a/test/internal/packstream-v1.test.js +++ b/test/internal/packstream-v1.test.js @@ -17,66 +17,70 @@ * limitations under the License. */ -import {alloc} from '../../src/v1/internal/node'; -import {Packer, Structure, Unpacker} from '../../src/v1/internal/packstream-v1'; -import {int} from '../../src/v1'; +import { alloc } from '../../src/v1/internal/node' +import { + Packer, + Structure, + Unpacker +} from '../../src/v1/internal/packstream-v1' +import { int } from '../../src/v1' describe('packstream-v1', () => { - it('should pack integers', () => { - let n, i; + let n, i // test small numbers for (n = -999; n <= 999; n += 1) { - i = int(n); - expect(packAndUnpack(i).toString()).toBe(i.toString()); + i = int(n) + expect(packAndUnpack(i).toString()).toBe(i.toString()) } // positive numbers for (n = 16; n <= 16; n += 1) { - i = int(Math.pow(2, n)); - expect(packAndUnpack(i).toString()).toBe(i.toString()); + i = int(Math.pow(2, n)) + expect(packAndUnpack(i).toString()).toBe(i.toString()) } // negative numbers for (n = 0; n <= 63; n += 1) { - i = int(-Math.pow(2, n)); - expect(packAndUnpack(i).toString()).toBe(i.toString()); + i = int(-Math.pow(2, n)) + expect(packAndUnpack(i).toString()).toBe(i.toString()) } - }); + }) it('should pack strings', () => { - expect(packAndUnpack('')).toBe(''); - expect(packAndUnpack('abcdefg123567')).toBe('abcdefg123567'); - const str = Array(65536 + 1).join('a'); // 2 ^ 16 + 1 - expect(packAndUnpack(str, str.length + 8)).toBe(str); - }); + expect(packAndUnpack('')).toBe('') + expect(packAndUnpack('abcdefg123567')).toBe('abcdefg123567') + const str = Array(65536 + 1).join('a') // 2 ^ 16 + 1 + expect(packAndUnpack(str, str.length + 8)).toBe(str) + }) it('should pack structures', () => { - expect(packAndUnpack(new Structure(1, ['Hello, world!!!'])).fields[0]) - .toBe('Hello, world!!!'); - }); + expect(packAndUnpack(new Structure(1, ['Hello, world!!!'])).fields[0]).toBe( + 'Hello, world!!!' + ) + }) it('should pack lists', () => { - const list = ['a', 'b']; - const unpacked = packAndUnpack(list); - expect(unpacked[0]).toBe(list[0]); - expect(unpacked[1]).toBe(list[1]); - }); + const list = ['a', 'b'] + const unpacked = packAndUnpack(list) + expect(unpacked[0]).toBe(list[0]) + expect(unpacked[1]).toBe(list[1]) + }) it('should pack long lists', () => { - const listLength = 256; - const list = []; + const listLength = 256 + const list = [] for (let i = 0; i < listLength; i++) { - list.push(null); + list.push(null) } - const unpacked = packAndUnpack(list, 1400); - expect(unpacked[0]).toBe(list[0]); - expect(unpacked[1]).toBe(list[1]); - }); -}); + const unpacked = packAndUnpack(list, 1400) + expect(unpacked[0]).toBe(list[0]) + expect(unpacked[1]).toBe(list[1]) + }) +}) -function packAndUnpack(val, bufferSize) { - bufferSize = bufferSize || 128; - const buffer = alloc(bufferSize); - new Packer(buffer).packable(val)(); - buffer.reset(); - return new Unpacker().unpack(buffer); +function packAndUnpack (val, bufferSize) { + bufferSize = bufferSize || 128 + const buffer = alloc(bufferSize) + new Packer(buffer).packable(val)() + buffer.reset() + return new Unpacker().unpack(buffer) } diff --git a/test/internal/pool-config.test.js b/test/internal/pool-config.test.js index 829e22beb..a5cdac87e 100644 --- a/test/internal/pool-config.test.js +++ b/test/internal/pool-config.test.js @@ -17,94 +17,94 @@ * limitations under the License. */ -import PoolConfig, {DEFAULT_ACQUISITION_TIMEOUT, DEFAULT_MAX_SIZE} from '../../src/v1/internal/pool-config'; +import PoolConfig, { + DEFAULT_ACQUISITION_TIMEOUT, + DEFAULT_MAX_SIZE +} from '../../src/v1/internal/pool-config' describe('PoolConfig', () => { - - let originalConsoleWarn; + let originalConsoleWarn beforeAll(() => { - originalConsoleWarn = console.warn; - console.warn = () => { - }; - }); + originalConsoleWarn = console.warn + console.warn = () => {} + }) afterAll(() => { - console.warn = originalConsoleWarn; - }); + console.warn = originalConsoleWarn + }) it('should respect zero values', () => { - const config = new PoolConfig(0, 0, 0); + const config = new PoolConfig(0, 0, 0) - expect(config.maxSize).toEqual(0); - expect(config.acquisitionTimeout).toEqual(0); - }); + expect(config.maxSize).toEqual(0) + expect(config.acquisitionTimeout).toEqual(0) + }) it('should expose default config', () => { - const config = PoolConfig.defaultConfig(); + const config = PoolConfig.defaultConfig() - expect(config.maxSize).toEqual(DEFAULT_MAX_SIZE); - expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT); - }); + expect(config.maxSize).toEqual(DEFAULT_MAX_SIZE) + expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT) + }) it('should convert from empty driver config', () => { - const driverConfig = {}; - const config = PoolConfig.fromDriverConfig(driverConfig); + const driverConfig = {} + const config = PoolConfig.fromDriverConfig(driverConfig) - expect(config.maxSize).toEqual(DEFAULT_MAX_SIZE); - expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT); - }); + expect(config.maxSize).toEqual(DEFAULT_MAX_SIZE) + expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT) + }) it('should convert from full driver config', () => { const driverConfig = { maxConnectionPoolSize: 42, connectionAcquisitionTimeout: 4242 - }; - const config = PoolConfig.fromDriverConfig(driverConfig); + } + const config = PoolConfig.fromDriverConfig(driverConfig) - expect(config.maxSize).toEqual(42); - expect(config.acquisitionTimeout).toEqual(4242); - }); + expect(config.maxSize).toEqual(42) + expect(config.acquisitionTimeout).toEqual(4242) + }) it('should convert from driver config with both connectionPoolSize and maxConnectionPoolSize', () => { const driverConfig = { connectionPoolSize: 42, maxConnectionPoolSize: 4242 - }; - const config = PoolConfig.fromDriverConfig(driverConfig); + } + const config = PoolConfig.fromDriverConfig(driverConfig) - expect(config.maxSize).toEqual(4242); - expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT); - }); + expect(config.maxSize).toEqual(4242) + expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT) + }) it('should convert from driver config without connectionPoolSize and maxConnectionPoolSize', () => { const driverConfig = { connectionAcquisitionTimeout: 42 - }; - const config = PoolConfig.fromDriverConfig(driverConfig); + } + const config = PoolConfig.fromDriverConfig(driverConfig) - expect(config.maxSize).toEqual(DEFAULT_MAX_SIZE); - expect(config.acquisitionTimeout).toEqual(42); - }); + expect(config.maxSize).toEqual(DEFAULT_MAX_SIZE) + expect(config.acquisitionTimeout).toEqual(42) + }) it('should convert from driver config with only connectionPoolSize', () => { const driverConfig = { connectionPoolSize: 42 - }; - const config = PoolConfig.fromDriverConfig(driverConfig); + } + const config = PoolConfig.fromDriverConfig(driverConfig) - expect(config.maxSize).toEqual(42); - expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT); - }); + expect(config.maxSize).toEqual(42) + expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT) + }) it('should convert from driver config with only maxConnectionPoolSize', () => { const driverConfig = { maxConnectionPoolSize: 42 - }; - const config = PoolConfig.fromDriverConfig(driverConfig); - - expect(config.maxSize).toEqual(42); - expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT); - }); + } + const config = PoolConfig.fromDriverConfig(driverConfig) -}); + expect(config.maxSize).toEqual(42) + expect(config.acquisitionTimeout).toEqual(DEFAULT_ACQUISITION_TIMEOUT) + }) +}) diff --git a/test/internal/pool.test.js b/test/internal/pool.test.js index 96e938cec..96d59c1c8 100644 --- a/test/internal/pool.test.js +++ b/test/internal/pool.test.js @@ -17,264 +17,277 @@ * limitations under the License. */ -import Pool from '../../src/v1/internal/pool'; -import PoolConfig from '../../src/v1/internal/pool-config'; -import ServerAddress from '../../src/v1/internal/server-address'; +import Pool from '../../src/v1/internal/pool' +import PoolConfig from '../../src/v1/internal/pool-config' +import ServerAddress from '../../src/v1/internal/server-address' describe('Pool', () => { - - it('allocates if pool is empty', (done) => { + it('allocates if pool is empty', done => { // Given - let counter = 0; - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release))); + let counter = 0 + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, counter++, release)) + ) // When - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) // Then - Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(r0.id).toBe(0); - expect(r1.id).toBe(1); - expect(r0).not.toBe(r1); + expect(r0.id).toBe(0) + expect(r1.id).toBe(1) + expect(r0).not.toBe(r1) - done(); - }); - }); + done() + }) + }) - it('pools if resources are returned', (done) => { + it('pools if resources are returned', done => { // Given a pool that allocates - let counter = 0; - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release))); + let counter = 0 + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, counter++, release)) + ) // When const p0 = pool.acquire(address).then(r0 => { - r0.close(); - return r0; - }); - const p1 = p0.then(r0 => pool.acquire(address)); + r0.close() + return r0 + }) + const p1 = p0.then(r0 => pool.acquire(address)) // Then - Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(r0.id).toBe(0); - expect(r1.id).toBe(0); - expect(r0).toBe(r1); + expect(r0.id).toBe(0) + expect(r1.id).toBe(0) + expect(r0).toBe(r1) - done(); - }); - }); + done() + }) + }) - it('handles multiple keys', (done) => { + it('handles multiple keys', done => { // Given a pool that allocates - let counter = 0; - const address1 = ServerAddress.fromUrl('bolt://localhost:7687'); - const address2 = ServerAddress.fromUrl('bolt://localhost:7688'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release))); + let counter = 0 + const address1 = ServerAddress.fromUrl('bolt://localhost:7687') + const address2 = ServerAddress.fromUrl('bolt://localhost:7688') + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, counter++, release)) + ) // When - const p0 = pool.acquire(address1); - const p1 = pool.acquire(address2); - const p01 = Promise.all([ p0, p1 ]).then(values => values[0].close()); - const p2 = p01.then(() => pool.acquire(address1)); - const p3 = p01.then(() => pool.acquire(address2)); + const p0 = pool.acquire(address1) + const p1 = pool.acquire(address2) + const p01 = Promise.all([p0, p1]).then(values => values[0].close()) + const p2 = p01.then(() => pool.acquire(address1)) + const p3 = p01.then(() => pool.acquire(address2)) // Then - Promise.all([ p0, p1, p2, p3 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; - const r2 = values[2]; - const r3 = values[3]; + Promise.all([p0, p1, p2, p3]).then(values => { + const r0 = values[0] + const r1 = values[1] + const r2 = values[2] + const r3 = values[3] - expect(r0.id).toBe(0); - expect(r1.id).toBe(1); - expect(r2.id).toBe(0); - expect(r3.id).toBe(2); + expect(r0.id).toBe(0) + expect(r1.id).toBe(1) + expect(r2.id).toBe(0) + expect(r3.id).toBe(2) - expect(r0).toBe(r2); - expect(r1).not.toBe(r3); + expect(r0).toBe(r2) + expect(r1).not.toBe(r3) - done(); - }); - }); + done() + }) + }) - it('frees if validate returns false', (done) => { + it('frees if validate returns false', done => { // Given a pool that allocates - let counter = 0; - let destroyed = []; - const address = ServerAddress.fromUrl('bolt://localhost:7687'); + let counter = 0 + let destroyed = [] + const address = ServerAddress.fromUrl('bolt://localhost:7687') const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), resource => { - destroyed.push(resource); + destroyed.push(resource) }, resource => false, new PoolConfig(1000, 60000) - ); + ) // When - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) // Then - Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; - - r0.close(); - r1.close(); + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(destroyed.length).toBe(2); - expect(destroyed[0].id).toBe(r0.id); - expect(destroyed[1].id).toBe(r1.id); + r0.close() + r1.close() - done(); - }); - }); + expect(destroyed.length).toBe(2) + expect(destroyed[0].id).toBe(r0.id) + expect(destroyed[1].id).toBe(r1.id) + done() + }) + }) - it('purges keys', (done) => { + it('purges keys', done => { // Given a pool that allocates - let counter = 0; - const address1 = ServerAddress.fromUrl('bolt://localhost:7687'); - const address2 = ServerAddress.fromUrl('bolt://localhost:7688'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + let counter = 0 + const address1 = ServerAddress.fromUrl('bolt://localhost:7687') + const address2 = ServerAddress.fromUrl('bolt://localhost:7688') + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true } - ); + ) // When - const p0 = pool.acquire(address1); - const p1 = pool.acquire(address2); - const p01 = Promise.all([ p0, p1 ]).then(values => { - values.forEach(v => v.close()); + const p0 = pool.acquire(address1) + const p1 = pool.acquire(address2) + const p01 = Promise.all([p0, p1]).then(values => { + values.forEach(v => v.close()) - expect(pool.has(address1)).toBeTruthy(); - expect(pool.has(address2)).toBeTruthy(); + expect(pool.has(address1)).toBeTruthy() + expect(pool.has(address2)).toBeTruthy() - pool.purge(address1); + pool.purge(address1) - expect(pool.has(address1)).toBeFalsy(); - expect(pool.has(address2)).toBeTruthy(); - }); + expect(pool.has(address1)).toBeFalsy() + expect(pool.has(address2)).toBeTruthy() + }) - const p2 = p01.then(() => pool.acquire(address1)); - const p3 = p01.then(() => pool.acquire(address2)); + const p2 = p01.then(() => pool.acquire(address1)) + const p3 = p01.then(() => pool.acquire(address2)) // Then - Promise.all([ p0, p1, p2, p3 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; - const r2 = values[2]; - const r3 = values[3]; - - expect(r0.id).toBe(0); - expect(r0.destroyed).toBeTruthy(); - expect(r1.id).toBe(1); - expect(r2.id).toBe(2); - expect(r3.id).toBe(1); - - done(); - }); - }); - - it('clears out resource counters even after purge', (done) => { + Promise.all([p0, p1, p2, p3]).then(values => { + const r0 = values[0] + const r1 = values[1] + const r2 = values[2] + const r3 = values[3] + + expect(r0.id).toBe(0) + expect(r0.destroyed).toBeTruthy() + expect(r1.id).toBe(1) + expect(r2.id).toBe(2) + expect(r3.id).toBe(1) + + done() + }) + }) + + it('clears out resource counters even after purge', done => { // Given a pool that allocates - let counter = 0; - const address1 = ServerAddress.fromUrl('bolt://localhost:7687'); - const address2 = ServerAddress.fromUrl('bolt://localhost:7688'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + let counter = 0 + const address1 = ServerAddress.fromUrl('bolt://localhost:7687') + const address2 = ServerAddress.fromUrl('bolt://localhost:7688') + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true } - ); + ) // When - const p00 = pool.acquire(address1); - const p01 = pool.acquire(address1); - const p10 = pool.acquire(address2); - const p11 = pool.acquire(address2); - const p12 = pool.acquire(address2); - const pall = Promise.all([p00, p01, p10, p11, p12]).then(values => { - expect(pool.activeResourceCount(address1)).toEqual(2); - expect(pool.activeResourceCount(address2)).toEqual(3); + const p00 = pool.acquire(address1) + const p01 = pool.acquire(address1) + const p10 = pool.acquire(address2) + const p11 = pool.acquire(address2) + const p12 = pool.acquire(address2) + Promise.all([p00, p01, p10, p11, p12]).then(values => { + expect(pool.activeResourceCount(address1)).toEqual(2) + expect(pool.activeResourceCount(address2)).toEqual(3) - expect(pool.has(address1)).toBeTruthy(); - expect(pool.has(address2)).toBeTruthy(); + expect(pool.has(address1)).toBeTruthy() + expect(pool.has(address2)).toBeTruthy() - values[0].close(); + values[0].close() - expect(pool.activeResourceCount(address1)).toEqual(1); + expect(pool.activeResourceCount(address1)).toEqual(1) - pool.purge(address1); + pool.purge(address1) - expect(pool.activeResourceCount(address1)).toEqual(1); + expect(pool.activeResourceCount(address1)).toEqual(1) - values[1].close(); + values[1].close() - expect(pool.activeResourceCount(address1)).toEqual(0); - expect(pool.activeResourceCount(address2)).toEqual(3); + expect(pool.activeResourceCount(address1)).toEqual(0) + expect(pool.activeResourceCount(address2)).toEqual(3) - expect(values[0].destroyed).toBeTruthy(); - expect(values[1].destroyed).toBeTruthy(); + expect(values[0].destroyed).toBeTruthy() + expect(values[1].destroyed).toBeTruthy() - expect(pool.has(address1)).toBeFalsy(); - expect(pool.has(address2)).toBeTruthy(); + expect(pool.has(address1)).toBeFalsy() + expect(pool.has(address2)).toBeTruthy() - done(); - }); - }); + done() + }) + }) - it('destroys resource when key was purged', (done) => { - let counter = 0; - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + it('destroys resource when key was purged', done => { + let counter = 0 + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true } - ); + ) - const p0 = pool.acquire(address); + const p0 = pool.acquire(address) p0.then(r0 => { - expect(pool.has(address)).toBeTruthy(); - expect(r0.id).toEqual(0); + expect(pool.has(address)).toBeTruthy() + expect(r0.id).toEqual(0) - pool.purge(address); - expect(pool.has(address)).toBeFalsy(); - expect(r0.destroyed).toBeFalsy(); + pool.purge(address) + expect(pool.has(address)).toBeFalsy() + expect(r0.destroyed).toBeFalsy() - r0.close(); - expect(pool.has(address)).toBeFalsy(); - expect(r0.destroyed).toBeTruthy(); + r0.close() + expect(pool.has(address)).toBeFalsy() + expect(r0.destroyed).toBeTruthy() - done(); - }); - }); + done() + }) + }) - it('purges all keys', (done) => { - let counter = 0; + it('purges all keys', done => { + let counter = 0 - const address1 = ServerAddress.fromUrl('bolt://localhost:7687'); - const address2 = ServerAddress.fromUrl('bolt://localhost:7688'); - const address3 = ServerAddress.fromUrl('bolt://localhost:7689'); + const address1 = ServerAddress.fromUrl('bolt://localhost:7687') + const address2 = ServerAddress.fromUrl('bolt://localhost:7688') + const address3 = ServerAddress.fromUrl('bolt://localhost:7689') - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true } - ); + ) const acquiredResources = [ pool.acquire(address1), @@ -283,32 +296,34 @@ describe('Pool', () => { pool.acquire(address1), pool.acquire(address2), pool.acquire(address3) - ]; + ] Promise.all(acquiredResources).then(values => { - values.forEach(resource => resource.close()); + values.forEach(resource => resource.close()) - pool.purgeAll(); + pool.purgeAll() - values.forEach(resource => expect(resource.destroyed).toBeTruthy()); + values.forEach(resource => expect(resource.destroyed).toBeTruthy()) - done(); - }); - }); + done() + }) + }) it('purges keys other than the ones to keep', done => { - let counter = 0; + let counter = 0 - const address1 = ServerAddress.fromUrl('bolt://localhost:7687'); - const address2 = ServerAddress.fromUrl('bolt://localhost:7688'); - const address3 = ServerAddress.fromUrl('bolt://localhost:7689'); + const address1 = ServerAddress.fromUrl('bolt://localhost:7687') + const address2 = ServerAddress.fromUrl('bolt://localhost:7688') + const address3 = ServerAddress.fromUrl('bolt://localhost:7689') - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true } - ); + ) const acquiredResources = [ pool.acquire(address1), @@ -317,36 +332,38 @@ describe('Pool', () => { pool.acquire(address1), pool.acquire(address2), pool.acquire(address3) - ]; + ] Promise.all(acquiredResources).then(values => { - expect(pool.has(address1)).toBeTruthy(); - expect(pool.has(address2)).toBeTruthy(); - expect(pool.has(address3)).toBeTruthy(); + expect(pool.has(address1)).toBeTruthy() + expect(pool.has(address2)).toBeTruthy() + expect(pool.has(address3)).toBeTruthy() - pool.keepAll([address1, address3]); + pool.keepAll([address1, address3]) - expect(pool.has(address1)).toBeTruthy(); - expect(pool.has(address3)).toBeTruthy(); - expect(pool.has(address2)).toBeFalsy(); + expect(pool.has(address1)).toBeTruthy() + expect(pool.has(address3)).toBeTruthy() + expect(pool.has(address2)).toBeFalsy() - done(); - }); - }); + done() + }) + }) it('purges all keys if addresses to keep is empty', done => { - let counter = 0; + let counter = 0 - const address1 = ServerAddress.fromUrl('bolt://localhost:7687'); - const address2 = ServerAddress.fromUrl('bolt://localhost:7688'); - const address3 = ServerAddress.fromUrl('bolt://localhost:7689'); + const address1 = ServerAddress.fromUrl('bolt://localhost:7687') + const address2 = ServerAddress.fromUrl('bolt://localhost:7688') + const address3 = ServerAddress.fromUrl('bolt://localhost:7689') - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true } - ); + ) const acquiredResources = [ pool.acquire(address1), @@ -355,410 +372,439 @@ describe('Pool', () => { pool.acquire(address1), pool.acquire(address2), pool.acquire(address3) - ]; + ] Promise.all(acquiredResources).then(values => { - expect(pool.has(address1)).toBeTruthy(); - expect(pool.has(address2)).toBeTruthy(); - expect(pool.has(address3)).toBeTruthy(); - - pool.keepAll([]); + expect(pool.has(address1)).toBeTruthy() + expect(pool.has(address2)).toBeTruthy() + expect(pool.has(address3)).toBeTruthy() - expect(pool.has(address1)).toBeFalsy(); - expect(pool.has(address3)).toBeFalsy(); - expect(pool.has(address2)).toBeFalsy(); + pool.keepAll([]) - done(); - }); - }); + expect(pool.has(address1)).toBeFalsy() + expect(pool.has(address3)).toBeFalsy() + expect(pool.has(address2)).toBeFalsy() + done() + }) + }) - it('skips broken connections during acquire', (done) => { - let validated = false; - let counter = 0; - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, counter++, release)), + it('skips broken connections during acquire', done => { + let validated = false + let counter = 0 + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool( + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), res => { - res.destroyed = true; - return true; + res.destroyed = true + return true }, () => { if (validated) { - return false; + return false } - validated = true; - return true; + validated = true + return true } - ); + ) - const p0 = pool.acquire(address); + const p0 = pool.acquire(address) const p1 = p0.then(r0 => { - r0.close(); + r0.close() - return pool.acquire(address); - }); + return pool.acquire(address) + }) - Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(r1).not.toBe(r0); + expect(r1).not.toBe(r0) - done(); - }); - }); + done() + }) + }) - it('reports presence of the key', (done) => { - const existingAddress = ServerAddress.fromUrl('bolt://localhost:7687'); - const absentAddress = ServerAddress.fromUrl('bolt://localhost:7688'); + it('reports presence of the key', done => { + const existingAddress = ServerAddress.fromUrl('bolt://localhost:7687') + const absentAddress = ServerAddress.fromUrl('bolt://localhost:7688') - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, 42, release))); + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, 42, release)) + ) - const p0 = pool.acquire(existingAddress); - const p1 = pool.acquire(existingAddress); + const p0 = pool.acquire(existingAddress) + const p1 = pool.acquire(existingAddress) - Promise.all([ p0, p1 ]).then(() => { - expect(pool.has(existingAddress)).toBeTruthy(); - expect(pool.has(absentAddress)).toBeFalsy(); + Promise.all([p0, p1]).then(() => { + expect(pool.has(existingAddress)).toBeTruthy() + expect(pool.has(absentAddress)).toBeFalsy() - done(); - }); - }); + done() + }) + }) it('reports zero active resources when empty', () => { - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, 42, release))); - - expect(pool.activeResourceCount(ServerAddress.fromUrl('bolt://localhost:1'))).toEqual(0); - expect(pool.activeResourceCount(ServerAddress.fromUrl('bolt://localhost:2'))).toEqual(0); - expect(pool.activeResourceCount(ServerAddress.fromUrl('bolt://localhost:3'))).toEqual(0); - }); - - it('reports active resources', (done) => { - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, 42, release))); - - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); - const p2 = pool.acquire(address); - - Promise.all([ p0, p1, p2 ]).then(values => { - values.forEach(v => expect(v).toBeDefined()); - - expect(pool.activeResourceCount(address)).toEqual(3); - - done(); - }); - }); - - it('reports active resources when they are acquired', (done) => { - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, 42, release))); + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, 42, release)) + ) + + expect( + pool.activeResourceCount(ServerAddress.fromUrl('bolt://localhost:1')) + ).toEqual(0) + expect( + pool.activeResourceCount(ServerAddress.fromUrl('bolt://localhost:2')) + ).toEqual(0) + expect( + pool.activeResourceCount(ServerAddress.fromUrl('bolt://localhost:3')) + ).toEqual(0) + }) + + it('reports active resources', done => { + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, 42, release)) + ) + + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) + const p2 = pool.acquire(address) + + Promise.all([p0, p1, p2]).then(values => { + values.forEach(v => expect(v).toBeDefined()) + + expect(pool.activeResourceCount(address)).toEqual(3) + + done() + }) + }) + + it('reports active resources when they are acquired', done => { + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, 42, release)) + ) // three new resources are created and returned to the pool - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); - const p2 = pool.acquire(address); - const p012 = Promise.all([ p0, p1, p2 ]).then(values => { - values.forEach(v => v.close()); - return values; - }); + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) + const p2 = pool.acquire(address) + const p012 = Promise.all([p0, p1, p2]).then(values => { + values.forEach(v => v.close()) + return values + }) // three idle resources are acquired from the pool - const p3 = p012.then(() => pool.acquire(address)); - const p4 = p012.then(() => pool.acquire(address)); - const p5 = p012.then(() => pool.acquire(address)); + const p3 = p012.then(() => pool.acquire(address)) + const p4 = p012.then(() => pool.acquire(address)) + const p5 = p012.then(() => pool.acquire(address)) - const pAll = Promise.all([ p012, p3, p4, p5 ]).then(values => { - const r0 = values[0][0]; - const r1 = values[0][1]; - const r2 = values[0][2]; + Promise.all([p012, p3, p4, p5]).then(values => { + const r0 = values[0][0] + const r1 = values[0][1] + const r2 = values[0][2] - expect(values).toContain(r0); - expect(values).toContain(r1); - expect(values).toContain(r2); + expect(values).toContain(r0) + expect(values).toContain(r1) + expect(values).toContain(r2) - expect(pool.activeResourceCount(address)).toEqual(3); + expect(pool.activeResourceCount(address)).toEqual(3) - done(); - }); - }); + done() + }) + }) - it('does not report resources that are returned to the pool', (done) => { - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const pool = new Pool((server, release) => Promise.resolve(new Resource(server, 42, release))); + it('does not report resources that are returned to the pool', done => { + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const pool = new Pool((server, release) => + Promise.resolve(new Resource(server, 42, release)) + ) - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); - const p2 = pool.acquire(address); - const p012 = Promise.all([ p0, p1, p2 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; - const r2 = values[2]; + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) + const p2 = pool.acquire(address) + const p012 = Promise.all([p0, p1, p2]).then(values => { + const r0 = values[0] + const r1 = values[1] + const r2 = values[2] - expect(pool.activeResourceCount(address)).toEqual(3); + expect(pool.activeResourceCount(address)).toEqual(3) - r0.close(); - expect(pool.activeResourceCount(address)).toEqual(2); + r0.close() + expect(pool.activeResourceCount(address)).toEqual(2) - r1.close(); - expect(pool.activeResourceCount(address)).toEqual(1); + r1.close() + expect(pool.activeResourceCount(address)).toEqual(1) - r2.close(); - expect(pool.activeResourceCount(address)).toEqual(0); + r2.close() + expect(pool.activeResourceCount(address)).toEqual(0) - return values; - }); + return values + }) - const p3 = p012.then(() => pool.acquire(address)).then(r3 => { - expect(pool.activeResourceCount(address)).toEqual(1); + p012 + .then(() => pool.acquire(address)) + .then(r3 => { + expect(pool.activeResourceCount(address)).toEqual(1) - r3.close(); - expect(pool.activeResourceCount(address)).toEqual(0); + r3.close() + expect(pool.activeResourceCount(address)).toEqual(0) - done(); - }); - }); + done() + }) + }) it('should wait for a returned connection when max pool size is reached', done => { - let counter = 0; + let counter = 0 - const address = ServerAddress.fromUrl('bolt://localhost:7687'); + const address = ServerAddress.fromUrl('bolt://localhost:7687') const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), - resource => {}, - resource => true, + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), + resource => {}, + resource => true, new PoolConfig(2, 5000) - ); + ) - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); - const p01 = Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(r0.id).toEqual(0); - expect(r1.id).toEqual(1); + expect(r0.id).toEqual(0) + expect(r1.id).toEqual(1) - const p2 = pool.acquire(address).then(r2 => { - expect(r2).toBe(r1); + pool.acquire(address).then(r2 => { + expect(r2).toBe(r1) - done(); - }); + done() + }) setTimeout(() => { - expectNumberOfAcquisitionRequests(pool, address, 1); - r1.close(); - }, 1000); - }); - }); + expectNumberOfAcquisitionRequests(pool, address, 1) + r1.close() + }, 1000) + }) + }) it('should time out when max pool size is reached', done => { - let counter = 0; + let counter = 0 - const address = ServerAddress.fromUrl('bolt://localhost:7687'); + const address = ServerAddress.fromUrl('bolt://localhost:7687') const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), - resource => {}, - resource => true, + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), + resource => {}, + resource => true, new PoolConfig(2, 1000) - ); + ) - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); - const p01 = Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(r0.id).toEqual(0); - expect(r1.id).toEqual(1); + expect(r0.id).toEqual(0) + expect(r1.id).toEqual(1) pool.acquire(address).catch(error => { - expect(error.message).toContain('timed out'); - expectNumberOfAcquisitionRequests(pool, address, 0); - done(); - }); - }); - }); + expect(error.message).toContain('timed out') + expectNumberOfAcquisitionRequests(pool, address, 0) + done() + }) + }) + }) it('should not time out if max pool size is not set', done => { - let counter = 0; + let counter = 0 - const address = ServerAddress.fromUrl('bolt://localhost:7687'); + const address = ServerAddress.fromUrl('bolt://localhost:7687') const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), - resource => {}, - resource => true - ); + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), + resource => {}, + resource => true + ) - const p0 = pool.acquire(address); - const p1 = pool.acquire(address); - const p01 = Promise.all([ p0, p1 ]).then(values => { - const r0 = values[0]; - const r1 = values[1]; + const p0 = pool.acquire(address) + const p1 = pool.acquire(address) + Promise.all([p0, p1]).then(values => { + const r0 = values[0] + const r1 = values[1] - expect(r0.id).toEqual(0); - expect(r1.id).toEqual(1); + expect(r0.id).toEqual(0) + expect(r1.id).toEqual(1) pool.acquire(address).then(r2 => { - expect(r2.id).toEqual(2); - expectNoPendingAcquisitionRequests(pool); - done(); - }); - }); - }); + expect(r2.id).toEqual(2) + expectNoPendingAcquisitionRequests(pool) + done() + }) + }) + }) it('should work fine when resources released together with acquisition timeout', done => { - const acquisitionTimeout = 1000; - let counter = 0; + const acquisitionTimeout = 1000 + let counter = 0 - const address = ServerAddress.fromUrl('bolt://localhost:7687'); + const address = ServerAddress.fromUrl('bolt://localhost:7687') const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), - resource => { - }, + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), + resource => {}, () => true, new PoolConfig(2, acquisitionTimeout) - ); + ) pool.acquire(address).then(resource1 => { - expect(resource1.id).toEqual(0); + expect(resource1.id).toEqual(0) pool.acquire(address).then(resource2 => { - expect(resource2.id).toEqual(1); + expect(resource2.id).toEqual(1) // try to release both resources around the time acquisition fails with timeout // double-release used to cause deletion of acquire requests in the pool and failure of the timeout // such background failure made this test fail, not the existing assertions setTimeout(() => { - resource1.close(); - resource2.close(); - }, acquisitionTimeout); - - pool.acquire(address).then(someResource => { - expect(someResource).toBeDefined(); - expect(someResource).not.toBeNull(); - expectNoPendingAcquisitionRequests(pool); - done(); // ok, promise got resolved before the timeout - }).catch(error => { - expect(error).toBeDefined(); - expect(error).not.toBeNull(); - expectNoPendingAcquisitionRequests(pool); - done(); // also ok, timeout fired before promise got resolved - }); - }); - }); - }); + resource1.close() + resource2.close() + }, acquisitionTimeout) + + pool + .acquire(address) + .then(someResource => { + expect(someResource).toBeDefined() + expect(someResource).not.toBeNull() + expectNoPendingAcquisitionRequests(pool) + done() // ok, promise got resolved before the timeout + }) + .catch(error => { + expect(error).toBeDefined() + expect(error).not.toBeNull() + expectNoPendingAcquisitionRequests(pool) + done() // also ok, timeout fired before promise got resolved + }) + }) + }) + }) it('should resolve pending acquisition request when single invalid resource returned', done => { - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const acquisitionTimeout = 1000; - let counter = 0; + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const acquisitionTimeout = 1000 + let counter = 0 const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), - resource => { - }, + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), + resource => {}, resourceValidOnlyOnceValidationFunction, new PoolConfig(1, acquisitionTimeout) - ); + ) pool.acquire(address).then(resource1 => { - expect(resource1.id).toEqual(0); - expect(pool.activeResourceCount(address)).toEqual(1); + expect(resource1.id).toEqual(0) + expect(pool.activeResourceCount(address)).toEqual(1) // release the resource before the acquisition timeout, it should be treated as invalid setTimeout(() => { - expectNumberOfAcquisitionRequests(pool, address, 1); - resource1.close(); - }, acquisitionTimeout / 2); - - pool.acquire(address).then(resource2 => { - expect(resource2.id).toEqual(1); - expectNoPendingAcquisitionRequests(pool); - expect(pool.activeResourceCount(address)).toEqual(1); - done(); - }).catch(error => { - done.fail(error); - }); - }); - }); + expectNumberOfAcquisitionRequests(pool, address, 1) + resource1.close() + }, acquisitionTimeout / 2) + + pool + .acquire(address) + .then(resource2 => { + expect(resource2.id).toEqual(1) + expectNoPendingAcquisitionRequests(pool) + expect(pool.activeResourceCount(address)).toEqual(1) + done() + }) + .catch(error => { + done.fail(error) + }) + }) + }) it('should work fine when invalid resources released and acquisition attempt pending', done => { - const address = ServerAddress.fromUrl('bolt://localhost:7687'); - const acquisitionTimeout = 1000; - let counter = 0; + const address = ServerAddress.fromUrl('bolt://localhost:7687') + const acquisitionTimeout = 1000 + let counter = 0 const pool = new Pool( - (server, release) => Promise.resolve(new Resource(server, counter++, release)), - resource => { - }, + (server, release) => + Promise.resolve(new Resource(server, counter++, release)), + resource => {}, resourceValidOnlyOnceValidationFunction, new PoolConfig(2, acquisitionTimeout) - ); + ) pool.acquire(address).then(resource1 => { - expect(resource1.id).toEqual(0); - expect(pool.activeResourceCount(address)).toEqual(1); + expect(resource1.id).toEqual(0) + expect(pool.activeResourceCount(address)).toEqual(1) pool.acquire(address).then(resource2 => { - expect(resource2.id).toEqual(1); - expect(pool.activeResourceCount(address)).toEqual(2); + expect(resource2.id).toEqual(1) + expect(pool.activeResourceCount(address)).toEqual(2) // release both resources before the acquisition timeout, they should be treated as invalid setTimeout(() => { - expectNumberOfAcquisitionRequests(pool, address, 1); - resource1.close(); - resource2.close(); - }, acquisitionTimeout / 2); - - pool.acquire(address).then(resource3 => { - expect(resource3.id).toEqual(2); - expectNoPendingAcquisitionRequests(pool); - expect(pool.activeResourceCount(address)).toEqual(1); - done(); - }).catch(error => { - done.fail(error); - }); - }); - }); - }); - -}); - -function expectNoPendingAcquisitionRequests(pool) { - const acquireRequests = pool._acquireRequests; + expectNumberOfAcquisitionRequests(pool, address, 1) + resource1.close() + resource2.close() + }, acquisitionTimeout / 2) + + pool + .acquire(address) + .then(resource3 => { + expect(resource3.id).toEqual(2) + expectNoPendingAcquisitionRequests(pool) + expect(pool.activeResourceCount(address)).toEqual(1) + done() + }) + .catch(error => { + done.fail(error) + }) + }) + }) + }) +}) + +function expectNoPendingAcquisitionRequests (pool) { + const acquireRequests = pool._acquireRequests Object.values(acquireRequests).forEach(requests => { if (Array.isArray(requests) && requests.length === 0) { - requests = undefined; + requests = undefined } - expect(requests).not.toBeDefined(); - }); + expect(requests).not.toBeDefined() + }) } -function expectNumberOfAcquisitionRequests(pool, address, expectedNumber) { - expect(pool._acquireRequests[address.asKey()].length).toEqual(expectedNumber); +function expectNumberOfAcquisitionRequests (pool, address, expectedNumber) { + expect(pool._acquireRequests[address.asKey()].length).toEqual(expectedNumber) } -function resourceValidOnlyOnceValidationFunction(resource) { +function resourceValidOnlyOnceValidationFunction (resource) { // all resources are valid only once if (resource.validatedOnce) { - return false; + return false } else { - resource.validatedOnce = true; - return true; + resource.validatedOnce = true + return true } } class Resource { - - constructor(key, id, release) { - this.id = id; - this.key = key; - this.release = release; - this.destroyed = false; + constructor (key, id, release) { + this.id = id + this.key = key + this.release = release + this.destroyed = false } - close() { - this.release(this.key, this); + close () { + this.release(this.key, this) } } diff --git a/test/internal/protocol-handshaker.test.js b/test/internal/protocol-handshaker.test.js index 3ae93a453..277ade136 100644 --- a/test/internal/protocol-handshaker.test.js +++ b/test/internal/protocol-handshaker.test.js @@ -17,74 +17,98 @@ * limitations under the License. */ -import ProtocolHandshaker from '../../src/v1/internal/protocol-handshaker'; -import Logger from '../../src/v1/internal/logger'; -import BoltProtocol from '../../src/v1/internal/bolt-protocol-v1'; -import {alloc} from '../../src/v1/internal/node'; +import ProtocolHandshaker from '../../src/v1/internal/protocol-handshaker' +import Logger from '../../src/v1/internal/logger' +import BoltProtocol from '../../src/v1/internal/bolt-protocol-v1' +import { alloc } from '../../src/v1/internal/node' describe('ProtocolHandshaker', () => { - it('should write handshake request', () => { - const writtenBuffers = []; + const writtenBuffers = [] const fakeChannel = { write: buffer => writtenBuffers.push(buffer) - }; + } - const handshaker = new ProtocolHandshaker(null, fakeChannel, null, false, Logger.noOp()); + const handshaker = new ProtocolHandshaker( + null, + fakeChannel, + null, + false, + Logger.noOp() + ) - handshaker.writeHandshakeRequest(); + handshaker.writeHandshakeRequest() - expect(writtenBuffers.length).toEqual(1); + expect(writtenBuffers.length).toEqual(1) - const boltMagicPreamble = '60 60 b0 17'; - const protocolVersion3 = '00 00 00 03'; - const protocolVersion2 = '00 00 00 02'; - const protocolVersion1 = '00 00 00 01'; - const noProtocolVersion = '00 00 00 00'; + const boltMagicPreamble = '60 60 b0 17' + const protocolVersion3 = '00 00 00 03' + const protocolVersion2 = '00 00 00 02' + const protocolVersion1 = '00 00 00 01' + const noProtocolVersion = '00 00 00 00' - expect(writtenBuffers[0].toHex()).toEqual(`${boltMagicPreamble} ${protocolVersion3} ${protocolVersion2} ${protocolVersion1} ${noProtocolVersion}`); - }); + expect(writtenBuffers[0].toHex()).toEqual( + `${boltMagicPreamble} ${protocolVersion3} ${protocolVersion2} ${protocolVersion1} ${noProtocolVersion}` + ) + }) it('should create protocol with valid version', () => { - const handshaker = new ProtocolHandshaker(null, null, null, false, Logger.noOp()); + const handshaker = new ProtocolHandshaker( + null, + null, + null, + false, + Logger.noOp() + ) // buffer with Bolt V1 - const buffer = handshakeResponse(1); + const buffer = handshakeResponse(1) - const protocol = handshaker.createNegotiatedProtocol(buffer); + const protocol = handshaker.createNegotiatedProtocol(buffer) - expect(protocol).toBeDefined(); - expect(protocol).not.toBeNull(); - expect(protocol instanceof BoltProtocol).toBeTruthy(); - }); + expect(protocol).toBeDefined() + expect(protocol).not.toBeNull() + expect(protocol instanceof BoltProtocol).toBeTruthy() + }) it('should fail to create protocol from invalid version', () => { - const handshaker = new ProtocolHandshaker(null, null, null, false, Logger.noOp()); + const handshaker = new ProtocolHandshaker( + null, + null, + null, + false, + Logger.noOp() + ) // buffer with Bolt V42 which is invalid - const buffer = handshakeResponse(42); + const buffer = handshakeResponse(42) - expect(() => handshaker.createNegotiatedProtocol(buffer)).toThrow(); - }); + expect(() => handshaker.createNegotiatedProtocol(buffer)).toThrow() + }) it('should fail to create protocol from HTTP as invalid version', () => { - const handshaker = new ProtocolHandshaker(null, null, null, false, Logger.noOp()); + const handshaker = new ProtocolHandshaker( + null, + null, + null, + false, + Logger.noOp() + ) // buffer with HTTP magic int - const buffer = handshakeResponse(1213486160); - - expect(() => handshaker.createNegotiatedProtocol(buffer)).toThrow(); - }); + const buffer = handshakeResponse(1213486160) -}); + expect(() => handshaker.createNegotiatedProtocol(buffer)).toThrow() + }) +}) /** * @param {number} version * @return {BaseBuffer} */ -function handshakeResponse(version) { - const buffer = alloc(4); - buffer.writeInt32(version); - buffer.reset(); - return buffer; +function handshakeResponse (version) { + const buffer = alloc(4) + buffer.writeInt32(version) + buffer.reset() + return buffer } diff --git a/test/internal/rediscovery.test.js b/test/internal/rediscovery.test.js index 928b88308..1d3810c59 100644 --- a/test/internal/rediscovery.test.js +++ b/test/internal/rediscovery.test.js @@ -17,79 +17,80 @@ * limitations under the License. */ -import Rediscovery from '../../src/v1/internal/rediscovery'; -import RoutingUtil from '../../src/v1/internal/routing-util'; -import {newError, PROTOCOL_ERROR} from '../../src/v1/error'; -import Record from '../../src/v1/record'; -import {int} from '../../src/v1/integer'; -import RoutingTable from '../../src/v1/internal/routing-table'; -import ServerAddress from '../../src/v1/internal/server-address'; +import Rediscovery from '../../src/v1/internal/rediscovery' +import RoutingUtil from '../../src/v1/internal/routing-util' +import { newError, PROTOCOL_ERROR } from '../../src/v1/error' +import Record from '../../src/v1/record' +import { int } from '../../src/v1/integer' +import ServerAddress from '../../src/v1/internal/server-address' -const ROUTER_ADDRESS = 'bolt+routing://test.router.com'; +const ROUTER_ADDRESS = 'bolt+routing://test.router.com' describe('rediscovery', () => { - it('should return null when connection error happens', done => { const util = new FakeRoutingUtil({ - callRoutingProcedure: () => null, - }); + callRoutingProcedure: () => null + }) lookupRoutingTableOnRouter(util).then(routingTable => { - expect(routingTable).toBeNull(); - done(); - }); - }); + expect(routingTable).toBeNull() + done() + }) + }) it('should throw when no records are returned', done => { const util = new FakeRoutingUtil({ - callRoutingProcedure: () => [], - }); + callRoutingProcedure: () => [] + }) lookupRoutingTableOnRouter(util).catch(error => { - expectProtocolError(error, 'Illegal response from router'); - done(); - }); - }); + expectProtocolError(error, 'Illegal response from router') + done() + }) + }) it('should throw when multiple records are returned', done => { const util = new FakeRoutingUtil({ - callRoutingProcedure: () => [new Record(['a'], ['aaa']), new Record(['b'], ['bbb'])] - }); + callRoutingProcedure: () => [ + new Record(['a'], ['aaa']), + new Record(['b'], ['bbb']) + ] + }) lookupRoutingTableOnRouter(util).catch(error => { - expectProtocolError(error, 'Illegal response from router'); - done(); - }); - }); + expectProtocolError(error, 'Illegal response from router') + done() + }) + }) it('should throw when ttl parsing throws', done => { const util = new FakeRoutingUtil({ callRoutingProcedure: () => [new Record(['a'], ['aaa'])], parseTtl: () => { - throw newError('Unable to parse TTL', PROTOCOL_ERROR); + throw newError('Unable to parse TTL', PROTOCOL_ERROR) } - }); + }) lookupRoutingTableOnRouter(util).catch(error => { - expectProtocolError(error, 'Unable to parse TTL'); - done(); - }); - }); + expectProtocolError(error, 'Unable to parse TTL') + done() + }) + }) it('should throw when servers parsing throws', done => { const util = new FakeRoutingUtil({ callRoutingProcedure: () => [new Record(['a'], ['aaa'])], parseTtl: () => int(42), parseServers: () => { - throw newError('Unable to parse servers', PROTOCOL_ERROR); + throw newError('Unable to parse servers', PROTOCOL_ERROR) } - }); + }) lookupRoutingTableOnRouter(util).catch(error => { - expectProtocolError(error, 'Unable to parse servers'); - done(); - }); - }); + expectProtocolError(error, 'Unable to parse servers') + done() + }) + }) it('should throw when no routers', done => { const util = new FakeRoutingUtil({ @@ -100,15 +101,15 @@ describe('rediscovery', () => { routers: [], readers: ['reader1'], writers: ['writer1'] - }; + } } - }); + }) lookupRoutingTableOnRouter(util).catch(error => { - expectProtocolError(error, 'Received no routers'); - done(); - }); - }); + expectProtocolError(error, 'Received no routers') + done() + }) + }) it('should throw when no readers', done => { const util = new FakeRoutingUtil({ @@ -119,15 +120,15 @@ describe('rediscovery', () => { routers: ['router1'], readers: [], writers: ['writer1'] - }; + } } - }); + }) lookupRoutingTableOnRouter(util).catch(error => { - expectProtocolError(error, 'Received no readers'); - done(); - }); - }); + expectProtocolError(error, 'Received no readers') + done() + }) + }) it('should return routing table when no writers', done => { const util = new FakeRoutingUtil({ @@ -138,30 +139,54 @@ describe('rediscovery', () => { routers: ['router1'], readers: ['reader1'], writers: [] - }; + } } - }); + }) lookupRoutingTableOnRouter(util).then(routingTable => { - expect(routingTable).toBeDefined(); - expect(routingTable).not.toBeNull(); - done(); - }); - }); + expect(routingTable).toBeDefined() + expect(routingTable).not.toBeNull() + done() + }) + }) it('should return valid routing table with 1 router, 1 reader and 1 writer', done => { - testValidRoutingTable(['router1:7687'], ['reader1:7687'], ['writer1:7687'], int(42), done); - }); + testValidRoutingTable( + ['router1:7687'], + ['reader1:7687'], + ['writer1:7687'], + int(42), + done + ) + }) it('should return valid routing table with 2 routers, 2 readers and 2 writers', done => { - testValidRoutingTable(['router1:7687', 'router2:7687'], ['reader1:7687', 'reader2:7687'], ['writer1:7687', 'writer2:7687'], int(Date.now()), done); - }); + testValidRoutingTable( + ['router1:7687', 'router2:7687'], + ['reader1:7687', 'reader2:7687'], + ['writer1:7687', 'writer2:7687'], + int(Date.now()), + done + ) + }) it('should return valid routing table with 1 router, 3 readers and 1 writer', done => { - testValidRoutingTable(['router1:7687'], ['reader1:7687', 'reader2:7687', 'reader3:7687'], ['writer1:7687'], int(12345), done); - }); - - function testValidRoutingTable(routerAddresses, readerAddresses, writerAddresses, expires, done) { + testValidRoutingTable( + ['router1:7687'], + ['reader1:7687', 'reader2:7687', 'reader3:7687'], + ['writer1:7687'], + int(12345), + done + ) + }) + + function testValidRoutingTable ( + routerAddresses, + readerAddresses, + writerAddresses, + expires, + done + ) { const util = new FakeRoutingUtil({ callRoutingProcedure: () => [new Record(['a'], ['aaa'])], parseTtl: () => expires, @@ -170,63 +195,70 @@ describe('rediscovery', () => { routers: routerAddresses.map(a => ServerAddress.fromUrl(a)), readers: readerAddresses.map(a => ServerAddress.fromUrl(a)), writers: writerAddresses.map(a => ServerAddress.fromUrl(a)) - }; + } } - }); + }) lookupRoutingTableOnRouter(util).then(routingTable => { - expect(routingTable).toBeDefined(); - expect(routingTable).not.toBeNull(); + expect(routingTable).toBeDefined() + expect(routingTable).not.toBeNull() - expect(routingTable.expirationTime).toEqual(expires); + expect(routingTable.expirationTime).toEqual(expires) - const allServers = routingTable.allServers().sort(); - const allExpectedServers = [...routerAddresses, ...readerAddresses, ...writerAddresses].sort(); - expect(allServers.map(s => s.asHostPort())).toEqual(allExpectedServers); + const allServers = routingTable.allServers().sort() + const allExpectedServers = [ + ...routerAddresses, + ...readerAddresses, + ...writerAddresses + ].sort() + expect(allServers.map(s => s.asHostPort())).toEqual(allExpectedServers) - done(); - }); + done() + }) } - function lookupRoutingTableOnRouter(routingUtil) { - const rediscovery = new Rediscovery(routingUtil); - return rediscovery.lookupRoutingTableOnRouter(null, ROUTER_ADDRESS); + function lookupRoutingTableOnRouter (routingUtil) { + const rediscovery = new Rediscovery(routingUtil) + return rediscovery.lookupRoutingTableOnRouter(null, ROUTER_ADDRESS) } - function expectProtocolError(error, messagePrefix) { - expect(error.code).toEqual(PROTOCOL_ERROR); - expect(error.message.indexOf(messagePrefix)).toEqual(0); + function expectProtocolError (error, messagePrefix) { + expect(error.code).toEqual(PROTOCOL_ERROR) + expect(error.message.indexOf(messagePrefix)).toEqual(0) } - function shouldNotBeCalled() { - throw new Error('Should not be called'); + function shouldNotBeCalled () { + throw new Error('Should not be called') } class FakeRoutingUtil extends RoutingUtil { - - constructor({callRoutingProcedure = shouldNotBeCalled, parseTtl = shouldNotBeCalled, parseServers = shouldNotBeCalled}) { - super(); - this._callAvailableRoutingProcedure = callRoutingProcedure; - this._parseTtl = parseTtl; - this._parseServers = parseServers; + constructor ({ + callRoutingProcedure = shouldNotBeCalled, + parseTtl = shouldNotBeCalled, + parseServers = shouldNotBeCalled + }) { + super() + this._callAvailableRoutingProcedure = callRoutingProcedure + this._parseTtl = parseTtl + this._parseServers = parseServers } - callRoutingProcedure(session, routerAddress) { + callRoutingProcedure (session, routerAddress) { return new Promise((resolve, reject) => { try { - resolve(this._callAvailableRoutingProcedure()); + resolve(this._callAvailableRoutingProcedure()) } catch (error) { - reject(error); + reject(error) } - }); + }) } - parseTtl(record, routerAddress) { - return this._parseTtl(); + parseTtl (record, routerAddress) { + return this._parseTtl() } - parseServers(record, routerAddress) { - return this._parseServers(); + parseServers (record, routerAddress) { + return this._parseServers() } } -}); +}) diff --git a/test/internal/request-message.test.js b/test/internal/request-message.test.js index 9b994412a..402a668d6 100644 --- a/test/internal/request-message.test.js +++ b/test/internal/request-message.test.js @@ -17,122 +17,157 @@ * limitations under the License. */ -import RequestMessage from '../../src/v1/internal/request-message'; -import Bookmark from '../../src/v1/internal/bookmark'; -import TxConfig from '../../src/v1/internal/tx-config'; -import {int} from '../../src/v1'; -import {READ, WRITE} from "../../src/v1/driver"; +import RequestMessage from '../../src/v1/internal/request-message' +import Bookmark from '../../src/v1/internal/bookmark' +import TxConfig from '../../src/v1/internal/tx-config' +import { int } from '../../src/v1' +import { READ, WRITE } from '../../src/v1/driver' describe('RequestMessage', () => { - it('should create INIT message', () => { - const userAgent = 'my-driver/1.0.2'; - const authToken = {username: 'neo4j', password: 'secret'}; + const userAgent = 'my-driver/1.0.2' + const authToken = { username: 'neo4j', password: 'secret' } - const message = RequestMessage.init(userAgent, authToken); + const message = RequestMessage.init(userAgent, authToken) - expect(message.signature).toEqual(0x01); - expect(message.fields).toEqual([userAgent, authToken]); - expect(message.toString()).toEqual(`INIT ${userAgent} {...}`); - }); + expect(message.signature).toEqual(0x01) + expect(message.fields).toEqual([userAgent, authToken]) + expect(message.toString()).toEqual(`INIT ${userAgent} {...}`) + }) it('should create RUN message', () => { - const statement = 'RETURN $x'; - const parameters = {x: 42}; + const statement = 'RETURN $x' + const parameters = { x: 42 } - const message = RequestMessage.run(statement, parameters); + const message = RequestMessage.run(statement, parameters) - expect(message.signature).toEqual(0x10); - expect(message.fields).toEqual([statement, parameters]); - expect(message.toString()).toEqual(`RUN ${statement} ${JSON.stringify(parameters)}`); - }); + expect(message.signature).toEqual(0x10) + expect(message.fields).toEqual([statement, parameters]) + expect(message.toString()).toEqual( + `RUN ${statement} ${JSON.stringify(parameters)}` + ) + }) it('should create PULL_ALL message', () => { - const message = RequestMessage.pullAll(); + const message = RequestMessage.pullAll() - expect(message.signature).toEqual(0x3F); - expect(message.fields).toEqual([]); - expect(message.toString()).toEqual('PULL_ALL'); - }); + expect(message.signature).toEqual(0x3f) + expect(message.fields).toEqual([]) + expect(message.toString()).toEqual('PULL_ALL') + }) it('should create RESET message', () => { - const message = RequestMessage.reset(); + const message = RequestMessage.reset() - expect(message.signature).toEqual(0x0F); - expect(message.fields).toEqual([]); - expect(message.toString()).toEqual('RESET'); - }); + expect(message.signature).toEqual(0x0f) + expect(message.fields).toEqual([]) + expect(message.toString()).toEqual('RESET') + }) it('should create HELLO message', () => { - const userAgent = 'my-driver/1.0.2'; - const authToken = {username: 'neo4j', password: 'secret'}; + const userAgent = 'my-driver/1.0.2' + const authToken = { username: 'neo4j', password: 'secret' } - const message = RequestMessage.hello(userAgent, authToken); + const message = RequestMessage.hello(userAgent, authToken) - expect(message.signature).toEqual(0x01); - expect(message.fields).toEqual([{user_agent: userAgent, username: 'neo4j', password: 'secret'}]); - expect(message.toString()).toEqual(`HELLO {user_agent: '${userAgent}', ...}`); - }); + expect(message.signature).toEqual(0x01) + expect(message.fields).toEqual([ + { user_agent: userAgent, username: 'neo4j', password: 'secret' } + ]) + expect(message.toString()).toEqual( + `HELLO {user_agent: '${userAgent}', ...}` + ) + }) it('should create BEGIN message', () => { - [READ, WRITE].forEach(mode => { - const bookmark = new Bookmark(['neo4j:bookmark:v1:tx1', 'neo4j:bookmark:v1:tx10']); - const txConfig = new TxConfig({timeout: 42, metadata: {key: 42}}); - - const message = RequestMessage.begin(bookmark, txConfig, mode); - - const expectedMetadata = {bookmarks: bookmark.values(), tx_timeout: int(42), tx_metadata: {key: 42}}; + ;[READ, WRITE].forEach(mode => { + const bookmark = new Bookmark([ + 'neo4j:bookmark:v1:tx1', + 'neo4j:bookmark:v1:tx10' + ]) + const txConfig = new TxConfig({ timeout: 42, metadata: { key: 42 } }) + + const message = RequestMessage.begin(bookmark, txConfig, mode) + + const expectedMetadata = { + bookmarks: bookmark.values(), + tx_timeout: int(42), + tx_metadata: { key: 42 } + } if (mode === READ) { - expectedMetadata.mode = "r"; + expectedMetadata.mode = 'r' } - expect(message.signature).toEqual(0x11); - expect(message.fields).toEqual([expectedMetadata]); - expect(message.toString()).toEqual(`BEGIN ${JSON.stringify(expectedMetadata)}`); - }); - }); + expect(message.signature).toEqual(0x11) + expect(message.fields).toEqual([expectedMetadata]) + expect(message.toString()).toEqual( + `BEGIN ${JSON.stringify(expectedMetadata)}` + ) + }) + }) it('should create COMMIT message', () => { - const message = RequestMessage.commit(); + const message = RequestMessage.commit() - expect(message.signature).toEqual(0x12); - expect(message.fields).toEqual([]); - expect(message.toString()).toEqual('COMMIT'); - }); + expect(message.signature).toEqual(0x12) + expect(message.fields).toEqual([]) + expect(message.toString()).toEqual('COMMIT') + }) it('should create ROLLBACK message', () => { - const message = RequestMessage.rollback(); + const message = RequestMessage.rollback() - expect(message.signature).toEqual(0x13); - expect(message.fields).toEqual([]); - expect(message.toString()).toEqual('ROLLBACK'); - }); + expect(message.signature).toEqual(0x13) + expect(message.fields).toEqual([]) + expect(message.toString()).toEqual('ROLLBACK') + }) it('should create RUN with metadata message', () => { - [READ, WRITE].forEach(mode => { - const statement = 'RETURN $x'; - const parameters = {x: 42}; - const bookmark = new Bookmark(['neo4j:bookmark:v1:tx1', 'neo4j:bookmark:v1:tx10', 'neo4j:bookmark:v1:tx100']); - const txConfig = new TxConfig({timeout: 999, metadata: {a: 'a', b: 'b'}}); - - const message = RequestMessage.runWithMetadata(statement, parameters, bookmark, txConfig, mode); - - const expectedMetadata = {bookmarks: bookmark.values(), tx_timeout: int(999), tx_metadata: {a: 'a', b: 'b'}}; + ;[READ, WRITE].forEach(mode => { + const statement = 'RETURN $x' + const parameters = { x: 42 } + const bookmark = new Bookmark([ + 'neo4j:bookmark:v1:tx1', + 'neo4j:bookmark:v1:tx10', + 'neo4j:bookmark:v1:tx100' + ]) + const txConfig = new TxConfig({ + timeout: 999, + metadata: { a: 'a', b: 'b' } + }) + + const message = RequestMessage.runWithMetadata( + statement, + parameters, + bookmark, + txConfig, + mode + ) + + const expectedMetadata = { + bookmarks: bookmark.values(), + tx_timeout: int(999), + tx_metadata: { a: 'a', b: 'b' } + } if (mode === READ) { - expectedMetadata.mode = "r"; + expectedMetadata.mode = 'r' } - expect(message.signature).toEqual(0x10); - expect(message.fields).toEqual([statement, parameters, expectedMetadata]); - expect(message.toString()).toEqual(`RUN ${statement} ${JSON.stringify(parameters)} ${JSON.stringify(expectedMetadata)}`); - }); - }); + expect(message.signature).toEqual(0x10) + expect(message.fields).toEqual([statement, parameters, expectedMetadata]) + expect(message.toString()).toEqual( + `RUN ${statement} ${JSON.stringify(parameters)} ${JSON.stringify( + expectedMetadata + )}` + ) + }) + }) it('should create GOODBYE message', () => { - const message = RequestMessage.goodbye(); + const message = RequestMessage.goodbye() - expect(message.signature).toEqual(0x02); - expect(message.fields).toEqual([]); - expect(message.toString()).toEqual('GOODBYE'); - }); -}); + expect(message.signature).toEqual(0x02) + expect(message.fields).toEqual([]) + expect(message.toString()).toEqual('GOODBYE') + }) +}) diff --git a/test/internal/round-robin-array-index.test.js b/test/internal/round-robin-array-index.test.js index aef264dca..a78300813 100644 --- a/test/internal/round-robin-array-index.test.js +++ b/test/internal/round-robin-array-index.test.js @@ -16,54 +16,52 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import RoundRobinArrayIndex from '../../src/v1/internal/round-robin-array-index'; +import RoundRobinArrayIndex from '../../src/v1/internal/round-robin-array-index' describe('RoundRobinArrayIndex', () => { - it('should return -1 for empty array', () => { - const arrayLength = 0; - const index = new RoundRobinArrayIndex(); + const arrayLength = 0 + const index = new RoundRobinArrayIndex() - expect(index.next(arrayLength)).toEqual(-1); - }); + expect(index.next(arrayLength)).toEqual(-1) + }) it('should always return 0 for single element array', () => { - const arrayLength = 1; - const index = new RoundRobinArrayIndex(); + const arrayLength = 1 + const index = new RoundRobinArrayIndex() - expect(index.next(arrayLength)).toEqual(0); - expect(index.next(arrayLength)).toEqual(0); - expect(index.next(arrayLength)).toEqual(0); - }); + expect(index.next(arrayLength)).toEqual(0) + expect(index.next(arrayLength)).toEqual(0) + expect(index.next(arrayLength)).toEqual(0) + }) it('should round robin for multi element array', () => { - const arrayLength = 5; - const index = new RoundRobinArrayIndex(); + const arrayLength = 5 + const index = new RoundRobinArrayIndex() - expect(index.next(arrayLength)).toEqual(0); - expect(index.next(arrayLength)).toEqual(1); - expect(index.next(arrayLength)).toEqual(2); - expect(index.next(arrayLength)).toEqual(3); - expect(index.next(arrayLength)).toEqual(4); - expect(index.next(arrayLength)).toEqual(0); - expect(index.next(arrayLength)).toEqual(1); - expect(index.next(arrayLength)).toEqual(2); - expect(index.next(arrayLength)).toEqual(3); - expect(index.next(arrayLength)).toEqual(4); - }); + expect(index.next(arrayLength)).toEqual(0) + expect(index.next(arrayLength)).toEqual(1) + expect(index.next(arrayLength)).toEqual(2) + expect(index.next(arrayLength)).toEqual(3) + expect(index.next(arrayLength)).toEqual(4) + expect(index.next(arrayLength)).toEqual(0) + expect(index.next(arrayLength)).toEqual(1) + expect(index.next(arrayLength)).toEqual(2) + expect(index.next(arrayLength)).toEqual(3) + expect(index.next(arrayLength)).toEqual(4) + }) it('should move back to zero when overflow', () => { - const arrayLength = 5; - const index = new RoundRobinArrayIndex(Number.MAX_SAFE_INTEGER - 2); - - expect(index.next(arrayLength)).toEqual(4); - expect(index.next(arrayLength)).toEqual(0); - expect(index.next(arrayLength)).toEqual(0); - expect(index.next(arrayLength)).toEqual(1); - expect(index.next(arrayLength)).toEqual(2); - expect(index.next(arrayLength)).toEqual(3); - expect(index.next(arrayLength)).toEqual(4); - expect(index.next(arrayLength)).toEqual(0); - }); + const arrayLength = 5 + const index = new RoundRobinArrayIndex(Number.MAX_SAFE_INTEGER - 2) -}); + expect(index.next(arrayLength)).toEqual(4) + expect(index.next(arrayLength)).toEqual(0) + expect(index.next(arrayLength)).toEqual(0) + expect(index.next(arrayLength)).toEqual(1) + expect(index.next(arrayLength)).toEqual(2) + expect(index.next(arrayLength)).toEqual(3) + expect(index.next(arrayLength)).toEqual(4) + expect(index.next(arrayLength)).toEqual(0) + }) +}) diff --git a/test/internal/round-robin-load-balancing-strategy.test.js b/test/internal/round-robin-load-balancing-strategy.test.js index 07f535b0d..af959aff6 100644 --- a/test/internal/round-robin-load-balancing-strategy.test.js +++ b/test/internal/round-robin-load-balancing-strategy.test.js @@ -16,66 +16,64 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import RoundRobinLoadBalancingStrategy from '../../src/v1/internal/round-robin-load-balancing-strategy'; +import RoundRobinLoadBalancingStrategy from '../../src/v1/internal/round-robin-load-balancing-strategy' describe('RoundRobinLoadBalancingStrategy', () => { - it('should return null when no readers', () => { - const knownReaders = []; - const strategy = new RoundRobinLoadBalancingStrategy(); + const knownReaders = [] + const strategy = new RoundRobinLoadBalancingStrategy() - expect(strategy.selectReader(knownReaders)).toBeNull(); - }); + expect(strategy.selectReader(knownReaders)).toBeNull() + }) it('should return null when no writers', () => { - const knownWriters = []; - const strategy = new RoundRobinLoadBalancingStrategy(); + const knownWriters = [] + const strategy = new RoundRobinLoadBalancingStrategy() - expect(strategy.selectWriter(knownWriters)).toBeNull(); - }); + expect(strategy.selectWriter(knownWriters)).toBeNull() + }) it('should return same reader when it is the only one available', () => { - const knownReaders = ['reader-1']; - const strategy = new RoundRobinLoadBalancingStrategy(); + const knownReaders = ['reader-1'] + const strategy = new RoundRobinLoadBalancingStrategy() - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - }); + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + }) it('should return same writer when it is the only one available', () => { - const knownWriters = ['writer-1']; - const strategy = new RoundRobinLoadBalancingStrategy(); + const knownWriters = ['writer-1'] + const strategy = new RoundRobinLoadBalancingStrategy() - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - }); + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + }) it('should return readers in round robin order', () => { - const knownReaders = ['reader-1', 'reader-2', 'reader-3']; - const strategy = new RoundRobinLoadBalancingStrategy(); + const knownReaders = ['reader-1', 'reader-2', 'reader-3'] + const strategy = new RoundRobinLoadBalancingStrategy() - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-3'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-1'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-2'); - expect(strategy.selectReader(knownReaders)).toEqual('reader-3'); - }); + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + expect(strategy.selectReader(knownReaders)).toEqual('reader-3') + expect(strategy.selectReader(knownReaders)).toEqual('reader-1') + expect(strategy.selectReader(knownReaders)).toEqual('reader-2') + expect(strategy.selectReader(knownReaders)).toEqual('reader-3') + }) it('should return writers in round robin order', () => { - const knownWriters = ['writer-1', 'writer-2', 'writer-3', 'writer-4']; - const strategy = new RoundRobinLoadBalancingStrategy(); - - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-2'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-3'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-1'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-2'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-3'); - expect(strategy.selectWriter(knownWriters)).toEqual('writer-4'); - }); + const knownWriters = ['writer-1', 'writer-2', 'writer-3', 'writer-4'] + const strategy = new RoundRobinLoadBalancingStrategy() -}); + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-2') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-3') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-1') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-2') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-3') + expect(strategy.selectWriter(knownWriters)).toEqual('writer-4') + }) +}) diff --git a/test/internal/routing-table.test.js b/test/internal/routing-table.test.js index 68d360847..09e394c2e 100644 --- a/test/internal/routing-table.test.js +++ b/test/internal/routing-table.test.js @@ -16,139 +16,200 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import RoutingTable from '../../src/v1/internal/routing-table'; -import {int} from '../../src/v1/integer'; -import {READ, WRITE} from '../../src/v1/driver'; -import ServerAddress from '../../src/v1/internal/server-address'; +import RoutingTable from '../../src/v1/internal/routing-table' +import { int } from '../../src/v1/integer' +import { READ, WRITE } from '../../src/v1/driver' +import ServerAddress from '../../src/v1/internal/server-address' describe('routing-table', () => { - const server1 = ServerAddress.fromUrl('server1'); - const server2 = ServerAddress.fromUrl('server2'); - const server3 = ServerAddress.fromUrl('server3'); - const server4 = ServerAddress.fromUrl('server4'); - const server5 = ServerAddress.fromUrl('server5'); - const server6 = ServerAddress.fromUrl('server6'); - const server7 = ServerAddress.fromUrl('server7'); - const server11 = ServerAddress.fromUrl('server11'); - const server22 = ServerAddress.fromUrl('server22'); - const server33 = ServerAddress.fromUrl('server33'); - const server44 = ServerAddress.fromUrl('server44'); - const server42 = ServerAddress.fromUrl('server42'); + const server1 = ServerAddress.fromUrl('server1') + const server2 = ServerAddress.fromUrl('server2') + const server3 = ServerAddress.fromUrl('server3') + const server4 = ServerAddress.fromUrl('server4') + const server5 = ServerAddress.fromUrl('server5') + const server6 = ServerAddress.fromUrl('server6') + const server42 = ServerAddress.fromUrl('server42') it('should not be stale when has routers, readers, writers and future expiration date', () => { - const table = createTable([server1, server2], [server3, server4], [server5, server6], notExpired()); - expect(table.isStaleFor(READ)).toBeFalsy(); - expect(table.isStaleFor(WRITE)).toBeFalsy(); - }); + const table = createTable( + [server1, server2], + [server3, server4], + [server5, server6], + notExpired() + ) + expect(table.isStaleFor(READ)).toBeFalsy() + expect(table.isStaleFor(WRITE)).toBeFalsy() + }) it('should be stale when expiration date in the past', () => { - const table = createTable([server1, server2], [server1, server2], [server1, server2], expired()); - expect(table.isStaleFor(READ)).toBeTruthy(); - expect(table.isStaleFor(WRITE)).toBeTruthy(); - }); + const table = createTable( + [server1, server2], + [server1, server2], + [server1, server2], + expired() + ) + expect(table.isStaleFor(READ)).toBeTruthy() + expect(table.isStaleFor(WRITE)).toBeTruthy() + }) it('should not be stale when has single router', () => { - const table = createTable([server1], [server2, server3], [server4, server5], notExpired()); - expect(table.isStaleFor(READ)).toBeFalsy(); - expect(table.isStaleFor(WRITE)).toBeFalsy(); - }); + const table = createTable( + [server1], + [server2, server3], + [server4, server5], + notExpired() + ) + expect(table.isStaleFor(READ)).toBeFalsy() + expect(table.isStaleFor(WRITE)).toBeFalsy() + }) it('should be stale for reads but not writes when no readers', () => { - const table = createTable([server1, server2], [], [server3, server4], notExpired()); - expect(table.isStaleFor(READ)).toBeTruthy(); - expect(table.isStaleFor(WRITE)).toBeFalsy(); - }); + const table = createTable( + [server1, server2], + [], + [server3, server4], + notExpired() + ) + expect(table.isStaleFor(READ)).toBeTruthy() + expect(table.isStaleFor(WRITE)).toBeFalsy() + }) it('should be stale for writes but not reads when no writers', () => { - const table = createTable([server1, server2], [server3, server4], [], notExpired()); - expect(table.isStaleFor(READ)).toBeFalsy(); - expect(table.isStaleFor(WRITE)).toBeTruthy(); - }); + const table = createTable( + [server1, server2], + [server3, server4], + [], + notExpired() + ) + expect(table.isStaleFor(READ)).toBeFalsy() + expect(table.isStaleFor(WRITE)).toBeTruthy() + }) it('should not be stale with single reader', () => { - const table = createTable([server1, server2], [server3], [server4, server5], notExpired()); - expect(table.isStaleFor(READ)).toBeFalsy(); - expect(table.isStaleFor(WRITE)).toBeFalsy(); - }); + const table = createTable( + [server1, server2], + [server3], + [server4, server5], + notExpired() + ) + expect(table.isStaleFor(READ)).toBeFalsy() + expect(table.isStaleFor(WRITE)).toBeFalsy() + }) it('should not be stale with single writer', () => { - const table = createTable([server1, server2], [server3, server4], [server5], notExpired()); - expect(table.isStaleFor(READ)).toBeFalsy(); - expect(table.isStaleFor(WRITE)).toBeFalsy(); - }); + const table = createTable( + [server1, server2], + [server3, server4], + [server5], + notExpired() + ) + expect(table.isStaleFor(READ)).toBeFalsy() + expect(table.isStaleFor(WRITE)).toBeFalsy() + }) it('should forget reader, writer but not router', () => { - const table = createTable([server1, server2], [server1, server2], [server1, server2], notExpired()); + const table = createTable( + [server1, server2], + [server1, server2], + [server1, server2], + notExpired() + ) - table.forget(server1); + table.forget(server1) - expect(table.routers).toEqual([server1, server2]); - expect(table.readers).toEqual([server2]); - expect(table.writers).toEqual([server2]); - }); + expect(table.routers).toEqual([server1, server2]) + expect(table.readers).toEqual([server2]) + expect(table.writers).toEqual([server2]) + }) it('should forget single reader', () => { - const table = createTable([server1, server2], [server42], [server1, server2, server3], notExpired()); + const table = createTable( + [server1, server2], + [server42], + [server1, server2, server3], + notExpired() + ) - table.forget(server42); + table.forget(server42) - expect(table.routers).toEqual([server1, server2]); - expect(table.readers).toEqual([]); - expect(table.writers).toEqual([server1, server2, server3]); - }); + expect(table.routers).toEqual([server1, server2]) + expect(table.readers).toEqual([]) + expect(table.writers).toEqual([server1, server2, server3]) + }) it('should forget single writer', () => { - const table = createTable([server1, server2], [server3, server4, server5], [server42], notExpired()); + const table = createTable( + [server1, server2], + [server3, server4, server5], + [server42], + notExpired() + ) - table.forget(server42); + table.forget(server42) - expect(table.routers).toEqual([server1, server2]); - expect(table.readers).toEqual([server3, server4, server5]); - expect(table.writers).toEqual([]); - }); + expect(table.routers).toEqual([server1, server2]) + expect(table.readers).toEqual([server3, server4, server5]) + expect(table.writers).toEqual([]) + }) it('should forget router', () => { - const table = createTable([server1, server2], [server1, server3], [server4, server1], notExpired()); + const table = createTable( + [server1, server2], + [server1, server3], + [server4, server1], + notExpired() + ) - table.forgetRouter(server1); + table.forgetRouter(server1) - expect(table.routers).toEqual([server2]); - expect(table.readers).toEqual([server1, server3]); - expect(table.writers).toEqual([server4, server1]); - }); + expect(table.routers).toEqual([server2]) + expect(table.readers).toEqual([server1, server3]) + expect(table.writers).toEqual([server4, server1]) + }) it('should forget writer', () => { - const table = createTable([server1, server2, server3], [server2, server1, server5], [server5, server1], notExpired()); + const table = createTable( + [server1, server2, server3], + [server2, server1, server5], + [server5, server1], + notExpired() + ) - table.forgetWriter(server1); + table.forgetWriter(server1) - expect(table.routers).toEqual([server1, server2, server3]); - expect(table.readers).toEqual([server2, server1, server5]); - expect(table.writers).toEqual([server5]); - }); + expect(table.routers).toEqual([server1, server2, server3]) + expect(table.readers).toEqual([server2, server1, server5]) + expect(table.writers).toEqual([server5]) + }) it('should have correct toString', () => { - const originalDateNow = Date.now; + const originalDateNow = Date.now try { - Date.now = () => 4242; - const table = createTable([server1, server2], [server3, server4], [server5, server6], 42); - expect(table.toString()).toEqual('RoutingTable[expirationTime=42, currentTime=4242, routers=[server1:7687,server2:7687], readers=[server3:7687,server4:7687], writers=[server5:7687,server6:7687]]'); + Date.now = () => 4242 + const table = createTable( + [server1, server2], + [server3, server4], + [server5, server6], + 42 + ) + expect(table.toString()).toEqual( + 'RoutingTable[expirationTime=42, currentTime=4242, routers=[server1:7687,server2:7687], readers=[server3:7687,server4:7687], writers=[server5:7687,server6:7687]]' + ) } finally { - Date.now = originalDateNow; + Date.now = originalDateNow } - }); + }) - function expired() { - return Date.now() - 3600; // expired an hour ago + function expired () { + return Date.now() - 3600 // expired an hour ago } - function notExpired() { - return Date.now() + 3600; // will expire in an hour + function notExpired () { + return Date.now() + 3600 // will expire in an hour } - function createTable(routers, readers, writers, expirationTime) { - const expiration = int(expirationTime); - return new RoutingTable(routers, readers, writers, expiration); + function createTable (routers, readers, writers, expirationTime) { + const expiration = int(expirationTime) + return new RoutingTable(routers, readers, writers, expiration) } - -}); +}) diff --git a/test/internal/routing-util.test.js b/test/internal/routing-util.test.js index 46c8cefd5..8e6f555d2 100644 --- a/test/internal/routing-util.test.js +++ b/test/internal/routing-util.test.js @@ -17,332 +17,410 @@ * limitations under the License. */ -import RoutingUtil from '../../src/v1/internal/routing-util'; -import Record from '../../src/v1/record'; -import Integer, {int} from '../../src/v1/integer'; -import {newError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../../src/v1/error'; -import lolex from 'lolex'; -import FakeConnection from './fake-connection'; -import ServerAddress from '../../src/v1/internal/server-address'; - -const ROUTER_ADDRESS = ServerAddress.fromUrl('test.router.com:4242'); +import RoutingUtil from '../../src/v1/internal/routing-util' +import Record from '../../src/v1/record' +import Integer, { int } from '../../src/v1/integer' +import { + newError, + PROTOCOL_ERROR, + SERVICE_UNAVAILABLE, + SESSION_EXPIRED +} from '../../src/v1/error' +import lolex from 'lolex' +import FakeConnection from './fake-connection' +import ServerAddress from '../../src/v1/internal/server-address' + +const ROUTER_ADDRESS = ServerAddress.fromUrl('test.router.com:4242') describe('RoutingUtil', () => { - - let clock; + let clock afterEach(() => { if (clock) { - clock.uninstall(); - clock = null; + clock.uninstall() + clock = null } - }); + }) it('should return retrieved records when query succeeds', done => { - const session = FakeSession.successful({records: ['foo', 'bar', 'baz']}); + const session = FakeSession.successful({ records: ['foo', 'bar', 'baz'] }) - callRoutingProcedure(session).then(records => { - expect(records).toEqual(['foo', 'bar', 'baz']); - done(); - }).catch(console.log); - }); + callRoutingProcedure(session) + .then(records => { + expect(records).toEqual(['foo', 'bar', 'baz']) + done() + }) + .catch(console.log) + }) it('should close session when query succeeds', done => { - const session = FakeSession.successful({records: ['foo', 'bar', 'baz']}); + const session = FakeSession.successful({ records: ['foo', 'bar', 'baz'] }) - callRoutingProcedure(session).then(() => { - expect(session.isClosed()).toBeTruthy(); - done(); - }).catch(console.log); - }); + callRoutingProcedure(session) + .then(() => { + expect(session.isClosed()).toBeTruthy() + done() + }) + .catch(console.log) + }) it('should not close session when query fails', done => { - const session = FakeSession.failed(newError('Oh no!', SESSION_EXPIRED)); + const session = FakeSession.failed(newError('Oh no!', SESSION_EXPIRED)) - callRoutingProcedure(session).then(() => { - expect(session.isClosed()).toBeFalsy(); - done(); - }).catch(console.log); - }); + callRoutingProcedure(session) + .then(() => { + expect(session.isClosed()).toBeFalsy() + done() + }) + .catch(console.log) + }) it('should return null on connection error', done => { - const session = FakeSession.failed(newError('Oh no!', SESSION_EXPIRED)); + const session = FakeSession.failed(newError('Oh no!', SESSION_EXPIRED)) - callRoutingProcedure(session).then(records => { - expect(records).toBeNull(); - done(); - }).catch(console.log); - }); + callRoutingProcedure(session) + .then(records => { + expect(records).toBeNull() + done() + }) + .catch(console.log) + }) it('should fail when procedure not found', done => { - const session = FakeSession.failed(newError('Oh no!', 'Neo.ClientError.Procedure.ProcedureNotFound')); + const session = FakeSession.failed( + newError('Oh no!', 'Neo.ClientError.Procedure.ProcedureNotFound') + ) callRoutingProcedure(session).catch(error => { - expect(error.code).toBe(SERVICE_UNAVAILABLE); - expect(error.message) - .toBe(`Server at ${ROUTER_ADDRESS} can't perform routing. Make sure you are connecting to a causal cluster`); - done(); - }); - }); + expect(error.code).toBe(SERVICE_UNAVAILABLE) + expect(error.message).toBe( + `Server at ${ROUTER_ADDRESS} can't perform routing. Make sure you are connecting to a causal cluster` + ) + done() + }) + }) it('should use getServers procedure when server version is older than 3.2.0', done => { - const connection = new FakeConnection().withServerVersion('Neo4j/3.1.9'); - const session = FakeSession.withFakeConnection(connection); + const connection = new FakeConnection().withServerVersion('Neo4j/3.1.9') + const session = FakeSession.withFakeConnection(connection) callRoutingProcedure(session, {}).then(() => { - expect(connection.seenStatements).toEqual(['CALL dbms.cluster.routing.getServers']); - expect(connection.seenParameters).toEqual([{}]); - done(); - }); - }); + expect(connection.seenStatements).toEqual([ + 'CALL dbms.cluster.routing.getServers' + ]) + expect(connection.seenParameters).toEqual([{}]) + done() + }) + }) it('should use getRoutingTable procedure with empty routing context when server version is 3.2.0', done => { - const connection = new FakeConnection().withServerVersion('Neo4j/3.2.0'); - const session = FakeSession.withFakeConnection(connection); + const connection = new FakeConnection().withServerVersion('Neo4j/3.2.0') + const session = FakeSession.withFakeConnection(connection) callRoutingProcedure(session, {}).then(() => { - expect(connection.seenStatements).toEqual(['CALL dbms.cluster.routing.getRoutingTable($context)']); - expect(connection.seenParameters).toEqual([{context: {}}]); - done(); - }); - }); + expect(connection.seenStatements).toEqual([ + 'CALL dbms.cluster.routing.getRoutingTable($context)' + ]) + expect(connection.seenParameters).toEqual([{ context: {} }]) + done() + }) + }) it('should use getRoutingTable procedure with routing context when server version is 3.2.0', done => { - const connection = new FakeConnection().withServerVersion('Neo4j/3.2.0'); - const session = FakeSession.withFakeConnection(connection); - - callRoutingProcedure(session, {key1: 'value1', key2: 'value2'}).then(() => { - expect(connection.seenStatements).toEqual(['CALL dbms.cluster.routing.getRoutingTable($context)']); - expect(connection.seenParameters).toEqual([{context: {key1: 'value1', key2: 'value2'}}]); - done(); - }); - }); + const connection = new FakeConnection().withServerVersion('Neo4j/3.2.0') + const session = FakeSession.withFakeConnection(connection) + + callRoutingProcedure(session, { key1: 'value1', key2: 'value2' }).then( + () => { + expect(connection.seenStatements).toEqual([ + 'CALL dbms.cluster.routing.getRoutingTable($context)' + ]) + expect(connection.seenParameters).toEqual([ + { context: { key1: 'value1', key2: 'value2' } } + ]) + done() + } + ) + }) it('should use getRoutingTable procedure with empty routing context when server version is newer than 3.2.0', done => { - const connection = new FakeConnection().withServerVersion('Neo4j/3.3.5'); - const session = FakeSession.withFakeConnection(connection); + const connection = new FakeConnection().withServerVersion('Neo4j/3.3.5') + const session = FakeSession.withFakeConnection(connection) callRoutingProcedure(session, {}).then(() => { - expect(connection.seenStatements).toEqual(['CALL dbms.cluster.routing.getRoutingTable($context)']); - expect(connection.seenParameters).toEqual([{context: {}}]); - done(); - }); - }); + expect(connection.seenStatements).toEqual([ + 'CALL dbms.cluster.routing.getRoutingTable($context)' + ]) + expect(connection.seenParameters).toEqual([{ context: {} }]) + done() + }) + }) it('should use getRoutingTable procedure with routing context when server version is newer than 3.2.0', done => { - const connection = new FakeConnection().withServerVersion('Neo4j/3.2.8'); - const session = FakeSession.withFakeConnection(connection); - - callRoutingProcedure(session, {key1: 'foo', key2: 'bar'}).then(() => { - expect(connection.seenStatements).toEqual(['CALL dbms.cluster.routing.getRoutingTable($context)']); - expect(connection.seenParameters).toEqual([{context: {key1: 'foo', key2: 'bar'}}]); - done(); - }); - }); + const connection = new FakeConnection().withServerVersion('Neo4j/3.2.8') + const session = FakeSession.withFakeConnection(connection) + + callRoutingProcedure(session, { key1: 'foo', key2: 'bar' }).then(() => { + expect(connection.seenStatements).toEqual([ + 'CALL dbms.cluster.routing.getRoutingTable($context)' + ]) + expect(connection.seenParameters).toEqual([ + { context: { key1: 'foo', key2: 'bar' } } + ]) + done() + }) + }) it('should parse valid ttl', () => { - clock = lolex.install(); + clock = lolex.install() - testValidTtlParsing(100, 5); - testValidTtlParsing(Date.now(), 3600); // 1 hour - testValidTtlParsing(Date.now(), 86400); // 24 hours - testValidTtlParsing(Date.now(), 3628800); // 42 days - testValidTtlParsing(0, 1); - testValidTtlParsing(50, 0); - testValidTtlParsing(Date.now(), 0); - }); + testValidTtlParsing(100, 5) + testValidTtlParsing(Date.now(), 3600) // 1 hour + testValidTtlParsing(Date.now(), 86400) // 24 hours + testValidTtlParsing(Date.now(), 3628800) // 42 days + testValidTtlParsing(0, 1) + testValidTtlParsing(50, 0) + testValidTtlParsing(Date.now(), 0) + }) it('should not overflow parsing huge ttl', () => { - const record = newRecord({ttl: Integer.MAX_VALUE}); - clock = lolex.install(); - clock.setSystemTime(42); + const record = newRecord({ ttl: Integer.MAX_VALUE }) + clock = lolex.install() + clock.setSystemTime(42) - const expirationTime = parseTtl(record); + const expirationTime = parseTtl(record) - expect(expirationTime).toBe(Integer.MAX_VALUE); - }); + expect(expirationTime).toBe(Integer.MAX_VALUE) + }) it('should return valid value parsing negative ttl', () => { - const record = newRecord({ttl: int(-42)}); - clock = lolex.install(); - clock.setSystemTime(42); + const record = newRecord({ ttl: int(-42) }) + clock = lolex.install() + clock.setSystemTime(42) - const expirationTime = parseTtl(record); + const expirationTime = parseTtl(record) - expect(expirationTime).toBe(Integer.MAX_VALUE); - }); + expect(expirationTime).toBe(Integer.MAX_VALUE) + }) it('should throw when record does not have a ttl entry', done => { - const record = new Record(["notTtl", "servers"], []); - expectProtocolError(() => parseTtl(record), done); - }); + const record = new Record(['notTtl', 'servers'], []) + expectProtocolError(() => parseTtl(record), done) + }) it('should parse servers', () => { - testValidServersParsing([], [], []); - - testValidServersParsing(['router1'], [], []); - testValidServersParsing([], ['reader1'], []); - testValidServersParsing([], [], ['writer1']); - - testValidServersParsing(['router1'], ['reader1'], []); - testValidServersParsing(['router1'], ['reader1'], ['writer1']); - testValidServersParsing([], ['reader1'], ['writer1']); - - testValidServersParsing(['router1'], ['reader1'], ['writer1']); - testValidServersParsing(['router1', 'router2'], ['reader1', 'reader2'], ['writer1']); - testValidServersParsing(['router1', 'router2'], ['reader1', 'reader2'], ['writer1', 'writer2']); - }); + testValidServersParsing([], [], []) + + testValidServersParsing(['router1'], [], []) + testValidServersParsing([], ['reader1'], []) + testValidServersParsing([], [], ['writer1']) + + testValidServersParsing(['router1'], ['reader1'], []) + testValidServersParsing(['router1'], ['reader1'], ['writer1']) + testValidServersParsing([], ['reader1'], ['writer1']) + + testValidServersParsing(['router1'], ['reader1'], ['writer1']) + testValidServersParsing( + ['router1', 'router2'], + ['reader1', 'reader2'], + ['writer1'] + ) + testValidServersParsing( + ['router1', 'router2'], + ['reader1', 'reader2'], + ['writer1', 'writer2'] + ) + }) it('should fail to parse servers entry when record does not have servers', done => { - const record = new Record(['ttl', 'notServers'], [int(42), [{"role": "READ", "addresses": ['1', '2', '3']}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'notServers'], + [int(42), [{ role: 'READ', addresses: ['1', '2', '3'] }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry without role', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"notRole": "READ", "addresses": ['1', '2', '3']}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ notRole: 'READ', addresses: ['1', '2', '3'] }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry with illegal role', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "ARBITER", "addresses": ['1', '2', '3']}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ role: 'ARBITER', addresses: ['1', '2', '3'] }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry with just ttl', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "READ"}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record(['ttl', 'servers'], [int(42), [{ role: 'READ' }]]) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry without addresses', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "WRITE", "notAddresses": ['1', '2', '3']}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ role: 'WRITE', notAddresses: ['1', '2', '3'] }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry with string addresses', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "WRITE", "addresses": ''}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ role: 'WRITE', addresses: '' }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry with null addresses', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "WRITE", "addresses": null}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ role: 'WRITE', addresses: null }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry with integer addresses', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "WRITE", "addresses": 12345}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ role: 'WRITE', addresses: 12345 }]] + ) + expectProtocolError(() => parseServers(record), done) + }) it('should fail to parse servers entry with object addresses', done => { - const record = new Record(['ttl', 'servers'], [int(42), [{"role": "WRITE", "addresses": {key: ['localhost']}}]]); - expectProtocolError(() => parseServers(record), done); - }); + const record = new Record( + ['ttl', 'servers'], + [int(42), [{ role: 'WRITE', addresses: { key: ['localhost'] } }]] + ) + expectProtocolError(() => parseServers(record), done) + }) - function testValidTtlParsing(currentTime, ttlSeconds) { - clock.setSystemTime(currentTime); - const expectedExpirationTime = currentTime + ttlSeconds * 1000; + function testValidTtlParsing (currentTime, ttlSeconds) { + clock.setSystemTime(currentTime) + const expectedExpirationTime = currentTime + ttlSeconds * 1000 // verify parsing when TTL is an Integer - const record1 = newRecord({ttl: int(ttlSeconds)}); - const expirationTime1 = parseTtl(record1).toNumber(); - expect(expirationTime1).toEqual(expectedExpirationTime); + const record1 = newRecord({ ttl: int(ttlSeconds) }) + const expirationTime1 = parseTtl(record1).toNumber() + expect(expirationTime1).toEqual(expectedExpirationTime) // verify parsing when TTL is a JavaScript Number, this can happen when driver is configured with {disableLosslessIntegers: true} - const record2 = newRecord({ttl: ttlSeconds}); - const expirationTime2 = parseTtl(record2).toNumber(); - expect(expirationTime2).toEqual(expectedExpirationTime); + const record2 = newRecord({ ttl: ttlSeconds }) + const expirationTime2 = parseTtl(record2).toNumber() + expect(expirationTime2).toEqual(expectedExpirationTime) } - function testValidServersParsing(routerAddresses, readerAddresses, writerAddresses) { - const record = newRecord({routers: routerAddresses, readers: readerAddresses, writers: writerAddresses}); - - const {routers, readers, writers} = parseServers(record); - - expect(routers).toEqual(routerAddresses.map(r => ServerAddress.fromUrl(r))); - expect(readers).toEqual(readerAddresses.map(r => ServerAddress.fromUrl(r))); - expect(writers).toEqual(writerAddresses.map(w => ServerAddress.fromUrl(w))); + function testValidServersParsing ( + routerAddresses, + readerAddresses, + writerAddresses + ) { + const record = newRecord({ + routers: routerAddresses, + readers: readerAddresses, + writers: writerAddresses + }) + + const { routers, readers, writers } = parseServers(record) + + expect(routers).toEqual(routerAddresses.map(r => ServerAddress.fromUrl(r))) + expect(readers).toEqual(readerAddresses.map(r => ServerAddress.fromUrl(r))) + expect(writers).toEqual(writerAddresses.map(w => ServerAddress.fromUrl(w))) } - function callRoutingProcedure(session, routingContext) { - const util = new RoutingUtil(routingContext || {}); - return util.callRoutingProcedure(session, ROUTER_ADDRESS); + function callRoutingProcedure (session, routingContext) { + const util = new RoutingUtil(routingContext || {}) + return util.callRoutingProcedure(session, ROUTER_ADDRESS) } - function parseTtl(record) { - const util = new RoutingUtil(); - return util.parseTtl(record, ROUTER_ADDRESS); + function parseTtl (record) { + const util = new RoutingUtil() + return util.parseTtl(record, ROUTER_ADDRESS) } - function parseServers(record) { - const util = new RoutingUtil(); - return util.parseServers(record, ROUTER_ADDRESS); + function parseServers (record) { + const util = new RoutingUtil() + return util.parseServers(record, ROUTER_ADDRESS) } - function newRecord({ttl = int(42), routers = [], readers = [], writers = []}) { + function newRecord ({ + ttl = int(42), + routers = [], + readers = [], + writers = [] + }) { const routersField = { - "role": "ROUTE", - "addresses": routers - }; + role: 'ROUTE', + addresses: routers + } const readersField = { - "role": "READ", - "addresses": readers - }; + role: 'READ', + addresses: readers + } const writersField = { - "role": "WRITE", - "addresses": writers - }; - return new Record(["ttl", "servers"], [ttl, [routersField, readersField, writersField]]); + role: 'WRITE', + addresses: writers + } + return new Record( + ['ttl', 'servers'], + [ttl, [routersField, readersField, writersField]] + ) } - function expectProtocolError(action, done) { + function expectProtocolError (action, done) { const promise = new Promise((resolve, reject) => { try { - resolve(action()); + resolve(action()) } catch (e) { - reject(e); + reject(e) } - }); + }) promise.catch(error => { - expect(error.code).toBe(PROTOCOL_ERROR); - done(); - }); + expect(error.code).toBe(PROTOCOL_ERROR) + done() + }) } class FakeSession { - - constructor(runResponse, fakeConnection) { - this._runResponse = runResponse; - this._fakeConnection = fakeConnection; - this._closed = false; + constructor (runResponse, fakeConnection) { + this._runResponse = runResponse + this._fakeConnection = fakeConnection + this._closed = false } - static successful(result) { - return new FakeSession(Promise.resolve(result), null); + static successful (result) { + return new FakeSession(Promise.resolve(result), null) } - static failed(error) { - return new FakeSession(Promise.reject(error), null); + static failed (error) { + return new FakeSession(Promise.reject(error), null) } - static withFakeConnection(connection) { - return new FakeSession(null, connection); + static withFakeConnection (connection) { + return new FakeSession(null, connection) } - _run(ignoreStatement, ignoreParameters, statementRunner) { + _run (ignoreStatement, ignoreParameters, statementRunner) { if (this._runResponse) { - return this._runResponse; + return this._runResponse } - statementRunner(this._fakeConnection); - return Promise.resolve(); + statementRunner(this._fakeConnection) + return Promise.resolve() } - close() { - this._closed = true; + close () { + this._closed = true } - isClosed() { - return this._closed; + isClosed () { + return this._closed } } -}); +}) diff --git a/test/internal/server-address.test.js b/test/internal/server-address.test.js index 050eb0853..d512a45e0 100644 --- a/test/internal/server-address.test.js +++ b/test/internal/server-address.test.js @@ -17,10 +17,9 @@ * limitations under the License. */ -import ServerAddress from '../../src/v1/internal/server-address'; +import ServerAddress from '../../src/v1/internal/server-address' describe('ServerAddress', () => { - it('should construct with correct values', () => { verifyAddress(ServerAddress.fromUrl('host.some.domain:8687'), { host: 'host.some.domain', @@ -28,7 +27,7 @@ describe('ServerAddress', () => { hostAndPort: 'host.some.domain:8687', key: 'host.some.domain:8687', toString: 'host.some.domain:8687' - }); + }) verifyAddress(ServerAddress.fromUrl('http://host.some.domain:8687'), { host: 'host.some.domain', @@ -36,7 +35,7 @@ describe('ServerAddress', () => { hostAndPort: 'host.some.domain:8687', key: 'host.some.domain:8687', toString: 'host.some.domain:8687' - }); + }) verifyAddress(ServerAddress.fromUrl('host2.some.domain'), { host: 'host2.some.domain', @@ -44,7 +43,7 @@ describe('ServerAddress', () => { hostAndPort: 'host2.some.domain:7687', key: 'host2.some.domain:7687', toString: 'host2.some.domain:7687' - }); + }) verifyAddress(ServerAddress.fromUrl('https://host2.some.domain'), { host: 'host2.some.domain', @@ -52,7 +51,7 @@ describe('ServerAddress', () => { hostAndPort: 'host2.some.domain:7473', key: 'host2.some.domain:7473', toString: 'host2.some.domain:7473' - }); + }) verifyAddress(ServerAddress.fromUrl('10.10.192.0'), { host: '10.10.192.0', @@ -60,7 +59,7 @@ describe('ServerAddress', () => { hostAndPort: '10.10.192.0:7687', key: '10.10.192.0:7687', toString: '10.10.192.0:7687' - }); + }) verifyAddress(ServerAddress.fromUrl('[1afc:0:a33:85a3::ff2f]:8889'), { host: '1afc:0:a33:85a3::ff2f', @@ -68,14 +67,13 @@ describe('ServerAddress', () => { hostAndPort: '[1afc:0:a33:85a3::ff2f]:8889', key: '[1afc:0:a33:85a3::ff2f]:8889', toString: '[1afc:0:a33:85a3::ff2f]:8889' - }); - - }); + }) + }) it('should return correct values when resolved', () => { - const address = ServerAddress.fromUrl('host.some.domain:8787'); - const resolved1 = address.resolveWith('172.0.0.1'); - const resolved2 = address.resolveWith('172.0.1.1'); + const address = ServerAddress.fromUrl('host.some.domain:8787') + const resolved1 = address.resolveWith('172.0.0.1') + const resolved2 = address.resolveWith('172.0.1.1') verifyAddress(resolved1, { host: 'host.some.domain', @@ -84,7 +82,7 @@ describe('ServerAddress', () => { key: 'host.some.domain:8787', toString: 'host.some.domain:8787(172.0.0.1)', resolvedHost: '172.0.0.1' - }); + }) verifyAddress(resolved2, { host: 'host.some.domain', @@ -93,13 +91,13 @@ describe('ServerAddress', () => { key: 'host.some.domain:8787', toString: 'host.some.domain:8787(172.0.1.1)', resolvedHost: '172.0.1.1' - }); - }); + }) + }) it('should not lose host info if resolved', () => { - const address = ServerAddress.fromUrl('host.some.domain:8787'); - const resolved1 = address.resolveWith('192.168.0.1'); - const resolved2 = resolved1.resolveWith('192.168.100.1'); + const address = ServerAddress.fromUrl('host.some.domain:8787') + const resolved1 = address.resolveWith('192.168.0.1') + const resolved2 = resolved1.resolveWith('192.168.100.1') verifyAddress(resolved2, { host: 'host.some.domain', @@ -108,15 +106,18 @@ describe('ServerAddress', () => { key: 'host.some.domain:8787', toString: 'host.some.domain:8787(192.168.100.1)', resolvedHost: '192.168.100.1' - }); - }); -}); + }) + }) +}) -function verifyAddress(address, { host, port, hostAndPort, key, toString, resolvedHost = null } = {}) { - expect(address.host()).toEqual(host); - expect(address.port()).toEqual(port); - expect(address.asHostPort()).toEqual(hostAndPort); - expect(address.asKey()).toEqual(key); - expect(address.toString()).toEqual(toString); - expect(address.resolvedHost()).toEqual(resolvedHost ? resolvedHost : host); +function verifyAddress ( + address, + { host, port, hostAndPort, key, toString, resolvedHost = null } = {} +) { + expect(address.host()).toEqual(host) + expect(address.port()).toEqual(port) + expect(address.asHostPort()).toEqual(hostAndPort) + expect(address.asKey()).toEqual(key) + expect(address.toString()).toEqual(toString) + expect(address.resolvedHost()).toEqual(resolvedHost || host) } diff --git a/test/internal/server-version.test.js b/test/internal/server-version.test.js index b88f38bed..b7c1245ac 100644 --- a/test/internal/server-version.test.js +++ b/test/internal/server-version.test.js @@ -17,142 +17,184 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import {ServerVersion, VERSION_3_2_0, VERSION_IN_DEV} from '../../src/v1/internal/server-version'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import { + ServerVersion, + VERSION_3_2_0, + VERSION_IN_DEV +} from '../../src/v1/internal/server-version' describe('ServerVersion', () => { - it('should construct with correct values', () => { - verifyVersion(new ServerVersion(2, 3, 10), 2, 3, 10); - verifyVersion(new ServerVersion(3, 2, 0), 3, 2, 0); - verifyVersion(new ServerVersion(1, 9, 12), 1, 9, 12); - }); + verifyVersion(new ServerVersion(2, 3, 10), 2, 3, 10) + verifyVersion(new ServerVersion(3, 2, 0), 3, 2, 0) + verifyVersion(new ServerVersion(1, 9, 12), 1, 9, 12) + }) it('should define correct 3.2.0 constant', () => { - verifyVersion(VERSION_3_2_0, 3, 2, 0); - }); + verifyVersion(VERSION_3_2_0, 3, 2, 0) + }) it('should parse "undefined" strings to 3.0.0 for backwards compatibility reasons', () => { - verifyVersion(parse(null), 3, 0, 0); - verifyVersion(parse(undefined), 3, 0, 0); - verifyVersion(parse(''), 3, 0, 0); - }); + verifyVersion(parse(null), 3, 0, 0) + verifyVersion(parse(undefined), 3, 0, 0) + verifyVersion(parse(''), 3, 0, 0) + }) it('should fail to parse object, array and function', () => { - expect(() => parse({})).toThrowError(TypeError); - expect(() => parse([])).toThrowError(TypeError); - expect(() => parse(() => { - })).toThrowError(TypeError); - }); + expect(() => parse({})).toThrowError(TypeError) + expect(() => parse([])).toThrowError(TypeError) + expect(() => parse(() => {})).toThrowError(TypeError) + }) it('should fail to parse illegal strings', () => { - expect(() => parse('Cat')).toThrow(); - expect(() => parse('Dog')).toThrow(); - expect(() => parse('Neo4j')).toThrow(); - expect(() => parse('Neo4j/')).toThrow(); - expect(() => parse('Not-Neo4j/3.1.0')).toThrow(); - expect(() => parse('Neo4j/5')).toThrow(); - expect(() => parse('Neo4j/3.')).toThrow(); - expect(() => parse('Neo4j/1.A')).toThrow(); - expect(() => parse('Neo4j/1.Hello')).toThrow(); - }); + expect(() => parse('Cat')).toThrow() + expect(() => parse('Dog')).toThrow() + expect(() => parse('Neo4j')).toThrow() + expect(() => parse('Neo4j/')).toThrow() + expect(() => parse('Not-Neo4j/3.1.0')).toThrow() + expect(() => parse('Neo4j/5')).toThrow() + expect(() => parse('Neo4j/3.')).toThrow() + expect(() => parse('Neo4j/1.A')).toThrow() + expect(() => parse('Neo4j/1.Hello')).toThrow() + }) it('should parse valid version strings', () => { - verifyVersion(parse('Neo4j/3.2.1'), 3, 2, 1); - verifyVersion(parse('Neo4j/1.9.10'), 1, 9, 10); - verifyVersion(parse('Neo4j/7.77.777'), 7, 77, 777); - - verifyVersion(parse('Neo4j/3.10.0-GA'), 3, 10, 0); - verifyVersion(parse('Neo4j/2.5.5-RC01'), 2, 5, 5); - verifyVersion(parse('Neo4j/3.1.1-SNAPSHOT'), 3, 1, 1); - verifyVersion(parse('Neo4j/2.0.0-M09'), 2, 0, 0); - - verifyVersion(parse('Neo4j/3.2'), 3, 2, 0); - verifyVersion(parse('Neo4j/1.5'), 1, 5, 0); - verifyVersion(parse('Neo4j/42.42'), 42, 42, 0); - - verifyVersion(parse('Neo4j/2.2-GA'), 2, 2, 0); - verifyVersion(parse('Neo4j/3.0-RC01'), 3, 0, 0); - verifyVersion(parse('Neo4j/2.3-SNAPSHOT'), 2, 3, 0); - verifyVersion(parse('Neo4j/2.2-M09'), 2, 2, 0); - - let maxVer = Number.MAX_SAFE_INTEGER; - verifyVersion(parse('Neo4j/dev'), maxVer, maxVer, maxVer); - verifyVersion(parse('Neo4j/DEV'), maxVer, maxVer, maxVer); - verifyVersion(parse('Neo4j/Dev'), maxVer, maxVer, maxVer); - }); + verifyVersion(parse('Neo4j/3.2.1'), 3, 2, 1) + verifyVersion(parse('Neo4j/1.9.10'), 1, 9, 10) + verifyVersion(parse('Neo4j/7.77.777'), 7, 77, 777) + + verifyVersion(parse('Neo4j/3.10.0-GA'), 3, 10, 0) + verifyVersion(parse('Neo4j/2.5.5-RC01'), 2, 5, 5) + verifyVersion(parse('Neo4j/3.1.1-SNAPSHOT'), 3, 1, 1) + verifyVersion(parse('Neo4j/2.0.0-M09'), 2, 0, 0) + + verifyVersion(parse('Neo4j/3.2'), 3, 2, 0) + verifyVersion(parse('Neo4j/1.5'), 1, 5, 0) + verifyVersion(parse('Neo4j/42.42'), 42, 42, 0) + + verifyVersion(parse('Neo4j/2.2-GA'), 2, 2, 0) + verifyVersion(parse('Neo4j/3.0-RC01'), 3, 0, 0) + verifyVersion(parse('Neo4j/2.3-SNAPSHOT'), 2, 3, 0) + verifyVersion(parse('Neo4j/2.2-M09'), 2, 2, 0) + + let maxVer = Number.MAX_SAFE_INTEGER + verifyVersion(parse('Neo4j/dev'), maxVer, maxVer, maxVer) + verifyVersion(parse('Neo4j/DEV'), maxVer, maxVer, maxVer) + verifyVersion(parse('Neo4j/Dev'), maxVer, maxVer, maxVer) + }) it('should fetch version using driver', done => { - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - ServerVersion.fromDriver(driver).then(version => { - driver.close(); - expect(version).not.toBeNull(); - expect(version).toBeDefined(); - expect(version instanceof ServerVersion).toBeTruthy(); - done(); - }).catch(error => { - driver.close(); - done.fail(error); - }); - }); + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + ServerVersion.fromDriver(driver) + .then(version => { + driver.close() + expect(version).not.toBeNull() + expect(version).toBeDefined() + expect(version instanceof ServerVersion).toBeTruthy() + done() + }) + .catch(error => { + driver.close() + done.fail(error) + }) + }) it('should fail to fetch version using incorrect driver', done => { - const driver = neo4j.driver('bolt://localhost:4242', sharedNeo4j.authToken); // use wrong port - ServerVersion.fromDriver(driver).then(version => { - driver.close(); - done.fail('Should not be able to fetch version: ' + JSON.stringify(version)); - }).catch(error => { - expect(error).not.toBeNull(); - expect(error).toBeDefined(); - driver.close(); - done(); - }); - }); + const driver = neo4j.driver('bolt://localhost:4242', sharedNeo4j.authToken) // use wrong port + ServerVersion.fromDriver(driver) + .then(version => { + driver.close() + done.fail( + 'Should not be able to fetch version: ' + JSON.stringify(version) + ) + }) + .catch(error => { + expect(error).not.toBeNull() + expect(error).toBeDefined() + driver.close() + done() + }) + }) it('should compare equal versions', () => { - expect(new ServerVersion(3, 1, 0).compareTo(new ServerVersion(3, 1, 0))).toEqual(0); - expect(new ServerVersion(1, 9, 12).compareTo(new ServerVersion(1, 9, 12))).toEqual(0); - expect(new ServerVersion(2, 3, 8).compareTo(new ServerVersion(2, 3, 8))).toEqual(0); - }); + expect( + new ServerVersion(3, 1, 0).compareTo(new ServerVersion(3, 1, 0)) + ).toEqual(0) + expect( + new ServerVersion(1, 9, 12).compareTo(new ServerVersion(1, 9, 12)) + ).toEqual(0) + expect( + new ServerVersion(2, 3, 8).compareTo(new ServerVersion(2, 3, 8)) + ).toEqual(0) + }) it('should compare correctly by major', () => { - expect(new ServerVersion(3, 1, 0).compareTo(new ServerVersion(2, 1, 0))).toBeGreaterThan(0); - expect(new ServerVersion(2, 1, 0).compareTo(new ServerVersion(3, 1, 0))).toBeLessThan(0); - - expect(new ServerVersion(3, 1, 4).compareTo(new ServerVersion(1, 9, 10))).toBeGreaterThan(0); - expect(new ServerVersion(1, 5, 42).compareTo(new ServerVersion(10, 10, 43))).toBeLessThan(0); - }); + expect( + new ServerVersion(3, 1, 0).compareTo(new ServerVersion(2, 1, 0)) + ).toBeGreaterThan(0) + expect( + new ServerVersion(2, 1, 0).compareTo(new ServerVersion(3, 1, 0)) + ).toBeLessThan(0) + + expect( + new ServerVersion(3, 1, 4).compareTo(new ServerVersion(1, 9, 10)) + ).toBeGreaterThan(0) + expect( + new ServerVersion(1, 5, 42).compareTo(new ServerVersion(10, 10, 43)) + ).toBeLessThan(0) + }) it('should compare correctly by minor', () => { - expect(new ServerVersion(3, 3, 0).compareTo(new ServerVersion(3, 1, 0))).toBeGreaterThan(0); - expect(new ServerVersion(1, 3, 5).compareTo(new ServerVersion(1, 9, 5))).toBeLessThan(0); - - expect(new ServerVersion(3, 9, 5).compareTo(new ServerVersion(3, 1, 2))).toBeGreaterThan(0); - expect(new ServerVersion(1, 5, 42).compareTo(new ServerVersion(1, 10, 11))).toBeLessThan(0); - }); + expect( + new ServerVersion(3, 3, 0).compareTo(new ServerVersion(3, 1, 0)) + ).toBeGreaterThan(0) + expect( + new ServerVersion(1, 3, 5).compareTo(new ServerVersion(1, 9, 5)) + ).toBeLessThan(0) + + expect( + new ServerVersion(3, 9, 5).compareTo(new ServerVersion(3, 1, 2)) + ).toBeGreaterThan(0) + expect( + new ServerVersion(1, 5, 42).compareTo(new ServerVersion(1, 10, 11)) + ).toBeLessThan(0) + }) it('should compare correctly by patch', () => { - expect(new ServerVersion(3, 3, 6).compareTo(new ServerVersion(3, 3, 5))).toBeGreaterThan(0); - expect(new ServerVersion(1, 8, 2).compareTo(new ServerVersion(1, 8, 8))).toBeLessThan(0); - expect(new ServerVersion(9, 9, 9).compareTo(new ServerVersion(9, 9, 0))).toBeGreaterThan(0); - expect(new ServerVersion(3, 3, 3).compareTo(new ServerVersion(3, 3, 42))).toBeLessThan(0); - }); + expect( + new ServerVersion(3, 3, 6).compareTo(new ServerVersion(3, 3, 5)) + ).toBeGreaterThan(0) + expect( + new ServerVersion(1, 8, 2).compareTo(new ServerVersion(1, 8, 8)) + ).toBeLessThan(0) + expect( + new ServerVersion(9, 9, 9).compareTo(new ServerVersion(9, 9, 0)) + ).toBeGreaterThan(0) + expect( + new ServerVersion(3, 3, 3).compareTo(new ServerVersion(3, 3, 42)) + ).toBeLessThan(0) + }) it('should compare dev version', () => { - expect(new ServerVersion(3, 1, 0).compareTo(VERSION_IN_DEV)).toBeLessThan(0); - expect(new ServerVersion(3, 3, 6).compareTo(VERSION_IN_DEV)).toBeLessThan(0); - expect(new ServerVersion(2, 3, 0).compareTo(VERSION_IN_DEV)).toBeLessThan(0); - }); - -}); - -function verifyVersion(serverVersion, expectedMajor, expectedMinor, expectedPatch) { - expect(serverVersion.major).toEqual(expectedMajor); - expect(serverVersion.minor).toEqual(expectedMinor); - expect(serverVersion.patch).toEqual(expectedPatch); + expect(new ServerVersion(3, 1, 0).compareTo(VERSION_IN_DEV)).toBeLessThan(0) + expect(new ServerVersion(3, 3, 6).compareTo(VERSION_IN_DEV)).toBeLessThan(0) + expect(new ServerVersion(2, 3, 0).compareTo(VERSION_IN_DEV)).toBeLessThan(0) + }) +}) + +function verifyVersion ( + serverVersion, + expectedMajor, + expectedMinor, + expectedPatch +) { + expect(serverVersion.major).toEqual(expectedMajor) + expect(serverVersion.minor).toEqual(expectedMinor) + expect(serverVersion.patch).toEqual(expectedPatch) } -function parse(string) { - return ServerVersion.fromString(string); +function parse (string) { + return ServerVersion.fromString(string) } diff --git a/test/internal/shared-neo4j.js b/test/internal/shared-neo4j.js index 17f4cc574..9a8a73824 100644 --- a/test/internal/shared-neo4j.js +++ b/test/internal/shared-neo4j.js @@ -17,88 +17,86 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; +import neo4j from '../../src/v1' class UnsupportedPlatform { - - pathJoin() { - throw new Error('Module \'path\' is not available on this platform'); + pathJoin () { + throw new Error("Module 'path' is not available on this platform") } - spawn(command, args) { - throw new Error('Module \'child_process\' is not available on this platform'); + spawn (command, args) { + throw new Error("Module 'child_process' is not available on this platform") } - listDir(path) { - throw new Error('Module \'fs\' is not available on this platform'); + listDir (path) { + throw new Error("Module 'fs' is not available on this platform") } - removeDir(path) { - throw new Error('Module \'fs\' is not available on this platform'); + removeDir (path) { + throw new Error("Module 'fs' is not available on this platform") } - isDirectory(path) { - throw new Error('Module \'fs\' is not available on this platform'); + isDirectory (path) { + throw new Error("Module 'fs' is not available on this platform") } } class SupportedPlatform extends UnsupportedPlatform { - - constructor() { - super(); - this._path = require('path'); - this._childProcess = require('child_process'); - this._fs = require('fs-extra'); + constructor () { + super() + this._path = require('path') + this._childProcess = require('child_process') + this._fs = require('fs-extra') } - static create() { + static create () { try { - return new SupportedPlatform(); + return new SupportedPlatform() } catch (e) { - return null; + return null } } - pathJoin() { - return this._path.join(...Array.from(arguments)); + pathJoin () { + return this._path.join(...Array.from(arguments)) } - spawn(command, args) { + spawn (command, args) { const options = { // ignore stdin, use default values for stdout and stderr // otherwise spawned java process does not see IPv6 address of the local interface and Neo4j fails to start // https://github.com/nodejs/node-v0.x-archive/issues/7406 stdio: ['ignore', null, null] - }; - return this._childProcess.spawnSync(command, args, options); + } + return this._childProcess.spawnSync(command, args, options) } - listDir(path) { - return this._fs.readdirSync(path); + listDir (path) { + return this._fs.readdirSync(path) } - removeDir(path) { + removeDir (path) { if (this.isDirectory(path)) { - this._fs.removeSync(path); + this._fs.removeSync(path) } } - isDirectory(path) { + isDirectory (path) { try { - this._fs.accessSync(path); - const stat = this._fs.statSync(path); - return stat.isDirectory(); + this._fs.accessSync(path) + const stat = this._fs.statSync(path) + return stat.isDirectory() } catch (e) { - return false; + return false } } } -const platform = SupportedPlatform.create() || new UnsupportedPlatform(); +const platform = SupportedPlatform.create() || new UnsupportedPlatform() -const username = 'neo4j'; -const password = 'password'; -const authToken = neo4j.auth.basic(username, password); +const username = 'neo4j' +const password = 'password' +const authToken = neo4j.auth.basic(username, password) const additionalConfig = { // tell neo4j to listen for IPv6 connections, only supported by 3.1+ @@ -114,168 +112,218 @@ const additionalConfig = { 'dbms.memory.pagecache.size': '512m' } -const neoCtrlVersionParam = '-e'; -const defaultNeo4jVersion = '3.5'; -const defaultNeoCtrlArgs = `${neoCtrlVersionParam} ${defaultNeo4jVersion}`; +const neoCtrlVersionParam = '-e' +const defaultNeo4jVersion = '3.5' +const defaultNeoCtrlArgs = `${neoCtrlVersionParam} ${defaultNeo4jVersion}` -function neo4jCertPath(dir) { - const neo4jDir = findExistingNeo4jDirStrict(dir); - return platform.pathJoin(neo4jDir, 'certificates', 'neo4j.cert'); +function neo4jCertPath (dir) { + const neo4jDir = findExistingNeo4jDirStrict(dir) + return platform.pathJoin(neo4jDir, 'certificates', 'neo4j.cert') } -function neo4jKeyPath(dir) { - const neo4jDir = findExistingNeo4jDirStrict(dir); - return platform.pathJoin(neo4jDir, 'certificates', 'neo4j.key'); +function neo4jKeyPath (dir) { + const neo4jDir = findExistingNeo4jDirStrict(dir) + return platform.pathJoin(neo4jDir, 'certificates', 'neo4j.key') } -function start(dir, givenNeoCtrlArgs) { - const boltKitCheckResult = runCommand('neoctrl-install', ['-h']); +function start (dir, givenNeoCtrlArgs) { + const boltKitCheckResult = runCommand('neoctrl-install', ['-h']) if (boltKitCheckResult.successful) { - const neo4jDir = installNeo4j(dir, givenNeoCtrlArgs); - configureNeo4j(neo4jDir); - createDefaultUser(neo4jDir); - startNeo4j(neo4jDir); + const neo4jDir = installNeo4j(dir, givenNeoCtrlArgs) + configureNeo4j(neo4jDir) + createDefaultUser(neo4jDir) + startNeo4j(neo4jDir) } else { - console.log('Boltkit unavailable. Please install it by running \'pip install --upgrade boltkit.'); - console.log('Integration tests will be skipped.'); - console.log('Command \'neoctrl-install -h\' resulted in\n' + boltKitCheckResult.fullOutput); + console.log( + "Boltkit unavailable. Please install it by running 'pip install --upgrade boltkit." + ) + console.log('Integration tests will be skipped.') + console.log( + "Command 'neoctrl-install -h' resulted in\n" + + boltKitCheckResult.fullOutput + ) } } -function stop(dir) { - const neo4jDir = findExistingNeo4jDirStrict(dir); - stopNeo4j(neo4jDir); +function stop (dir) { + const neo4jDir = findExistingNeo4jDirStrict(dir) + stopNeo4j(neo4jDir) } -function restart(dir) { - const neo4jDir = findExistingNeo4jDirStrict(dir); - stopNeo4j(neo4jDir); - startNeo4j(neo4jDir); +function restart (dir) { + const neo4jDir = findExistingNeo4jDirStrict(dir) + stopNeo4j(neo4jDir) + startNeo4j(neo4jDir) } -function installNeo4j(dir, givenNeoCtrlArgs) { - const neoCtrlArgs = givenNeoCtrlArgs || defaultNeoCtrlArgs; - const argsArray = neoCtrlArgs.split(' ').map(value => value.trim()); - argsArray.push(dir); +function installNeo4j (dir, givenNeoCtrlArgs) { + const neoCtrlArgs = givenNeoCtrlArgs || defaultNeoCtrlArgs + const argsArray = neoCtrlArgs.split(' ').map(value => value.trim()) + argsArray.push(dir) - const neo4jVersion = extractNeo4jVersion(argsArray); - const existingNeo4jDir = findExistingNeo4jDir(dir, neo4jVersion); + const neo4jVersion = extractNeo4jVersion(argsArray) + const existingNeo4jDir = findExistingNeo4jDir(dir, neo4jVersion) if (existingNeo4jDir) { - console.log('Found existing Neo4j ' + neo4jVersion + ' installation at: \'' + existingNeo4jDir + '\''); - return existingNeo4jDir; + console.log( + 'Found existing Neo4j ' + + neo4jVersion + + " installation at: '" + + existingNeo4jDir + + "'" + ) + return existingNeo4jDir } else { - platform.removeDir(dir); + platform.removeDir(dir) - console.log('Installing Neo4j with neoctrl arguments: \'' + neoCtrlArgs + '\''); - const result = runCommand('neoctrl-install', argsArray); + console.log( + "Installing Neo4j with neoctrl arguments: '" + neoCtrlArgs + "'" + ) + const result = runCommand('neoctrl-install', argsArray) if (!result.successful) { - throw new Error('Unable to install Neo4j.\n' + result.fullOutput); + throw new Error('Unable to install Neo4j.\n' + result.fullOutput) } - const installedNeo4jDir = result.stdout; - console.log('Installed Neo4j to: \'' + installedNeo4jDir + '\''); - return installedNeo4jDir; + const installedNeo4jDir = result.stdout + console.log("Installed Neo4j to: '" + installedNeo4jDir + "'") + return installedNeo4jDir } } -function configureNeo4j(neo4jDir) { - console.log('Configuring Neo4j at: \'' + neo4jDir + '\' with ' + JSON.stringify(additionalConfig)); - - const configEntries = Object.keys(additionalConfig).map(key => `${key}=${additionalConfig[key]}`); - const configureResult = runCommand('neoctrl-configure', [neo4jDir, ...configEntries]); +function configureNeo4j (neo4jDir) { + console.log( + "Configuring Neo4j at: '" + + neo4jDir + + "' with " + + JSON.stringify(additionalConfig) + ) + + const configEntries = Object.keys(additionalConfig).map( + key => `${key}=${additionalConfig[key]}` + ) + const configureResult = runCommand('neoctrl-configure', [ + neo4jDir, + ...configEntries + ]) if (!configureResult.successful) { - throw new Error('Unable to configure Neo4j.\n' + configureResult.fullOutput); + throw new Error('Unable to configure Neo4j.\n' + configureResult.fullOutput) } - console.log('Configured Neo4j at: \'' + neo4jDir + '\''); + console.log("Configured Neo4j at: '" + neo4jDir + "'") } -function createDefaultUser(neo4jDir) { - console.log('Creating user \'' + username + '\' for Neo4j at: \'' + neo4jDir + '\''); - const result = runCommand('neoctrl-create-user', [neo4jDir, username, password]); +function createDefaultUser (neo4jDir) { + console.log( + "Creating user '" + username + "' for Neo4j at: '" + neo4jDir + "'" + ) + const result = runCommand('neoctrl-create-user', [ + neo4jDir, + username, + password + ]) if (!result.successful) { - throw new Error('Unable to create user: \'' + username + '\' for Neo4j at: ' + neo4jDir + '\'\n' + result.fullOutput); + throw new Error( + "Unable to create user: '" + + username + + "' for Neo4j at: " + + neo4jDir + + "'\n" + + result.fullOutput + ) } - console.log('Created user \'' + username + '\' for Neo4j at: \'' + neo4jDir + '\''); + console.log( + "Created user '" + username + "' for Neo4j at: '" + neo4jDir + "'" + ) } -function startNeo4j(neo4jDir) { - console.log('Starting Neo4j at: \'' + neo4jDir + '\''); - const result = runCommand('neoctrl-start', [neo4jDir]); +function startNeo4j (neo4jDir) { + console.log("Starting Neo4j at: '" + neo4jDir + "'") + const result = runCommand('neoctrl-start', [neo4jDir]) if (!result.successful) { - throw new Error('Unable to start Neo4j.\n' + result.fullOutput); + throw new Error('Unable to start Neo4j.\n' + result.fullOutput) } - console.log('Started Neo4j at: \'' + neo4jDir + '\''); + console.log("Started Neo4j at: '" + neo4jDir + "'") } -function stopNeo4j(neo4jDir) { - console.log('Stopping Neo4j at: \'' + neo4jDir + '\''); - const result = runCommand('neoctrl-stop', [neo4jDir]); +function stopNeo4j (neo4jDir) { + console.log("Stopping Neo4j at: '" + neo4jDir + "'") + const result = runCommand('neoctrl-stop', [neo4jDir]) if (!result.successful) { - throw new Error('Unable to stop Neo4j at: \'' + neo4jDir + '\'\n' + result.fullOutput); + throw new Error( + "Unable to stop Neo4j at: '" + neo4jDir + "'\n" + result.fullOutput + ) } } -function findExistingNeo4jDirStrict(dir) { - const neo4jDir = findExistingNeo4jDir(dir, null); +function findExistingNeo4jDirStrict (dir) { + const neo4jDir = findExistingNeo4jDir(dir, null) if (!neo4jDir) { - throw new Error(`Unable to find Neo4j dir in: '${dir}'`); + throw new Error(`Unable to find Neo4j dir in: '${dir}'`) } - return neo4jDir; + return neo4jDir } -function findExistingNeo4jDir(dir, neo4jVersion) { +function findExistingNeo4jDir (dir, neo4jVersion) { if (!platform.isDirectory(dir)) { - return null; + return null } - const dirs = platform.listDir(dir).filter(entry => isNeo4jDir(entry, neo4jVersion)) + const dirs = platform + .listDir(dir) + .filter(entry => isNeo4jDir(entry, neo4jVersion)) .map(entry => platform.pathJoin(dir, entry)) - .filter(entry => platform.isDirectory(entry)); + .filter(entry => platform.isDirectory(entry)) - return dirs.length === 1 ? dirs[0] : null; + return dirs.length === 1 ? dirs[0] : null } -function isNeo4jDir(name, version) { +function isNeo4jDir (name, version) { if (!name.startsWith('neo4j')) { - return false; + return false } if (version && name.indexOf(version) === -1) { - return false; + return false } - return true; + return true } -function extractNeo4jVersion(neoCtrlArgs) { - const index = neoCtrlArgs.indexOf(neoCtrlVersionParam); +function extractNeo4jVersion (neoCtrlArgs) { + const index = neoCtrlArgs.indexOf(neoCtrlVersionParam) if (index === -1) { - throw new Error(`No '${neoCtrlVersionParam}' parameter`); + throw new Error(`No '${neoCtrlVersionParam}' parameter`) } - const version = neoCtrlArgs[index + 1]; + const version = neoCtrlArgs[index + 1] if (!version) { - throw new Error(`Version is undefined in: ${neoCtrlArgs}`); + throw new Error(`Version is undefined in: ${neoCtrlArgs}`) } - return version.trim(); + return version.trim() } -function runCommand(command, args) { - const spawnResult = platform.spawn(command, args); - return new RunCommandResult(spawnResult); +function runCommand (command, args) { + const spawnResult = platform.spawn(command, args) + return new RunCommandResult(spawnResult) } class RunCommandResult { - - constructor(spawnResult) { - this.successful = spawnResult.status === 0; - this.stdout = (spawnResult.stdout || '').toString().trim(); - this.stderr = (spawnResult.stderr || '').toString().trim(); - this.fullOutput = 'STDOUT:\n\t' + this.stdout + '\n' + - 'STDERR:\n\t' + this.stderr + '\n' + - 'EXIT CODE:\n\t' + spawnResult.status + '\n' + - 'ERROR:\n\t' + spawnResult.error + '\n'; + constructor (spawnResult) { + this.successful = spawnResult.status === 0 + this.stdout = (spawnResult.stdout || '').toString().trim() + this.stderr = (spawnResult.stderr || '').toString().trim() + this.fullOutput = + 'STDOUT:\n\t' + + this.stdout + + '\n' + + 'STDERR:\n\t' + + this.stderr + + '\n' + + 'EXIT CODE:\n\t' + + spawnResult.status + + '\n' + + 'ERROR:\n\t' + + spawnResult.error + + '\n' } } @@ -288,4 +336,4 @@ export default { username: username, password: password, authToken: authToken -}; +} diff --git a/test/internal/stream-observer.test.js b/test/internal/stream-observer.test.js index 84f367539..79d9be496 100644 --- a/test/internal/stream-observer.test.js +++ b/test/internal/stream-observer.test.js @@ -17,183 +17,192 @@ * limitations under the License. */ -import StreamObserver from '../../src/v1/internal/stream-observer'; -import FakeConnection from './fake-connection'; +import StreamObserver from '../../src/v1/internal/stream-observer' +import FakeConnection from './fake-connection' -const NO_OP = () => { -}; +const NO_OP = () => {} describe('StreamObserver', () => { - it('remembers resolved connection', () => { - const streamObserver = newStreamObserver(); - const connection = new FakeConnection(); + const streamObserver = newStreamObserver() + const connection = new FakeConnection() - streamObserver.resolveConnection(connection); + streamObserver.resolveConnection(connection) - expect(streamObserver._conn).toBe(connection); - }); + expect(streamObserver._conn).toBe(connection) + }) it('remembers subscriber', () => { - const streamObserver = newStreamObserver(); - const subscriber = newObserver(); + const streamObserver = newStreamObserver() + const subscriber = newObserver() - streamObserver.subscribe(subscriber); + streamObserver.subscribe(subscriber) - expect(streamObserver._observer).toBe(subscriber); - }); + expect(streamObserver._observer).toBe(subscriber) + }) it('passes received records to the subscriber', () => { - const streamObserver = newStreamObserver(); - const receivedRecords = []; + const streamObserver = newStreamObserver() + const receivedRecords = [] const observer = newObserver(record => { - receivedRecords.push(record); - }); + receivedRecords.push(record) + }) - streamObserver.subscribe(observer); - streamObserver.onCompleted({fields: ['A', 'B', 'C']}); + streamObserver.subscribe(observer) + streamObserver.onCompleted({ fields: ['A', 'B', 'C'] }) - streamObserver.onNext([1, 2, 3]); - streamObserver.onNext([11, 22, 33]); - streamObserver.onNext([111, 222, 333]); + streamObserver.onNext([1, 2, 3]) + streamObserver.onNext([11, 22, 33]) + streamObserver.onNext([111, 222, 333]) - expect(receivedRecords.length).toEqual(3); - expect(receivedRecords[0].toObject()).toEqual({'A': 1, 'B': 2, 'C': 3}); - expect(receivedRecords[1].toObject()).toEqual({'A': 11, 'B': 22, 'C': 33}); - expect(receivedRecords[2].toObject()).toEqual({'A': 111, 'B': 222, 'C': 333}); - }); + expect(receivedRecords.length).toEqual(3) + expect(receivedRecords[0].toObject()).toEqual({ A: 1, B: 2, C: 3 }) + expect(receivedRecords[1].toObject()).toEqual({ A: 11, B: 22, C: 33 }) + expect(receivedRecords[2].toObject()).toEqual({ A: 111, B: 222, C: 333 }) + }) it('queues received record when no subscriber', () => { - const streamObserver = newStreamObserver(); + const streamObserver = newStreamObserver() - streamObserver.onCompleted({fields: ['A', 'B', 'C']}); + streamObserver.onCompleted({ fields: ['A', 'B', 'C'] }) - streamObserver.onNext([1111, 2222, 3333]); - streamObserver.onNext([111, 222, 333]); - streamObserver.onNext([11, 22, 33]); - streamObserver.onNext([1, 2, 3]); + streamObserver.onNext([1111, 2222, 3333]) + streamObserver.onNext([111, 222, 333]) + streamObserver.onNext([11, 22, 33]) + streamObserver.onNext([1, 2, 3]) - const queuedRecords = streamObserver._queuedRecords; + const queuedRecords = streamObserver._queuedRecords - expect(queuedRecords.length).toEqual(4); - expect(queuedRecords[0].toObject()).toEqual({'A': 1111, 'B': 2222, 'C': 3333}); - expect(queuedRecords[1].toObject()).toEqual({'A': 111, 'B': 222, 'C': 333}); - expect(queuedRecords[2].toObject()).toEqual({'A': 11, 'B': 22, 'C': 33}); - expect(queuedRecords[3].toObject()).toEqual({'A': 1, 'B': 2, 'C': 3}); - }); + expect(queuedRecords.length).toEqual(4) + expect(queuedRecords[0].toObject()).toEqual({ A: 1111, B: 2222, C: 3333 }) + expect(queuedRecords[1].toObject()).toEqual({ A: 111, B: 222, C: 333 }) + expect(queuedRecords[2].toObject()).toEqual({ A: 11, B: 22, C: 33 }) + expect(queuedRecords[3].toObject()).toEqual({ A: 1, B: 2, C: 3 }) + }) it('passes received error the subscriber', () => { - const streamObserver = newStreamObserver(); - const error = new Error('Invalid Cypher statement'); + const streamObserver = newStreamObserver() + const error = new Error('Invalid Cypher statement') - let receivedError = null; + let receivedError = null const observer = newObserver(NO_OP, error => { - receivedError = error; - }); + receivedError = error + }) - streamObserver.subscribe(observer); - streamObserver.onError(error); + streamObserver.subscribe(observer) + streamObserver.onError(error) - expect(receivedError).toBe(error); - }); + expect(receivedError).toBe(error) + }) it('passes existing error to a new subscriber', () => { - const streamObserver = newStreamObserver(); - const error = new Error('Invalid Cypher statement'); + const streamObserver = newStreamObserver() + const error = new Error('Invalid Cypher statement') - streamObserver.onError(error); + streamObserver.onError(error) - streamObserver.subscribe(newObserver(NO_OP, receivedError => { - expect(receivedError).toBe(error); - })); - }); + streamObserver.subscribe( + newObserver(NO_OP, receivedError => { + expect(receivedError).toBe(error) + }) + ) + }) it('passes queued records to a new subscriber', () => { - const streamObserver = newStreamObserver(); + const streamObserver = newStreamObserver() - streamObserver.onCompleted({fields: ['A', 'B', 'C']}); + streamObserver.onCompleted({ fields: ['A', 'B', 'C'] }) - streamObserver.onNext([1, 2, 3]); - streamObserver.onNext([11, 22, 33]); - streamObserver.onNext([111, 222, 333]); + streamObserver.onNext([1, 2, 3]) + streamObserver.onNext([11, 22, 33]) + streamObserver.onNext([111, 222, 333]) - const receivedRecords = []; - streamObserver.subscribe(newObserver(record => { - receivedRecords.push(record); - })); + const receivedRecords = [] + streamObserver.subscribe( + newObserver(record => { + receivedRecords.push(record) + }) + ) - expect(receivedRecords.length).toEqual(3); - expect(receivedRecords[0].toObject()).toEqual({'A': 1, 'B': 2, 'C': 3}); - expect(receivedRecords[1].toObject()).toEqual({'A': 11, 'B': 22, 'C': 33}); - expect(receivedRecords[2].toObject()).toEqual({'A': 111, 'B': 222, 'C': 333}); - }); + expect(receivedRecords.length).toEqual(3) + expect(receivedRecords[0].toObject()).toEqual({ A: 1, B: 2, C: 3 }) + expect(receivedRecords[1].toObject()).toEqual({ A: 11, B: 22, C: 33 }) + expect(receivedRecords[2].toObject()).toEqual({ A: 111, B: 222, C: 333 }) + }) it('passes existing metadata to a new subscriber', () => { - const streamObserver = newStreamObserver(); - - streamObserver.onCompleted({fields: ['Foo', 'Bar', 'Baz', 'Qux']}); - streamObserver.onCompleted({metaDataField1: 'value1', metaDataField2: 'value2'}); - - let receivedMetaData = null; - streamObserver.subscribe(newObserver(NO_OP, NO_OP, metaData => { - receivedMetaData = metaData; - })); - - expect(receivedMetaData).toEqual({metaDataField1: 'value1', metaDataField2: 'value2'}); - }); + const streamObserver = newStreamObserver() + + streamObserver.onCompleted({ fields: ['Foo', 'Bar', 'Baz', 'Qux'] }) + streamObserver.onCompleted({ + metaDataField1: 'value1', + metaDataField2: 'value2' + }) + + let receivedMetaData = null + streamObserver.subscribe( + newObserver(NO_OP, NO_OP, metaData => { + receivedMetaData = metaData + }) + ) + + expect(receivedMetaData).toEqual({ + metaDataField1: 'value1', + metaDataField2: 'value2' + }) + }) it('invokes subscribed observer only once of error', () => { - const errors = []; - const streamObserver = new StreamObserver(); + const errors = [] + const streamObserver = new StreamObserver() streamObserver.subscribe({ onError: error => errors.push(error) - }); + }) - const error1 = new Error('Hello'); - const error2 = new Error('World'); + const error1 = new Error('Hello') + const error2 = new Error('World') - streamObserver.onError(error1); - streamObserver.onError(error2); + streamObserver.onError(error1) + streamObserver.onError(error2) - expect(errors).toEqual([error1]); - }); + expect(errors).toEqual([error1]) + }) it('should be able to handle a single response', done => { - const streamObserver = new StreamObserver(); - streamObserver.prepareToHandleSingleResponse(); + const streamObserver = new StreamObserver() + streamObserver.prepareToHandleSingleResponse() streamObserver.subscribe({ onCompleted: metadata => { - expect(metadata.key).toEqual(42); - done(); + expect(metadata.key).toEqual(42) + done() } - }); + }) - streamObserver.onCompleted({key: 42}); - }); + streamObserver.onCompleted({ key: 42 }) + }) it('should mark as completed', done => { - const streamObserver = new StreamObserver(); - streamObserver.markCompleted(); + const streamObserver = new StreamObserver() + streamObserver.markCompleted() streamObserver.subscribe({ onCompleted: metadata => { - expect(metadata).toEqual({}); - done(); + expect(metadata).toEqual({}) + done() } - }); - }); - -}); + }) + }) +}) -function newStreamObserver() { - return new StreamObserver(); +function newStreamObserver () { + return new StreamObserver() } -function newObserver(onNext = NO_OP, onError = NO_OP, onCompleted = NO_OP) { +function newObserver (onNext = NO_OP, onError = NO_OP, onCompleted = NO_OP) { return { onNext: onNext, onError: onError, onCompleted: onCompleted - }; + } } diff --git a/test/internal/temporal-util.test.js b/test/internal/temporal-util.test.js index 543696bd5..028f6eba5 100644 --- a/test/internal/temporal-util.test.js +++ b/test/internal/temporal-util.test.js @@ -17,319 +17,444 @@ * limitations under the License. */ -import {int} from '../../src/v1/integer'; -import * as util from '../../src/v1/internal/temporal-util'; -import {types} from '../../src/v1'; -import testUtils from './test-utils'; +import { int } from '../../src/v1/integer' +import * as util from '../../src/v1/internal/temporal-util' +import { types } from '../../src/v1' +import testUtils from './test-utils' describe('temporal-util', () => { - it('should normalize seconds for duration', () => { - expect(util.normalizeSecondsForDuration(1, 0)).toEqual(int(1)); - expect(util.normalizeSecondsForDuration(3, 0)).toEqual(int(3)); - expect(util.normalizeSecondsForDuration(424242, 0)).toEqual(int(424242)); + expect(util.normalizeSecondsForDuration(1, 0)).toEqual(int(1)) + expect(util.normalizeSecondsForDuration(3, 0)).toEqual(int(3)) + expect(util.normalizeSecondsForDuration(424242, 0)).toEqual(int(424242)) - expect(util.normalizeSecondsForDuration(-1, 0)).toEqual(int(-1)); - expect(util.normalizeSecondsForDuration(-9, 0)).toEqual(int(-9)); - expect(util.normalizeSecondsForDuration(-42, 0)).toEqual(int(-42)); + expect(util.normalizeSecondsForDuration(-1, 0)).toEqual(int(-1)) + expect(util.normalizeSecondsForDuration(-9, 0)).toEqual(int(-9)) + expect(util.normalizeSecondsForDuration(-42, 0)).toEqual(int(-42)) - expect(util.normalizeSecondsForDuration(1, 19)).toEqual(int(1)); - expect(util.normalizeSecondsForDuration(42, 42)).toEqual(int(42)); - expect(util.normalizeSecondsForDuration(12345, 6789)).toEqual(int(12345)); + expect(util.normalizeSecondsForDuration(1, 19)).toEqual(int(1)) + expect(util.normalizeSecondsForDuration(42, 42)).toEqual(int(42)) + expect(util.normalizeSecondsForDuration(12345, 6789)).toEqual(int(12345)) - expect(util.normalizeSecondsForDuration(-1, 42)).toEqual(int(-1)); - expect(util.normalizeSecondsForDuration(-42, 4242)).toEqual(int(-42)); - expect(util.normalizeSecondsForDuration(-123, 999)).toEqual(int(-123)); + expect(util.normalizeSecondsForDuration(-1, 42)).toEqual(int(-1)) + expect(util.normalizeSecondsForDuration(-42, 4242)).toEqual(int(-42)) + expect(util.normalizeSecondsForDuration(-123, 999)).toEqual(int(-123)) - expect(util.normalizeSecondsForDuration(1, 1000000000)).toEqual(int(2)); - expect(util.normalizeSecondsForDuration(40, 2000000001)).toEqual(int(42)); - expect(util.normalizeSecondsForDuration(583, 7999999999)).toEqual(int(590)); + expect(util.normalizeSecondsForDuration(1, 1000000000)).toEqual(int(2)) + expect(util.normalizeSecondsForDuration(40, 2000000001)).toEqual(int(42)) + expect(util.normalizeSecondsForDuration(583, 7999999999)).toEqual(int(590)) - expect(util.normalizeSecondsForDuration(1, -1000000000)).toEqual(int(0)); - expect(util.normalizeSecondsForDuration(1, -5000000000)).toEqual(int(-4)); - expect(util.normalizeSecondsForDuration(85, -42000000123)).toEqual(int(42)); + expect(util.normalizeSecondsForDuration(1, -1000000000)).toEqual(int(0)) + expect(util.normalizeSecondsForDuration(1, -5000000000)).toEqual(int(-4)) + expect(util.normalizeSecondsForDuration(85, -42000000123)).toEqual(int(42)) - expect(util.normalizeSecondsForDuration(-19, -1000000000)).toEqual(int(-20)); - expect(util.normalizeSecondsForDuration(-19, -11123456789)).toEqual(int(-31)); - expect(util.normalizeSecondsForDuration(-42, -2000000001)).toEqual(int(-45)); - }); + expect(util.normalizeSecondsForDuration(-19, -1000000000)).toEqual(int(-20)) + expect(util.normalizeSecondsForDuration(-19, -11123456789)).toEqual( + int(-31) + ) + expect(util.normalizeSecondsForDuration(-42, -2000000001)).toEqual(int(-45)) + }) it('should normalize nanoseconds for duration', () => { - expect(util.normalizeNanosecondsForDuration(0)).toEqual(int(0)); - - expect(util.normalizeNanosecondsForDuration(1)).toEqual(int(1)); - expect(util.normalizeNanosecondsForDuration(42)).toEqual(int(42)); - expect(util.normalizeNanosecondsForDuration(123456789)).toEqual(int(123456789)); - expect(util.normalizeNanosecondsForDuration(999999999)).toEqual(int(999999999)); - - expect(util.normalizeNanosecondsForDuration(1000000000)).toEqual(int(0)); - expect(util.normalizeNanosecondsForDuration(1000000001)).toEqual(int(1)); - expect(util.normalizeNanosecondsForDuration(1000000042)).toEqual(int(42)); - expect(util.normalizeNanosecondsForDuration(1123456789)).toEqual(int(123456789)); - expect(util.normalizeNanosecondsForDuration(42999999999)).toEqual(int(999999999)); - - expect(util.normalizeNanosecondsForDuration(-1)).toEqual(int(999999999)); - expect(util.normalizeNanosecondsForDuration(-3)).toEqual(int(999999997)); - expect(util.normalizeNanosecondsForDuration(-100)).toEqual(int(999999900)); - expect(util.normalizeNanosecondsForDuration(-999999999)).toEqual(int(1)); - expect(util.normalizeNanosecondsForDuration(-1999999999)).toEqual(int(1)); - expect(util.normalizeNanosecondsForDuration(-1123456789)).toEqual(int(876543211)); - }); + expect(util.normalizeNanosecondsForDuration(0)).toEqual(int(0)) + + expect(util.normalizeNanosecondsForDuration(1)).toEqual(int(1)) + expect(util.normalizeNanosecondsForDuration(42)).toEqual(int(42)) + expect(util.normalizeNanosecondsForDuration(123456789)).toEqual( + int(123456789) + ) + expect(util.normalizeNanosecondsForDuration(999999999)).toEqual( + int(999999999) + ) + + expect(util.normalizeNanosecondsForDuration(1000000000)).toEqual(int(0)) + expect(util.normalizeNanosecondsForDuration(1000000001)).toEqual(int(1)) + expect(util.normalizeNanosecondsForDuration(1000000042)).toEqual(int(42)) + expect(util.normalizeNanosecondsForDuration(1123456789)).toEqual( + int(123456789) + ) + expect(util.normalizeNanosecondsForDuration(42999999999)).toEqual( + int(999999999) + ) + + expect(util.normalizeNanosecondsForDuration(-1)).toEqual(int(999999999)) + expect(util.normalizeNanosecondsForDuration(-3)).toEqual(int(999999997)) + expect(util.normalizeNanosecondsForDuration(-100)).toEqual(int(999999900)) + expect(util.normalizeNanosecondsForDuration(-999999999)).toEqual(int(1)) + expect(util.normalizeNanosecondsForDuration(-1999999999)).toEqual(int(1)) + expect(util.normalizeNanosecondsForDuration(-1123456789)).toEqual( + int(876543211) + ) + }) it('should convert date to ISO string', () => { - expect(util.dateToIsoString(90, 2, 5)).toEqual('0090-02-05'); - expect(util.dateToIsoString(int(1), 1, int(1))).toEqual('0001-01-01'); - expect(util.dateToIsoString(-123, int(12), int(23))).toEqual('-0123-12-23'); - expect(util.dateToIsoString(int(-999), int(9), int(10))).toEqual('-0999-09-10'); - expect(util.dateToIsoString(1999, 12, 19)).toEqual('1999-12-19'); - expect(util.dateToIsoString(int(2023), int(8), int(16))).toEqual('2023-08-16'); - expect(util.dateToIsoString(12345, 12, 31)).toEqual('12345-12-31'); - expect(util.dateToIsoString(int(19191919), int(11), int(30))).toEqual('19191919-11-30'); - expect(util.dateToIsoString(-909090, 9, 9)).toEqual('-909090-09-09'); - expect(util.dateToIsoString(int(-888999777), int(7), int(26))).toEqual('-888999777-07-26'); - }); + expect(util.dateToIsoString(90, 2, 5)).toEqual('0090-02-05') + expect(util.dateToIsoString(int(1), 1, int(1))).toEqual('0001-01-01') + expect(util.dateToIsoString(-123, int(12), int(23))).toEqual('-0123-12-23') + expect(util.dateToIsoString(int(-999), int(9), int(10))).toEqual( + '-0999-09-10' + ) + expect(util.dateToIsoString(1999, 12, 19)).toEqual('1999-12-19') + expect(util.dateToIsoString(int(2023), int(8), int(16))).toEqual( + '2023-08-16' + ) + expect(util.dateToIsoString(12345, 12, 31)).toEqual('12345-12-31') + expect(util.dateToIsoString(int(19191919), int(11), int(30))).toEqual( + '19191919-11-30' + ) + expect(util.dateToIsoString(-909090, 9, 9)).toEqual('-909090-09-09') + expect(util.dateToIsoString(int(-888999777), int(7), int(26))).toEqual( + '-888999777-07-26' + ) + }) it('should convert time zone offset to ISO string', () => { - expect(util.timeZoneOffsetToIsoString(0)).toEqual('Z'); - expect(util.timeZoneOffsetToIsoString(-0)).toEqual('Z'); - expect(util.timeZoneOffsetToIsoString(1)).toEqual('+00:00:01'); - expect(util.timeZoneOffsetToIsoString(-1)).toEqual('-00:00:01'); - expect(util.timeZoneOffsetToIsoString(20 * 60)).toEqual('+00:20'); - expect(util.timeZoneOffsetToIsoString(-12 * 60)).toEqual('-00:12'); - expect(util.timeZoneOffsetToIsoString(8 * 60 * 60)).toEqual('+08:00'); - expect(util.timeZoneOffsetToIsoString(-13 * 60 * 60)).toEqual('-13:00'); - expect(util.timeZoneOffsetToIsoString(8 * 60 * 60 + 59 * 60)).toEqual('+08:59'); - expect(util.timeZoneOffsetToIsoString(-12 * 60 * 60 - 31 * 60)).toEqual('-12:31'); - expect(util.timeZoneOffsetToIsoString(2 * 60 * 60 + 9 * 60 + 17)).toEqual('+02:09:17'); - expect(util.timeZoneOffsetToIsoString(-7 * 60 * 60 - 18 * 60 - 54)).toEqual('-07:18:54'); - }); + expect(util.timeZoneOffsetToIsoString(0)).toEqual('Z') + expect(util.timeZoneOffsetToIsoString(-0)).toEqual('Z') + expect(util.timeZoneOffsetToIsoString(1)).toEqual('+00:00:01') + expect(util.timeZoneOffsetToIsoString(-1)).toEqual('-00:00:01') + expect(util.timeZoneOffsetToIsoString(20 * 60)).toEqual('+00:20') + expect(util.timeZoneOffsetToIsoString(-12 * 60)).toEqual('-00:12') + expect(util.timeZoneOffsetToIsoString(8 * 60 * 60)).toEqual('+08:00') + expect(util.timeZoneOffsetToIsoString(-13 * 60 * 60)).toEqual('-13:00') + expect(util.timeZoneOffsetToIsoString(8 * 60 * 60 + 59 * 60)).toEqual( + '+08:59' + ) + expect(util.timeZoneOffsetToIsoString(-12 * 60 * 60 - 31 * 60)).toEqual( + '-12:31' + ) + expect(util.timeZoneOffsetToIsoString(2 * 60 * 60 + 9 * 60 + 17)).toEqual( + '+02:09:17' + ) + expect(util.timeZoneOffsetToIsoString(-7 * 60 * 60 - 18 * 60 - 54)).toEqual( + '-07:18:54' + ) + }) it('should convert time to ISO string', () => { - expect(util.timeToIsoString(8, 9, 1, 0)).toEqual('08:09:01'); - expect(util.timeToIsoString(1, 23, 45, 600000000)).toEqual('01:23:45.600000000'); - expect(util.timeToIsoString(int(2), int(4), int(6), int(7))).toEqual('02:04:06.000000007'); - expect(util.timeToIsoString(22, 19, 7, 999)).toEqual('22:19:07.000000999'); - expect(util.timeToIsoString(int(17), int(2), int(59), int(909090))).toEqual('17:02:59.000909090'); - expect(util.timeToIsoString(23, 59, 59, 999999991)).toEqual('23:59:59.999999991'); - expect(util.timeToIsoString(int(23), int(22), int(21), int(111222333))).toEqual('23:22:21.111222333'); - }); + expect(util.timeToIsoString(8, 9, 1, 0)).toEqual('08:09:01') + expect(util.timeToIsoString(1, 23, 45, 600000000)).toEqual( + '01:23:45.600000000' + ) + expect(util.timeToIsoString(int(2), int(4), int(6), int(7))).toEqual( + '02:04:06.000000007' + ) + expect(util.timeToIsoString(22, 19, 7, 999)).toEqual('22:19:07.000000999') + expect(util.timeToIsoString(int(17), int(2), int(59), int(909090))).toEqual( + '17:02:59.000909090' + ) + expect(util.timeToIsoString(23, 59, 59, 999999991)).toEqual( + '23:59:59.999999991' + ) + expect( + util.timeToIsoString(int(23), int(22), int(21), int(111222333)) + ).toEqual('23:22:21.111222333') + }) it('should convert duration to ISO string', () => { - expect(util.durationToIsoString(0, 0, 0, 0)).toEqual('P0M0DT0S'); - expect(util.durationToIsoString(0, 0, 0, 123)).toEqual('P0M0DT0.000000123S'); - expect(util.durationToIsoString(11, 99, 100, 99901)).toEqual('P11M99DT100.000099901S'); - expect(util.durationToIsoString(int(3), int(9191), int(17), int(123456789))).toEqual('P3M9191DT17.123456789S'); - expect(util.durationToIsoString(-5, 2, -13, 123)).toEqual('P-5M2DT-12.999999877S'); - }); + expect(util.durationToIsoString(0, 0, 0, 0)).toEqual('P0M0DT0S') + expect(util.durationToIsoString(0, 0, 0, 123)).toEqual('P0M0DT0.000000123S') + expect(util.durationToIsoString(11, 99, 100, 99901)).toEqual( + 'P11M99DT100.000099901S' + ) + expect( + util.durationToIsoString(int(3), int(9191), int(17), int(123456789)) + ).toEqual('P3M9191DT17.123456789S') + expect(util.durationToIsoString(-5, 2, -13, 123)).toEqual( + 'P-5M2DT-12.999999877S' + ) + }) it('should convert epoch day to cypher date', () => { - expect(util.epochDayToDate(-719528)).toEqual(date(0, 1, 1)); - expect(util.epochDayToDate(-135153)).toEqual(date(1599, 12, 19)); - expect(util.epochDayToDate(7905)).toEqual(date(1991, 8, 24)); - expect(util.epochDayToDate(int(48210))).toEqual(date(2101, 12, 30)); - expect(util.epochDayToDate(int(-4310226))).toEqual(date(-9831, 1, 1)); - }); + expect(util.epochDayToDate(-719528)).toEqual(date(0, 1, 1)) + expect(util.epochDayToDate(-135153)).toEqual(date(1599, 12, 19)) + expect(util.epochDayToDate(7905)).toEqual(date(1991, 8, 24)) + expect(util.epochDayToDate(int(48210))).toEqual(date(2101, 12, 30)) + expect(util.epochDayToDate(int(-4310226))).toEqual(date(-9831, 1, 1)) + }) it('should convert cypher date to epoch day', () => { - expect(util.dateToEpochDay(-13, 12, 31)).toEqual(int(-723912)); - expect(util.dateToEpochDay(9, 9, 9)).toEqual(int(-715989)); - expect(util.dateToEpochDay(2015, 2, 17)).toEqual(int(16483)); - expect(util.dateToEpochDay(2189, 7, 19)).toEqual(int(80188)); - expect(util.dateToEpochDay(19999, 9, 28)).toEqual(int(6585227)); - }); + expect(util.dateToEpochDay(-13, 12, 31)).toEqual(int(-723912)) + expect(util.dateToEpochDay(9, 9, 9)).toEqual(int(-715989)) + expect(util.dateToEpochDay(2015, 2, 17)).toEqual(int(16483)) + expect(util.dateToEpochDay(2189, 7, 19)).toEqual(int(80188)) + expect(util.dateToEpochDay(19999, 9, 28)).toEqual(int(6585227)) + }) it('should convert epoch second with nano to cypher local date-time', () => { - expect(util.epochSecondAndNanoToLocalDateTime(653165977, 999)).toEqual(localDateTime(1990, 9, 12, 18, 59, 37, 999)); - expect(util.epochSecondAndNanoToLocalDateTime(-62703676801, 12345)).toEqual(localDateTime(-18, 12, 31, 23, 59, 59, 12345)); - expect(util.epochSecondAndNanoToLocalDateTime(2678400, int(1))).toEqual(localDateTime(1970, 2, 1, 0, 0, 0, 1)); - expect(util.epochSecondAndNanoToLocalDateTime(int(3065493882737), int(1794673))).toEqual(localDateTime(99111, 8, 21, 6, 32, 17, 1794673)); - expect(util.epochSecondAndNanoToLocalDateTime(int(-37428234001), 999999111)).toEqual(localDateTime(783, 12, 12, 20, 19, 59, 999999111)); - }); + expect(util.epochSecondAndNanoToLocalDateTime(653165977, 999)).toEqual( + localDateTime(1990, 9, 12, 18, 59, 37, 999) + ) + expect(util.epochSecondAndNanoToLocalDateTime(-62703676801, 12345)).toEqual( + localDateTime(-18, 12, 31, 23, 59, 59, 12345) + ) + expect(util.epochSecondAndNanoToLocalDateTime(2678400, int(1))).toEqual( + localDateTime(1970, 2, 1, 0, 0, 0, 1) + ) + expect( + util.epochSecondAndNanoToLocalDateTime(int(3065493882737), int(1794673)) + ).toEqual(localDateTime(99111, 8, 21, 6, 32, 17, 1794673)) + expect( + util.epochSecondAndNanoToLocalDateTime(int(-37428234001), 999999111) + ).toEqual(localDateTime(783, 12, 12, 20, 19, 59, 999999111)) + }) it('should convert cypher local date-time to epoch second', () => { - expect(util.localDateTimeToEpochSecond(1990, 9, 12, 18, 59, 37, 999)).toEqual(int(653165977)); - expect(util.localDateTimeToEpochSecond(-18, 12, 31, 23, 59, 59, 12345)).toEqual(int(-62703676801)); - expect(util.localDateTimeToEpochSecond(1970, 2, 1, 0, 0, 0, 1)).toEqual(int(2678400)); - expect(util.localDateTimeToEpochSecond(99111, 8, 21, 6, 32, 17, 1794673)).toEqual(int(3065493882737)); - expect(util.localDateTimeToEpochSecond(783, 12, 12, 20, 19, 59, 999999111)).toEqual(int(-37428234001)); - }); + expect( + util.localDateTimeToEpochSecond(1990, 9, 12, 18, 59, 37, 999) + ).toEqual(int(653165977)) + expect( + util.localDateTimeToEpochSecond(-18, 12, 31, 23, 59, 59, 12345) + ).toEqual(int(-62703676801)) + expect(util.localDateTimeToEpochSecond(1970, 2, 1, 0, 0, 0, 1)).toEqual( + int(2678400) + ) + expect( + util.localDateTimeToEpochSecond(99111, 8, 21, 6, 32, 17, 1794673) + ).toEqual(int(3065493882737)) + expect( + util.localDateTimeToEpochSecond(783, 12, 12, 20, 19, 59, 999999111) + ).toEqual(int(-37428234001)) + }) it('should convert nanosecond of the day to cypher local time', () => { - expect(util.nanoOfDayToLocalTime(68079000012399)).toEqual(localTime(18, 54, 39, 12399)); - expect(util.nanoOfDayToLocalTime(0)).toEqual(localTime(0, 0, 0, 0)); - expect(util.nanoOfDayToLocalTime(1)).toEqual(localTime(0, 0, 0, 1)); - expect(util.nanoOfDayToLocalTime(int(86399999999999))).toEqual(localTime(23, 59, 59, 999999999)); - expect(util.nanoOfDayToLocalTime(int(46277000808080))).toEqual(localTime(12, 51, 17, 808080)); - }); + expect(util.nanoOfDayToLocalTime(68079000012399)).toEqual( + localTime(18, 54, 39, 12399) + ) + expect(util.nanoOfDayToLocalTime(0)).toEqual(localTime(0, 0, 0, 0)) + expect(util.nanoOfDayToLocalTime(1)).toEqual(localTime(0, 0, 0, 1)) + expect(util.nanoOfDayToLocalTime(int(86399999999999))).toEqual( + localTime(23, 59, 59, 999999999) + ) + expect(util.nanoOfDayToLocalTime(int(46277000808080))).toEqual( + localTime(12, 51, 17, 808080) + ) + }) it('should convert cypher local time to nanosecond of the day', () => { - expect(util.localTimeToNanoOfDay(18, 54, 39, 12399)).toEqual(int(68079000012399)); - expect(util.localTimeToNanoOfDay(0, 0, 0, 0)).toEqual(int(0)); - expect(util.localTimeToNanoOfDay(0, 0, 0, 1)).toEqual(int(1)); - expect(util.localTimeToNanoOfDay(23, 59, 59, 999999999)).toEqual(int(86399999999999)); - expect(util.localTimeToNanoOfDay(12, 51, 17, 808080)).toEqual(int(46277000808080)); - }); + expect(util.localTimeToNanoOfDay(18, 54, 39, 12399)).toEqual( + int(68079000012399) + ) + expect(util.localTimeToNanoOfDay(0, 0, 0, 0)).toEqual(int(0)) + expect(util.localTimeToNanoOfDay(0, 0, 0, 1)).toEqual(int(1)) + expect(util.localTimeToNanoOfDay(23, 59, 59, 999999999)).toEqual( + int(86399999999999) + ) + expect(util.localTimeToNanoOfDay(12, 51, 17, 808080)).toEqual( + int(46277000808080) + ) + }) it('should get total nanoseconds from standard date', () => { - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0))).toEqual(0); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 1))).toEqual(1000000); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 23))).toEqual(23000000); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 999))).toEqual(999000000); - - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), 0)).toEqual(0); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), 1)).toEqual(1); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), 999)).toEqual(999); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 1), 999)).toEqual(1000999); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 999), 111)).toEqual(999000111); - - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), int(0))).toEqual(int(0)); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), int(1))).toEqual(int(1)); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), int(999))).toEqual(int(999)); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 1), int(999))).toEqual(int(1000999)); - expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 999), int(111))).toEqual(int(999000111)); - }); + expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0))).toEqual(0) + expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 1))).toEqual( + 1000000 + ) + expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 23))).toEqual( + 23000000 + ) + expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 999))).toEqual( + 999000000 + ) + + expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), 0)).toEqual( + 0 + ) + expect(util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), 1)).toEqual( + 1 + ) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), 999) + ).toEqual(999) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 1), 999) + ).toEqual(1000999) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 999), 111) + ).toEqual(999000111) + + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), int(0)) + ).toEqual(int(0)) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), int(1)) + ).toEqual(int(1)) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 0), int(999)) + ).toEqual(int(999)) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 1), int(999)) + ).toEqual(int(1000999)) + expect( + util.totalNanoseconds(new Date(2000, 1, 1, 1, 1, 1, 999), int(111)) + ).toEqual(int(999000111)) + }) it('should get timezone offset in seconds from standard date', () => { - expect(util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(0))).toBe(0); - expect(util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(2))).toBe(-120); - expect(util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(10))).toBe(-600); - expect(util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(101))).toBe(-6060); - expect(util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(-180))).toBe(10800); - expect(util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(-600))).toBe(36000); - }); + expect( + util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(0)) + ).toBe(0) + expect( + util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(2)) + ).toBe(-120) + expect( + util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(10)) + ).toBe(-600) + expect( + util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(101)) + ).toBe(-6060) + expect( + util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(-180)) + ).toBe(10800) + expect( + util.timeZoneOffsetInSeconds(testUtils.fakeStandardDateWithOffset(-600)) + ).toBe(36000) + }) it('should verify year', () => { - expect(util.assertValidYear(-1)).toEqual(-1); - expect(util.assertValidYear(-2010)).toEqual(-2010); - expect(util.assertValidYear(int(-42))).toEqual(int(-42)); - expect(util.assertValidYear(int(-2019))).toEqual(int(-2019)); - - expect(util.assertValidYear(0)).toEqual(0); - expect(util.assertValidYear(1)).toEqual(1); - expect(util.assertValidYear(int(2015))).toEqual(int(2015)); - expect(util.assertValidYear(int(99999))).toEqual(int(99999)); - - expect(() => util.assertValidYear(1000000000)).toThrow(); - expect(() => util.assertValidYear(1999999999)).toThrow(); - expect(() => util.assertValidYear(int(2000000000))).toThrow(); - expect(() => util.assertValidYear(int(3999999999))).toThrow(); - - expect(() => util.assertValidYear(-1000000001)).toThrow(); - expect(() => util.assertValidYear(-1888888888)).toThrow(); - expect(() => util.assertValidYear(int(-2000000001))).toThrow(); - expect(() => util.assertValidYear(int(-3888888888))).toThrow(); - }); + expect(util.assertValidYear(-1)).toEqual(-1) + expect(util.assertValidYear(-2010)).toEqual(-2010) + expect(util.assertValidYear(int(-42))).toEqual(int(-42)) + expect(util.assertValidYear(int(-2019))).toEqual(int(-2019)) + + expect(util.assertValidYear(0)).toEqual(0) + expect(util.assertValidYear(1)).toEqual(1) + expect(util.assertValidYear(int(2015))).toEqual(int(2015)) + expect(util.assertValidYear(int(99999))).toEqual(int(99999)) + + expect(() => util.assertValidYear(1000000000)).toThrow() + expect(() => util.assertValidYear(1999999999)).toThrow() + expect(() => util.assertValidYear(int(2000000000))).toThrow() + expect(() => util.assertValidYear(int(3999999999))).toThrow() + + expect(() => util.assertValidYear(-1000000001)).toThrow() + expect(() => util.assertValidYear(-1888888888)).toThrow() + expect(() => util.assertValidYear(int(-2000000001))).toThrow() + expect(() => util.assertValidYear(int(-3888888888))).toThrow() + }) it('should verify month', () => { for (let i = 1; i <= 12; i++) { - expect(util.assertValidMonth(i)).toEqual(i); - expect(util.assertValidMonth(int(i))).toEqual(int(i)); + expect(util.assertValidMonth(i)).toEqual(i) + expect(util.assertValidMonth(int(i))).toEqual(int(i)) } - expect(() => util.assertValidMonth(0)).toThrow(); - expect(() => util.assertValidMonth(int(0))).toThrow(); - expect(() => util.assertValidMonth(-1)).toThrow(); - expect(() => util.assertValidMonth(int(-1))).toThrow(); - expect(() => util.assertValidMonth(-42)).toThrow(); - expect(() => util.assertValidMonth(int(-42))).toThrow(); - expect(() => util.assertValidMonth(13)).toThrow(); - expect(() => util.assertValidMonth(int(13))).toThrow(); - expect(() => util.assertValidMonth(42)).toThrow(); - expect(() => util.assertValidMonth(int(42))).toThrow(); - }); + expect(() => util.assertValidMonth(0)).toThrow() + expect(() => util.assertValidMonth(int(0))).toThrow() + expect(() => util.assertValidMonth(-1)).toThrow() + expect(() => util.assertValidMonth(int(-1))).toThrow() + expect(() => util.assertValidMonth(-42)).toThrow() + expect(() => util.assertValidMonth(int(-42))).toThrow() + expect(() => util.assertValidMonth(13)).toThrow() + expect(() => util.assertValidMonth(int(13))).toThrow() + expect(() => util.assertValidMonth(42)).toThrow() + expect(() => util.assertValidMonth(int(42))).toThrow() + }) it('should verify day', () => { for (let i = 1; i <= 31; i++) { - expect(util.assertValidDay(i)).toEqual(i); - expect(util.assertValidDay(int(i))).toEqual(int(i)); + expect(util.assertValidDay(i)).toEqual(i) + expect(util.assertValidDay(int(i))).toEqual(int(i)) } - expect(() => util.assertValidDay(0)).toThrow(); - expect(() => util.assertValidDay(int(0))).toThrow(); - expect(() => util.assertValidDay(-1)).toThrow(); - expect(() => util.assertValidDay(int(-1))).toThrow(); - expect(() => util.assertValidDay(-42)).toThrow(); - expect(() => util.assertValidDay(int(-42))).toThrow(); - expect(() => util.assertValidDay(42)).toThrow(); - expect(() => util.assertValidDay(int(42))).toThrow(); - }); + expect(() => util.assertValidDay(0)).toThrow() + expect(() => util.assertValidDay(int(0))).toThrow() + expect(() => util.assertValidDay(-1)).toThrow() + expect(() => util.assertValidDay(int(-1))).toThrow() + expect(() => util.assertValidDay(-42)).toThrow() + expect(() => util.assertValidDay(int(-42))).toThrow() + expect(() => util.assertValidDay(42)).toThrow() + expect(() => util.assertValidDay(int(42))).toThrow() + }) it('should verify hour', () => { for (let i = 0; i <= 23; i++) { - expect(util.assertValidHour(i)).toEqual(i); - expect(util.assertValidHour(int(i))).toEqual(int(i)); + expect(util.assertValidHour(i)).toEqual(i) + expect(util.assertValidHour(int(i))).toEqual(int(i)) } - expect(() => util.assertValidHour(-1)).toThrow(); - expect(() => util.assertValidHour(int(-1))).toThrow(); - expect(() => util.assertValidHour(-42)).toThrow(); - expect(() => util.assertValidHour(int(-42))).toThrow(); - expect(() => util.assertValidHour(24)).toThrow(); - expect(() => util.assertValidHour(int(24))).toThrow(); - expect(() => util.assertValidHour(42)).toThrow(); - expect(() => util.assertValidHour(int(42))).toThrow(); - }); + expect(() => util.assertValidHour(-1)).toThrow() + expect(() => util.assertValidHour(int(-1))).toThrow() + expect(() => util.assertValidHour(-42)).toThrow() + expect(() => util.assertValidHour(int(-42))).toThrow() + expect(() => util.assertValidHour(24)).toThrow() + expect(() => util.assertValidHour(int(24))).toThrow() + expect(() => util.assertValidHour(42)).toThrow() + expect(() => util.assertValidHour(int(42))).toThrow() + }) it('should verify minute', () => { for (let i = 0; i <= 59; i++) { - expect(util.assertValidMinute(i)).toEqual(i); - expect(util.assertValidMinute(int(i))).toEqual(int(i)); + expect(util.assertValidMinute(i)).toEqual(i) + expect(util.assertValidMinute(int(i))).toEqual(int(i)) } - expect(() => util.assertValidMinute(-1)).toThrow(); - expect(() => util.assertValidMinute(int(-1))).toThrow(); - expect(() => util.assertValidMinute(-42)).toThrow(); - expect(() => util.assertValidMinute(int(-42))).toThrow(); - expect(() => util.assertValidMinute(60)).toThrow(); - expect(() => util.assertValidMinute(int(60))).toThrow(); - expect(() => util.assertValidMinute(91023)).toThrow(); - expect(() => util.assertValidMinute(int(1234))).toThrow(); - }); + expect(() => util.assertValidMinute(-1)).toThrow() + expect(() => util.assertValidMinute(int(-1))).toThrow() + expect(() => util.assertValidMinute(-42)).toThrow() + expect(() => util.assertValidMinute(int(-42))).toThrow() + expect(() => util.assertValidMinute(60)).toThrow() + expect(() => util.assertValidMinute(int(60))).toThrow() + expect(() => util.assertValidMinute(91023)).toThrow() + expect(() => util.assertValidMinute(int(1234))).toThrow() + }) it('should verify second', () => { for (let i = 0; i <= 59; i++) { - expect(util.assertValidSecond(i)).toEqual(i); - expect(util.assertValidSecond(int(i))).toEqual(int(i)); + expect(util.assertValidSecond(i)).toEqual(i) + expect(util.assertValidSecond(int(i))).toEqual(int(i)) } - expect(() => util.assertValidSecond(-1)).toThrow(); - expect(() => util.assertValidSecond(int(-1))).toThrow(); - expect(() => util.assertValidSecond(-42)).toThrow(); - expect(() => util.assertValidSecond(int(-42))).toThrow(); - expect(() => util.assertValidSecond(60)).toThrow(); - expect(() => util.assertValidSecond(int(60))).toThrow(); - expect(() => util.assertValidSecond(123)).toThrow(); - expect(() => util.assertValidSecond(int(321))).toThrow(); - }); + expect(() => util.assertValidSecond(-1)).toThrow() + expect(() => util.assertValidSecond(int(-1))).toThrow() + expect(() => util.assertValidSecond(-42)).toThrow() + expect(() => util.assertValidSecond(int(-42))).toThrow() + expect(() => util.assertValidSecond(60)).toThrow() + expect(() => util.assertValidSecond(int(60))).toThrow() + expect(() => util.assertValidSecond(123)).toThrow() + expect(() => util.assertValidSecond(int(321))).toThrow() + }) it('should verify nanosecond', () => { - expect(util.assertValidNanosecond(0)).toEqual(0); - expect(util.assertValidNanosecond(1)).toEqual(1); - expect(util.assertValidNanosecond(42)).toEqual(42); - expect(util.assertValidNanosecond(999)).toEqual(999); - expect(util.assertValidNanosecond(123456789)).toEqual(123456789); - expect(util.assertValidNanosecond(999999999)).toEqual(999999999); - - expect(() => util.assertValidNanosecond(-1)).toThrow(); - expect(() => util.assertValidNanosecond(int(-1))).toThrow(); - expect(() => util.assertValidNanosecond(-42)).toThrow(); - expect(() => util.assertValidNanosecond(int(-42))).toThrow(); - expect(() => util.assertValidNanosecond(1000000000)).toThrow(); - expect(() => util.assertValidNanosecond(int(1000000000))).toThrow(); - expect(() => util.assertValidNanosecond(1999999999)).toThrow(); - expect(() => util.assertValidNanosecond(int(1222222222))).toThrow(); - }); - -}); - -function date(year, month, day) { - return new types.Date(int(year), int(month), int(day)); + expect(util.assertValidNanosecond(0)).toEqual(0) + expect(util.assertValidNanosecond(1)).toEqual(1) + expect(util.assertValidNanosecond(42)).toEqual(42) + expect(util.assertValidNanosecond(999)).toEqual(999) + expect(util.assertValidNanosecond(123456789)).toEqual(123456789) + expect(util.assertValidNanosecond(999999999)).toEqual(999999999) + + expect(() => util.assertValidNanosecond(-1)).toThrow() + expect(() => util.assertValidNanosecond(int(-1))).toThrow() + expect(() => util.assertValidNanosecond(-42)).toThrow() + expect(() => util.assertValidNanosecond(int(-42))).toThrow() + expect(() => util.assertValidNanosecond(1000000000)).toThrow() + expect(() => util.assertValidNanosecond(int(1000000000))).toThrow() + expect(() => util.assertValidNanosecond(1999999999)).toThrow() + expect(() => util.assertValidNanosecond(int(1222222222))).toThrow() + }) +}) + +function date (year, month, day) { + return new types.Date(int(year), int(month), int(day)) } -function localTime(hour, minute, second, nanosecond) { - return new types.LocalTime(int(hour), int(minute), int(second), int(nanosecond)); +function localTime (hour, minute, second, nanosecond) { + return new types.LocalTime( + int(hour), + int(minute), + int(second), + int(nanosecond) + ) } -function localDateTime(year, month, day, hour, minute, second, nanosecond) { - return new types.LocalDateTime(int(year), int(month), int(day), int(hour), int(minute), int(second), int(nanosecond)); +function localDateTime (year, month, day, hour, minute, second, nanosecond) { + return new types.LocalDateTime( + int(year), + int(month), + int(day), + int(hour), + int(minute), + int(second), + int(nanosecond) + ) } diff --git a/test/internal/test-utils.js b/test/internal/test-utils.js index 2f365c215..af8a9c33b 100644 --- a/test/internal/test-utils.js +++ b/test/internal/test-utils.js @@ -16,22 +16,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -function isClient() { - return (typeof window != 'undefined' && window.document); +function isClient () { + return typeof window !== 'undefined' && window.document } -function isServer() { - return !isClient(); +function isServer () { + return !isClient() } -function fakeStandardDateWithOffset(offsetMinutes) { - const date = new Date(); - date.getTimezoneOffset = () => offsetMinutes; - return date; +function fakeStandardDateWithOffset (offsetMinutes) { + const date = new Date() + date.getTimezoneOffset = () => offsetMinutes + return date } export default { isClient, isServer, fakeStandardDateWithOffset -}; +} diff --git a/test/internal/timers-util.js b/test/internal/timers-util.js index 83610e117..04df43fd4 100644 --- a/test/internal/timers-util.js +++ b/test/internal/timers-util.js @@ -17,52 +17,51 @@ * limitations under the License. */ class SetTimeoutMock { - - constructor() { - this._clearState(); + constructor () { + this._clearState() } - install() { - this._originalSetTimeout = global.setTimeout; + install () { + this._originalSetTimeout = global.setTimeout global.setTimeout = (code, delay) => { if (!this._paused) { - code(); - this.invocationDelays.push(delay); + code() + this.invocationDelays.push(delay) } - return this._timeoutIdCounter++; - }; + return this._timeoutIdCounter++ + } - this._originalClearTimeout = global.clearTimeout; + this._originalClearTimeout = global.clearTimeout global.clearTimeout = id => { - this.clearedTimeouts.push(id); - }; + this.clearedTimeouts.push(id) + } - return this; + return this } - pause() { - this._paused = true; + pause () { + this._paused = true } - uninstall() { - global.setTimeout = this._originalSetTimeout; - global.clearTimeout = this._originalClearTimeout; - this._clearState(); + uninstall () { + global.setTimeout = this._originalSetTimeout + global.clearTimeout = this._originalClearTimeout + this._clearState() } - setTimeoutOriginal(code, delay) { - return this._originalSetTimeout.call(null, code, delay); + setTimeoutOriginal (code, delay) { + return this._originalSetTimeout.call(null, code, delay) } - _clearState() { - this._originalSetTimeout = null; - this._originalClearTimeout = null; - this._paused = false; - this._timeoutIdCounter = 0; + _clearState () { + this._originalSetTimeout = null + this._originalClearTimeout = null + this._paused = false + this._timeoutIdCounter = 0 - this.invocationDelays = []; - this.clearedTimeouts = []; + this.invocationDelays = [] + this.clearedTimeouts = [] } } -export const setTimeoutMock = new SetTimeoutMock(); +export const setTimeoutMock = new SetTimeoutMock() diff --git a/test/internal/transaction-executor.test.js b/test/internal/transaction-executor.test.js index c1c42a5d5..f4f6c929f 100644 --- a/test/internal/transaction-executor.test.js +++ b/test/internal/transaction-executor.test.js @@ -17,401 +17,489 @@ * limitations under the License. */ -import TransactionExecutor from '../../src/v1/internal/transaction-executor'; -import {newError, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from '../../src/v1/error'; -import {setTimeoutMock} from './timers-util'; -import lolex from 'lolex'; - -const TRANSIENT_ERROR_1 = 'Neo.TransientError.Transaction.DeadlockDetected'; -const TRANSIENT_ERROR_2 = 'Neo.TransientError.Network.CommunicationError'; -const UNKNOWN_ERROR = 'Neo.DatabaseError.General.UnknownError'; -const TX_TERMINATED_ERROR = 'Neo.TransientError.Transaction.Terminated'; -const LOCKS_TERMINATED_ERROR = 'Neo.TransientError.Transaction.LockClientStopped'; -const OOM_ERROR = 'Neo.DatabaseError.General.OutOfMemoryError'; +import TransactionExecutor from '../../src/v1/internal/transaction-executor' +import { + newError, + SERVICE_UNAVAILABLE, + SESSION_EXPIRED +} from '../../src/v1/error' +import { setTimeoutMock } from './timers-util' +import lolex from 'lolex' + +const TRANSIENT_ERROR_1 = 'Neo.TransientError.Transaction.DeadlockDetected' +const TRANSIENT_ERROR_2 = 'Neo.TransientError.Network.CommunicationError' +const UNKNOWN_ERROR = 'Neo.DatabaseError.General.UnknownError' +const TX_TERMINATED_ERROR = 'Neo.TransientError.Transaction.Terminated' +const LOCKS_TERMINATED_ERROR = + 'Neo.TransientError.Transaction.LockClientStopped' +const OOM_ERROR = 'Neo.DatabaseError.General.OutOfMemoryError' describe('TransactionExecutor', () => { - - let clock; - let fakeSetTimeout; + let clock + let fakeSetTimeout beforeEach(() => { - fakeSetTimeout = setTimeoutMock.install(); - }); + fakeSetTimeout = setTimeoutMock.install() + }) afterEach(() => { if (clock) { - clock.uninstall(); - clock = null; + clock.uninstall() + clock = null } - fakeSetTimeout.uninstall(); - }); + fakeSetTimeout.uninstall() + }) it('should retry when transaction work returns promise rejected with SERVICE_UNAVAILABLE', done => { - testRetryWhenTransactionWorkReturnsRejectedPromise([SERVICE_UNAVAILABLE], done); - }); + testRetryWhenTransactionWorkReturnsRejectedPromise( + [SERVICE_UNAVAILABLE], + done + ) + }) it('should retry when transaction work returns promise rejected with SESSION_EXPIRED', done => { - testRetryWhenTransactionWorkReturnsRejectedPromise([SESSION_EXPIRED], done); - }); + testRetryWhenTransactionWorkReturnsRejectedPromise([SESSION_EXPIRED], done) + }) it('should retry when transaction work returns promise rejected with deadlock error', done => { - testRetryWhenTransactionWorkReturnsRejectedPromise([TRANSIENT_ERROR_1], done); - }); + testRetryWhenTransactionWorkReturnsRejectedPromise( + [TRANSIENT_ERROR_1], + done + ) + }) it('should retry when transaction work returns promise rejected with communication error', done => { - testRetryWhenTransactionWorkReturnsRejectedPromise([TRANSIENT_ERROR_2], done); - }); + testRetryWhenTransactionWorkReturnsRejectedPromise( + [TRANSIENT_ERROR_2], + done + ) + }) it('should not retry when transaction work returns promise rejected with OOM error', done => { - testNoRetryOnUnknownError([OOM_ERROR], 1, done); - }); + testNoRetryOnUnknownError([OOM_ERROR], 1, done) + }) it('should not retry when transaction work returns promise rejected with unknown error', done => { - testNoRetryOnUnknownError([UNKNOWN_ERROR], 1, done); - }); + testNoRetryOnUnknownError([UNKNOWN_ERROR], 1, done) + }) it('should not retry when transaction work returns promise rejected with transaction termination error', done => { - testNoRetryOnUnknownError([TX_TERMINATED_ERROR], 1, done); - }); + testNoRetryOnUnknownError([TX_TERMINATED_ERROR], 1, done) + }) it('should not retry when transaction work returns promise rejected with locks termination error', done => { - testNoRetryOnUnknownError([LOCKS_TERMINATED_ERROR], 1, done); - }); + testNoRetryOnUnknownError([LOCKS_TERMINATED_ERROR], 1, done) + }) it('should stop retrying when time expires', done => { - const executor = new TransactionExecutor(); - const usedTransactions = []; - const realWork = transactionWork([SERVICE_UNAVAILABLE, SESSION_EXPIRED, TRANSIENT_ERROR_1, TRANSIENT_ERROR_2], 42); + const executor = new TransactionExecutor() + const usedTransactions = [] + const realWork = transactionWork( + [ + SERVICE_UNAVAILABLE, + SESSION_EXPIRED, + TRANSIENT_ERROR_1, + TRANSIENT_ERROR_2 + ], + 42 + ) const result = executor.execute(transactionCreator(), tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); + expect(tx).toBeDefined() + usedTransactions.push(tx) if (usedTransactions.length === 3) { - const currentTime = Date.now(); - clock = lolex.install(); - clock.setSystemTime(currentTime + 30001); // move `Date.now()` call forward by 30 seconds + const currentTime = Date.now() + clock = lolex.install() + clock.setSystemTime(currentTime + 30001) // move `Date.now()` call forward by 30 seconds } - return realWork(); - }); + return realWork() + }) result.catch(error => { - expect(usedTransactions.length).toEqual(3); - expectAllTransactionsToBeClosed(usedTransactions); - expect(error.code).toEqual(TRANSIENT_ERROR_1); - done(); - }); - }); + expect(usedTransactions.length).toEqual(3) + expectAllTransactionsToBeClosed(usedTransactions) + expect(error.code).toEqual(TRANSIENT_ERROR_1) + done() + }) + }) it('should retry when given transaction creator throws once', done => { - testRetryWhenTransactionCreatorFails( - [SERVICE_UNAVAILABLE], - done - ); - }); + testRetryWhenTransactionCreatorFails([SERVICE_UNAVAILABLE], done) + }) it('should retry when given transaction creator throws many times', done => { testRetryWhenTransactionCreatorFails( - [SERVICE_UNAVAILABLE, SESSION_EXPIRED, TRANSIENT_ERROR_2, SESSION_EXPIRED, SERVICE_UNAVAILABLE, TRANSIENT_ERROR_1], + [ + SERVICE_UNAVAILABLE, + SESSION_EXPIRED, + TRANSIENT_ERROR_2, + SESSION_EXPIRED, + SERVICE_UNAVAILABLE, + TRANSIENT_ERROR_1 + ], done - ); - }); + ) + }) it('should retry when given transaction work throws once', done => { - testRetryWhenTransactionWorkThrows([SERVICE_UNAVAILABLE], done); - }); + testRetryWhenTransactionWorkThrows([SERVICE_UNAVAILABLE], done) + }) it('should retry when given transaction work throws many times', done => { testRetryWhenTransactionWorkThrows( - [SERVICE_UNAVAILABLE, TRANSIENT_ERROR_2, TRANSIENT_ERROR_2, SESSION_EXPIRED], + [ + SERVICE_UNAVAILABLE, + TRANSIENT_ERROR_2, + TRANSIENT_ERROR_2, + SESSION_EXPIRED + ], done - ); - }); + ) + }) it('should retry when given transaction work returns rejected promise many times', done => { testRetryWhenTransactionWorkReturnsRejectedPromise( - [SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE, TRANSIENT_ERROR_2, SESSION_EXPIRED, TRANSIENT_ERROR_1, SESSION_EXPIRED], + [ + SERVICE_UNAVAILABLE, + SERVICE_UNAVAILABLE, + TRANSIENT_ERROR_2, + SESSION_EXPIRED, + TRANSIENT_ERROR_1, + SESSION_EXPIRED + ], done - ); - }); + ) + }) it('should retry when transaction commit returns rejected promise once', done => { - testRetryWhenTransactionCommitReturnsRejectedPromise([TRANSIENT_ERROR_1], done); - }); + testRetryWhenTransactionCommitReturnsRejectedPromise( + [TRANSIENT_ERROR_1], + done + ) + }) it('should retry when transaction commit returns rejected promise multiple times', done => { testRetryWhenTransactionCommitReturnsRejectedPromise( - [TRANSIENT_ERROR_1, TRANSIENT_ERROR_1, SESSION_EXPIRED, SERVICE_UNAVAILABLE, TRANSIENT_ERROR_2], + [ + TRANSIENT_ERROR_1, + TRANSIENT_ERROR_1, + SESSION_EXPIRED, + SERVICE_UNAVAILABLE, + TRANSIENT_ERROR_2 + ], done - ); - }); + ) + }) it('should retry until database error happens', done => { testNoRetryOnUnknownError( - [SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE, TRANSIENT_ERROR_2, SESSION_EXPIRED, UNKNOWN_ERROR, SESSION_EXPIRED], + [ + SERVICE_UNAVAILABLE, + SERVICE_UNAVAILABLE, + TRANSIENT_ERROR_2, + SESSION_EXPIRED, + UNKNOWN_ERROR, + SESSION_EXPIRED + ], 5, done - ); - }); + ) + }) it('should retry when transaction work throws and rollback fails', done => { testRetryWhenTransactionWorkThrowsAndRollbackFails( - [SERVICE_UNAVAILABLE, TRANSIENT_ERROR_2, SESSION_EXPIRED, SESSION_EXPIRED], + [ + SERVICE_UNAVAILABLE, + TRANSIENT_ERROR_2, + SESSION_EXPIRED, + SESSION_EXPIRED + ], [SESSION_EXPIRED, TRANSIENT_ERROR_1], done - ); - }); + ) + }) it('should cancel in-flight timeouts when closed', done => { - const executor = new TransactionExecutor(); + const executor = new TransactionExecutor() // do not execute setTimeout callbacks - fakeSetTimeout.pause(); - - executor.execute(transactionCreator([SERVICE_UNAVAILABLE]), () => Promise.resolve(42)); - executor.execute(transactionCreator([TRANSIENT_ERROR_1]), () => Promise.resolve(4242)); - executor.execute(transactionCreator([SESSION_EXPIRED]), () => Promise.resolve(424242)); + fakeSetTimeout.pause() + + executor.execute(transactionCreator([SERVICE_UNAVAILABLE]), () => + Promise.resolve(42) + ) + executor.execute(transactionCreator([TRANSIENT_ERROR_1]), () => + Promise.resolve(4242) + ) + executor.execute(transactionCreator([SESSION_EXPIRED]), () => + Promise.resolve(424242) + ) fakeSetTimeout.setTimeoutOriginal(() => { - executor.close(); - expect(fakeSetTimeout.clearedTimeouts.length).toEqual(3); - done(); - }, 1000); - }); + executor.close() + expect(fakeSetTimeout.clearedTimeouts.length).toEqual(3) + done() + }, 1000) + }) it('should allow zero max retry time', () => { - const executor = new TransactionExecutor(0); - expect(executor._maxRetryTimeMs).toEqual(0); - }); + const executor = new TransactionExecutor(0) + expect(executor._maxRetryTimeMs).toEqual(0) + }) it('should allow zero initial delay', () => { - const executor = new TransactionExecutor(42, 0); - expect(executor._initialRetryDelayMs).toEqual(0); - }); + const executor = new TransactionExecutor(42, 0) + expect(executor._initialRetryDelayMs).toEqual(0) + }) it('should disallow zero multiplier', () => { - expect(() => new TransactionExecutor(42, 42, 0)).toThrow(); - }); + expect(() => new TransactionExecutor(42, 42, 0)).toThrow() + }) it('should allow zero jitter factor', () => { - const executor = new TransactionExecutor(42, 42, 42, 0); - expect(executor._jitterFactor).toEqual(0); - }); - - function testRetryWhenTransactionCreatorFails(errorCodes, done) { - const executor = new TransactionExecutor(); - const transactionCreator = throwingTransactionCreator(errorCodes, new FakeTransaction()); - const usedTransactions = []; + const executor = new TransactionExecutor(42, 42, 42, 0) + expect(executor._jitterFactor).toEqual(0) + }) + + function testRetryWhenTransactionCreatorFails (errorCodes, done) { + const executor = new TransactionExecutor() + const transactionCreator = throwingTransactionCreator( + errorCodes, + new FakeTransaction() + ) + const usedTransactions = [] const result = executor.execute(transactionCreator, tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); - return Promise.resolve(42); - }); + expect(tx).toBeDefined() + usedTransactions.push(tx) + return Promise.resolve(42) + }) result.then(value => { - expect(usedTransactions.length).toEqual(1); - expect(value).toEqual(42); - verifyRetryDelays(fakeSetTimeout, errorCodes.length); - done(); - }); + expect(usedTransactions.length).toEqual(1) + expect(value).toEqual(42) + verifyRetryDelays(fakeSetTimeout, errorCodes.length) + done() + }) } - function testRetryWhenTransactionWorkReturnsRejectedPromise(errorCodes, done) { - const executor = new TransactionExecutor(); - const usedTransactions = []; - const realWork = transactionWork(errorCodes, 42); + function testRetryWhenTransactionWorkReturnsRejectedPromise ( + errorCodes, + done + ) { + const executor = new TransactionExecutor() + const usedTransactions = [] + const realWork = transactionWork(errorCodes, 42) const result = executor.execute(transactionCreator(), tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); - return realWork(); - }); + expect(tx).toBeDefined() + usedTransactions.push(tx) + return realWork() + }) result.then(value => { // work should have failed 'failures.length' times and succeeded 1 time - expect(usedTransactions.length).toEqual(errorCodes.length + 1); - expectAllTransactionsToBeClosed(usedTransactions); - expect(value).toEqual(42); - verifyRetryDelays(fakeSetTimeout, errorCodes.length); - done(); - }); + expect(usedTransactions.length).toEqual(errorCodes.length + 1) + expectAllTransactionsToBeClosed(usedTransactions) + expect(value).toEqual(42) + verifyRetryDelays(fakeSetTimeout, errorCodes.length) + done() + }) } - function testRetryWhenTransactionCommitReturnsRejectedPromise(errorCodes, done) { - const executor = new TransactionExecutor(); - const usedTransactions = []; - const realWork = () => Promise.resolve(4242); + function testRetryWhenTransactionCommitReturnsRejectedPromise ( + errorCodes, + done + ) { + const executor = new TransactionExecutor() + const usedTransactions = [] + const realWork = () => Promise.resolve(4242) const result = executor.execute(transactionCreator(errorCodes), tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); - return realWork(); - }); + expect(tx).toBeDefined() + usedTransactions.push(tx) + return realWork() + }) result.then(value => { // work should have failed 'failures.length' times and succeeded 1 time - expect(usedTransactions.length).toEqual(errorCodes.length + 1); - expectAllTransactionsToBeClosed(usedTransactions); - expect(value).toEqual(4242); - verifyRetryDelays(fakeSetTimeout, errorCodes.length); - done(); - }); + expect(usedTransactions.length).toEqual(errorCodes.length + 1) + expectAllTransactionsToBeClosed(usedTransactions) + expect(value).toEqual(4242) + verifyRetryDelays(fakeSetTimeout, errorCodes.length) + done() + }) } - function testRetryWhenTransactionWorkThrows(errorCodes, done) { - const executor = new TransactionExecutor(); - const usedTransactions = []; - const realWork = throwingTransactionWork(errorCodes, 42); + function testRetryWhenTransactionWorkThrows (errorCodes, done) { + const executor = new TransactionExecutor() + const usedTransactions = [] + const realWork = throwingTransactionWork(errorCodes, 42) const result = executor.execute(transactionCreator(), tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); - return realWork(); - }); + expect(tx).toBeDefined() + usedTransactions.push(tx) + return realWork() + }) result.then(value => { // work should have failed 'failures.length' times and succeeded 1 time - expect(usedTransactions.length).toEqual(errorCodes.length + 1); - expectAllTransactionsToBeClosed(usedTransactions); - expect(value).toEqual(42); - verifyRetryDelays(fakeSetTimeout, errorCodes.length); - done(); - }); + expect(usedTransactions.length).toEqual(errorCodes.length + 1) + expectAllTransactionsToBeClosed(usedTransactions) + expect(value).toEqual(42) + verifyRetryDelays(fakeSetTimeout, errorCodes.length) + done() + }) } - function testRetryWhenTransactionWorkThrowsAndRollbackFails(txWorkErrorCodes, rollbackErrorCodes, done) { - const executor = new TransactionExecutor(); - const usedTransactions = []; - const realWork = throwingTransactionWork(txWorkErrorCodes, 424242); - - const result = executor.execute(transactionCreator([], rollbackErrorCodes), tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); - return realWork(); - }); + function testRetryWhenTransactionWorkThrowsAndRollbackFails ( + txWorkErrorCodes, + rollbackErrorCodes, + done + ) { + const executor = new TransactionExecutor() + const usedTransactions = [] + const realWork = throwingTransactionWork(txWorkErrorCodes, 424242) + + const result = executor.execute( + transactionCreator([], rollbackErrorCodes), + tx => { + expect(tx).toBeDefined() + usedTransactions.push(tx) + return realWork() + } + ) result.then(value => { // work should have failed 'failures.length' times and succeeded 1 time - expect(usedTransactions.length).toEqual(txWorkErrorCodes.length + 1); - expectAllTransactionsToBeClosed(usedTransactions); - expect(value).toEqual(424242); - verifyRetryDelays(fakeSetTimeout, txWorkErrorCodes.length); - done(); - }); + expect(usedTransactions.length).toEqual(txWorkErrorCodes.length + 1) + expectAllTransactionsToBeClosed(usedTransactions) + expect(value).toEqual(424242) + verifyRetryDelays(fakeSetTimeout, txWorkErrorCodes.length) + done() + }) } - function testNoRetryOnUnknownError(errorCodes, expectedWorkInvocationCount, done) { - const executor = new TransactionExecutor(); - const usedTransactions = []; - const realWork = transactionWork(errorCodes, 42); + function testNoRetryOnUnknownError ( + errorCodes, + expectedWorkInvocationCount, + done + ) { + const executor = new TransactionExecutor() + const usedTransactions = [] + const realWork = transactionWork(errorCodes, 42) const result = executor.execute(transactionCreator(), tx => { - expect(tx).toBeDefined(); - usedTransactions.push(tx); - return realWork(); - }); + expect(tx).toBeDefined() + usedTransactions.push(tx) + return realWork() + }) result.catch(error => { - expect(usedTransactions.length).toEqual(expectedWorkInvocationCount); - expectAllTransactionsToBeClosed(usedTransactions); + expect(usedTransactions.length).toEqual(expectedWorkInvocationCount) + expectAllTransactionsToBeClosed(usedTransactions) if (errorCodes.length === 1) { - expect(error.code).toEqual(errorCodes[0]); + expect(error.code).toEqual(errorCodes[0]) } else { - expect(error.code).toEqual(errorCodes[expectedWorkInvocationCount - 1]); + expect(error.code).toEqual(errorCodes[expectedWorkInvocationCount - 1]) } - done(); - }); + done() + }) } - -}); - -function transactionCreator(commitErrorCodes, rollbackErrorCodes) { - const remainingCommitErrorCodes = (commitErrorCodes || []).slice().reverse(); - const remainingRollbackErrorCodes = (rollbackErrorCodes || []).slice().reverse(); - return () => new FakeTransaction(remainingCommitErrorCodes.pop(), remainingRollbackErrorCodes.pop()); +}) + +function transactionCreator (commitErrorCodes, rollbackErrorCodes) { + const remainingCommitErrorCodes = (commitErrorCodes || []).slice().reverse() + const remainingRollbackErrorCodes = (rollbackErrorCodes || []) + .slice() + .reverse() + return () => + new FakeTransaction( + remainingCommitErrorCodes.pop(), + remainingRollbackErrorCodes.pop() + ) } -function throwingTransactionCreator(errorCodes, result) { - const remainingErrorCodes = errorCodes.slice().reverse(); +function throwingTransactionCreator (errorCodes, result) { + const remainingErrorCodes = errorCodes.slice().reverse() return () => { if (remainingErrorCodes.length === 0) { - return result; + return result } - const errorCode = remainingErrorCodes.pop(); - throw error(errorCode); - }; + const errorCode = remainingErrorCodes.pop() + throw error(errorCode) + } } -function throwingTransactionWork(errorCodes, result) { - const remainingErrorCodes = errorCodes.slice().reverse(); +function throwingTransactionWork (errorCodes, result) { + const remainingErrorCodes = errorCodes.slice().reverse() return () => { if (remainingErrorCodes.length === 0) { - return Promise.resolve(result); + return Promise.resolve(result) } - const errorCode = remainingErrorCodes.pop(); - throw error(errorCode); - }; + const errorCode = remainingErrorCodes.pop() + throw error(errorCode) + } } -function transactionWork(errorCodes, result) { - const remainingErrorCodes = errorCodes.slice().reverse(); +function transactionWork (errorCodes, result) { + const remainingErrorCodes = errorCodes.slice().reverse() return () => { if (remainingErrorCodes.length === 0) { - return Promise.resolve(result); + return Promise.resolve(result) } - const errorCode = remainingErrorCodes.pop(); - return Promise.reject(error(errorCode)); - }; + const errorCode = remainingErrorCodes.pop() + return Promise.reject(error(errorCode)) + } } -function error(code) { - return newError('', code); +function error (code) { + return newError('', code) } -function verifyRetryDelays(fakeSetTimeout, expectedInvocationCount) { - const delays = fakeSetTimeout.invocationDelays; - expect(delays.length).toEqual(expectedInvocationCount); +function verifyRetryDelays (fakeSetTimeout, expectedInvocationCount) { + const delays = fakeSetTimeout.invocationDelays + expect(delays.length).toEqual(expectedInvocationCount) delays.forEach((delay, index) => { // delays make a geometric progression with fist element 1000 and multiplier 2.0 // so expected delay can be calculated as n-th element: `firstElement * pow(multiplier, n - 1)` - const expectedDelayWithoutJitter = 1000 * Math.pow(2.0, index); - const jitter = expectedDelayWithoutJitter * 0.2; - const min = expectedDelayWithoutJitter - jitter; - const max = expectedDelayWithoutJitter + jitter; - - expect(delay >= min).toBeTruthy(); - expect(delay <= max).toBeTruthy(); - }); + const expectedDelayWithoutJitter = 1000 * Math.pow(2.0, index) + const jitter = expectedDelayWithoutJitter * 0.2 + const min = expectedDelayWithoutJitter - jitter + const max = expectedDelayWithoutJitter + jitter + + expect(delay >= min).toBeTruthy() + expect(delay <= max).toBeTruthy() + }) } -function expectAllTransactionsToBeClosed(transactions) { - transactions.forEach(tx => expect(tx.isOpen()).toBeFalsy()); +function expectAllTransactionsToBeClosed (transactions) { + transactions.forEach(tx => expect(tx.isOpen()).toBeFalsy()) } class FakeTransaction { - - constructor(commitErrorCode, rollbackErrorCode) { - this._commitErrorCode = commitErrorCode; - this._rollbackErrorCode = rollbackErrorCode; - this._open = true; + constructor (commitErrorCode, rollbackErrorCode) { + this._commitErrorCode = commitErrorCode + this._rollbackErrorCode = rollbackErrorCode + this._open = true } - isOpen() { - return this._open; + isOpen () { + return this._open } - commit() { - this._open = false; + commit () { + this._open = false if (this._commitErrorCode) { - return Promise.reject(error(this._commitErrorCode)); + return Promise.reject(error(this._commitErrorCode)) } - return Promise.resolve(); + return Promise.resolve() } - rollback() { - this._open = false; + rollback () { + this._open = false if (this._rollbackErrorCode) { - return Promise.reject(error(this._rollbackErrorCode)); + return Promise.reject(error(this._rollbackErrorCode)) } - return Promise.resolve(); + return Promise.resolve() } } diff --git a/test/internal/tx-config.test.js b/test/internal/tx-config.test.js index 023727475..d6c38f314 100644 --- a/test/internal/tx-config.test.js +++ b/test/internal/tx-config.test.js @@ -16,86 +16,88 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import TxConfig from '../../src/v1/internal/tx-config'; -import {int} from '../../src/v1'; +import TxConfig from '../../src/v1/internal/tx-config' +import { int } from '../../src/v1' describe('TxConfig', () => { - it('should be possible to construct from null', () => { - testEmptyConfigCreation(null); - }); + testEmptyConfigCreation(null) + }) it('should be possible to construct from undefined', () => { - testEmptyConfigCreation(undefined); - }); + testEmptyConfigCreation(undefined) + }) it('should be possible to construct from empty object', () => { - testEmptyConfigCreation({}); - }); + testEmptyConfigCreation({}) + }) it('should fail to construct from array', () => { - expect(() => new TxConfig([])).toThrowError(TypeError); - }); + expect(() => new TxConfig([])).toThrowError(TypeError) + }) it('should fail to construct from function', () => { - const func = () => { - }; - expect(() => new TxConfig(func)).toThrowError(TypeError); - }); + const func = () => {} + expect(() => new TxConfig(func)).toThrowError(TypeError) + }) it('should expose empty config', () => { - const config = TxConfig.empty(); - expect(config).toBeDefined(); - expect(config.isEmpty()).toBeTruthy(); - }); + const config = TxConfig.empty() + expect(config).toBeDefined() + expect(config.isEmpty()).toBeTruthy() + }) it('should fail to construct with invalid timeout', () => { - const invalidTimeoutValues = ['15s', [15], {}, 0, int(0), -42, int(-42)]; + const invalidTimeoutValues = ['15s', [15], {}, 0, int(0), -42, int(-42)] invalidTimeoutValues.forEach(invalidValue => - expect(() => new TxConfig({timeout: invalidValue})).toThrow()); - }); + expect(() => new TxConfig({ timeout: invalidValue })).toThrow() + ) + }) it('should construct with valid timeout', () => { - testConfigCreationWithTimeout(1); - testConfigCreationWithTimeout(42000); + testConfigCreationWithTimeout(1) + testConfigCreationWithTimeout(42000) - testConfigCreationWithTimeout(int(1)); - testConfigCreationWithTimeout(int(424242)); - }); + testConfigCreationWithTimeout(int(1)) + testConfigCreationWithTimeout(int(424242)) + }) it('should fail to construct with invalid metadata', () => { - const invalidMetadataValues = ['hello', [1, 2, 3], () => 'Hello', 42]; + const invalidMetadataValues = ['hello', [1, 2, 3], () => 'Hello', 42] invalidMetadataValues.forEach(invalidValue => - expect(() => new TxConfig({metadata: invalidValue})).toThrow()); - }); + expect(() => new TxConfig({ metadata: invalidValue })).toThrow() + ) + }) it('should construct with valid metadata', () => { - testEmptyConfigCreation({metadata: {}}); - - testConfigCreationWithMetadata({key: 'value'}); - testConfigCreationWithMetadata({map: {key1: 1, key2: '2', key3: []}, array: [1, 2, 3, '4']}); - }); - - function testEmptyConfigCreation(value) { - const config = new TxConfig(value); - expect(config).toBeDefined(); - expect(config.isEmpty()).toBeTruthy(); + testEmptyConfigCreation({ metadata: {} }) + + testConfigCreationWithMetadata({ key: 'value' }) + testConfigCreationWithMetadata({ + map: { key1: 1, key2: '2', key3: [] }, + array: [1, 2, 3, '4'] + }) + }) + + function testEmptyConfigCreation (value) { + const config = new TxConfig(value) + expect(config).toBeDefined() + expect(config.isEmpty()).toBeTruthy() } - function testConfigCreationWithTimeout(value) { - const config = new TxConfig({timeout: value}); - expect(config).toBeDefined(); - expect(config.isEmpty()).toBeFalsy(); - expect(config.timeout).toEqual(int(value)); + function testConfigCreationWithTimeout (value) { + const config = new TxConfig({ timeout: value }) + expect(config).toBeDefined() + expect(config.isEmpty()).toBeFalsy() + expect(config.timeout).toEqual(int(value)) } - function testConfigCreationWithMetadata(value) { - const config = new TxConfig({metadata: value}); - expect(config).toBeDefined(); - expect(config.isEmpty()).toBeFalsy(); - expect(config.metadata).toEqual(value); + function testConfigCreationWithMetadata (value) { + const config = new TxConfig({ metadata: value }) + expect(config).toBeDefined() + expect(config.isEmpty()).toBeFalsy() + expect(config.metadata).toEqual(value) } - -}); +}) diff --git a/test/internal/url-util.test.js b/test/internal/url-util.test.js index 9cd5b440f..2550c1571 100644 --- a/test/internal/url-util.test.js +++ b/test/internal/url-util.test.js @@ -17,471 +17,479 @@ * limitations under the License. */ -import urlUtil from '../../src/v1/internal/url-util'; +import urlUtil from '../../src/v1/internal/url-util' describe('url-util', () => { - it('should parse URL with just host name', () => { verifyUrl('localhost', { host: 'localhost' - }); + }) verifyUrl('neo4j.com', { host: 'neo4j.com' - }); + }) verifyUrl('some-neo4j-server.com', { host: 'some-neo4j-server.com' - }); + }) verifyUrl('ec2-34-242-76-91.eu-west-1.compute.aws.com', { host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com' - }); - }); + }) + }) it('should parse URL with just IPv4 address', () => { verifyUrl('127.0.0.1', { host: '127.0.0.1' - }); + }) verifyUrl('10.10.192.0', { host: '10.10.192.0' - }); + }) verifyUrl('172.10.5.1', { host: '172.10.5.1' - }); + }) verifyUrl('34.242.76.91', { host: '34.242.76.91' - }); - }); + }) + }) it('should parse URL with just IPv6 address', () => { verifyUrl('[::1]', { host: '::1', ipv6: true - }); + }) verifyUrl('[ff02::2:ff00:0]', { host: 'ff02::2:ff00:0', ipv6: true - }); + }) verifyUrl('[1afc:0:a33:85a3::ff2f]', { host: '1afc:0:a33:85a3::ff2f', ipv6: true - }); + }) verifyUrl('[ff0a::101]', { host: 'ff0a::101', ipv6: true - }); + }) verifyUrl('[2a05:d018:270:f400:6d8c:d425:c5f:97f3]', { host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', ipv6: true - }); + }) verifyUrl('[fe80::1%lo0]', { host: 'fe80::1%lo0', ipv6: true - }); - }); + }) + }) it('should parse URL with host name and query', () => { verifyUrl('localhost?key1=value1&key2=value2', { host: 'localhost', - query: {key1: 'value1', key2: 'value2'} - }); + query: { key1: 'value1', key2: 'value2' } + }) verifyUrl('neo4j.com/?key1=1&key2=2', { host: 'neo4j.com', - query: {key1: '1', key2: '2'} - }); + query: { key1: '1', key2: '2' } + }) verifyUrl('some-neo4j-server.com?a=value1&b=value2&c=value3', { host: 'some-neo4j-server.com', - query: {a: 'value1', b: 'value2', c: 'value3'} - }); - - verifyUrl('ec2-34-242-76-91.eu-west-1.compute.aws.com/?foo=1&bar=2&baz=3&qux=4', { - host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', - query: {foo: '1', bar: '2', baz: '3', qux: '4'} - }); - }); + query: { a: 'value1', b: 'value2', c: 'value3' } + }) + + verifyUrl( + 'ec2-34-242-76-91.eu-west-1.compute.aws.com/?foo=1&bar=2&baz=3&qux=4', + { + host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', + query: { foo: '1', bar: '2', baz: '3', qux: '4' } + } + ) + }) it('should parse URL with IPv4 address and query', () => { verifyUrl('127.0.0.1?key1=value1&key2=value2', { host: '127.0.0.1', - query: {key1: 'value1', key2: 'value2'} - }); + query: { key1: 'value1', key2: 'value2' } + }) verifyUrl('10.10.192.0?key1=1&key2=2', { host: '10.10.192.0', - query: {key1: '1', key2: '2'} - }); + query: { key1: '1', key2: '2' } + }) verifyUrl('172.10.5.1?a=value1&b=value2&c=value3', { host: '172.10.5.1', - query: {a: 'value1', b: 'value2', c: 'value3'} - }); + query: { a: 'value1', b: 'value2', c: 'value3' } + }) verifyUrl('34.242.76.91/?foo=1&bar=2&baz=3&qux=4', { host: '34.242.76.91', - query: {foo: '1', bar: '2', baz: '3', qux: '4'} - }); - }); + query: { foo: '1', bar: '2', baz: '3', qux: '4' } + }) + }) it('should parse URL with IPv6 address and query', () => { verifyUrl('[::1]?key1=value1&key2=value2', { host: '::1', - query: {key1: 'value1', key2: 'value2'}, + query: { key1: 'value1', key2: 'value2' }, ipv6: true - }); + }) verifyUrl('[ff02::2:ff00:0]?key1=1&key2=2', { host: 'ff02::2:ff00:0', - query: {key1: '1', key2: '2'}, + query: { key1: '1', key2: '2' }, ipv6: true - }); + }) verifyUrl('[1afc:0:a33:85a3::ff2f]/?a=value1&b=value2&c=value3', { host: '1afc:0:a33:85a3::ff2f', - query: {a: 'value1', b: 'value2', c: 'value3'}, + query: { a: 'value1', b: 'value2', c: 'value3' }, ipv6: true - }); + }) verifyUrl('[ff0a::101]/?foo=1&bar=2&baz=3&qux=4', { host: 'ff0a::101', - query: {foo: '1', bar: '2', baz: '3', qux: '4'}, + query: { foo: '1', bar: '2', baz: '3', qux: '4' }, ipv6: true - }); + }) verifyUrl('[2a05:d018:270:f400:6d8c:d425:c5f:97f3]?animal=apa', { host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', - query: {animal: 'apa'}, + query: { animal: 'apa' }, ipv6: true - }); + }) verifyUrl('[fe80::1%lo0]?animal=apa', { host: 'fe80::1%lo0', - query: {animal: 'apa'}, + query: { animal: 'apa' }, ipv6: true - }); - }); + }) + }) it('should parse URL with scheme, host name and query', () => { verifyUrl('http://localhost?key1=value1&key2=value2', { scheme: 'http', host: 'localhost', - query: {key1: 'value1', key2: 'value2'} - }); + query: { key1: 'value1', key2: 'value2' } + }) verifyUrl('https://neo4j.com/?key1=1&key2=2', { scheme: 'https', host: 'neo4j.com', - query: {key1: '1', key2: '2'} - }); + query: { key1: '1', key2: '2' } + }) verifyUrl('bolt://some-neo4j-server.com/?a=value1&b=value2&c=value3', { scheme: 'bolt', host: 'some-neo4j-server.com', - query: {a: 'value1', b: 'value2', c: 'value3'} - }); - - verifyUrl('bolt+routing://ec2-34-242-76-91.eu-west-1.compute.aws.com?foo=1&bar=2&baz=3&qux=4', { - scheme: 'bolt+routing', - host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', - query: {foo: '1', bar: '2', baz: '3', qux: '4'} - }); - }); + query: { a: 'value1', b: 'value2', c: 'value3' } + }) + + verifyUrl( + 'bolt+routing://ec2-34-242-76-91.eu-west-1.compute.aws.com?foo=1&bar=2&baz=3&qux=4', + { + scheme: 'bolt+routing', + host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', + query: { foo: '1', bar: '2', baz: '3', qux: '4' } + } + ) + }) it('should parse URL with scheme, IPv4 address and query', () => { verifyUrl('ftp://127.0.0.1/?key1=value1&key2=value2', { scheme: 'ftp', host: '127.0.0.1', - query: {key1: 'value1', key2: 'value2'} - }); + query: { key1: 'value1', key2: 'value2' } + }) verifyUrl('bolt+routing://10.10.192.0?key1=1&key2=2', { scheme: 'bolt+routing', host: '10.10.192.0', - query: {key1: '1', key2: '2'} - }); + query: { key1: '1', key2: '2' } + }) verifyUrl('bolt://172.10.5.1?a=value1&b=value2&c=value3', { scheme: 'bolt', host: '172.10.5.1', - query: {a: 'value1', b: 'value2', c: 'value3'} - }); + query: { a: 'value1', b: 'value2', c: 'value3' } + }) verifyUrl('https://34.242.76.91/?foo=1&bar=2&baz=3&qux=4', { scheme: 'https', host: '34.242.76.91', - query: {foo: '1', bar: '2', baz: '3', qux: '4'} - }); - }); + query: { foo: '1', bar: '2', baz: '3', qux: '4' } + }) + }) it('should parse URL with scheme, IPv6 address and query', () => { verifyUrl('bolt+routing://[::1]?key1=value1&key2=value2', { scheme: 'bolt+routing', host: '::1', - query: {key1: 'value1', key2: 'value2'}, + query: { key1: 'value1', key2: 'value2' }, ipv6: true - }); + }) verifyUrl('http://[ff02::2:ff00:0]?key1=1&key2=2', { scheme: 'http', host: 'ff02::2:ff00:0', - query: {key1: '1', key2: '2'}, + query: { key1: '1', key2: '2' }, ipv6: true - }); + }) verifyUrl('https://[1afc:0:a33:85a3::ff2f]/?a=value1&b=value2&c=value3', { scheme: 'https', host: '1afc:0:a33:85a3::ff2f', - query: {a: 'value1', b: 'value2', c: 'value3'}, + query: { a: 'value1', b: 'value2', c: 'value3' }, ipv6: true - }); + }) verifyUrl('bolt://[ff0a::101]/?foo=1&bar=2&baz=3&qux=4', { scheme: 'bolt', host: 'ff0a::101', - query: {foo: '1', bar: '2', baz: '3', qux: '4'}, + query: { foo: '1', bar: '2', baz: '3', qux: '4' }, ipv6: true - }); + }) - verifyUrl('bolt+routing://[2a05:d018:270:f400:6d8c:d425:c5f:97f3]?animal=apa', { - scheme: 'bolt+routing', - host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', - query: {animal: 'apa'}, - ipv6: true - }); + verifyUrl( + 'bolt+routing://[2a05:d018:270:f400:6d8c:d425:c5f:97f3]?animal=apa', + { + scheme: 'bolt+routing', + host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', + query: { animal: 'apa' }, + ipv6: true + } + ) verifyUrl('bolt+routing://[fe80::1%lo0]?animal=apa', { scheme: 'bolt+routing', host: 'fe80::1%lo0', - query: {animal: 'apa'}, + query: { animal: 'apa' }, ipv6: true - }); - }); + }) + }) it('should parse URL with host name and port', () => { verifyUrl('localhost:1212', { host: 'localhost', port: 1212 - }); + }) verifyUrl('neo4j.com:8888', { host: 'neo4j.com', port: 8888 - }); + }) verifyUrl('some-neo4j-server.com:42', { host: 'some-neo4j-server.com', port: 42 - }); + }) verifyUrl('ec2-34-242-76-91.eu-west-1.compute.aws.com:62220', { host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', port: 62220 - }); - }); + }) + }) it('should parse URL with IPv4 address and port', () => { verifyUrl('127.0.0.1:9090', { host: '127.0.0.1', port: 9090 - }); + }) verifyUrl('10.10.192.0:22000', { host: '10.10.192.0', port: 22000 - }); + }) verifyUrl('172.10.5.1:42', { host: '172.10.5.1', port: 42 - }); + }) verifyUrl('34.242.76.91:7687', { host: '34.242.76.91', port: 7687 - }); - }); + }) + }) it('should parse URL with IPv6 address and port', () => { verifyUrl('[::1]:36000', { host: '::1', port: 36000, ipv6: true - }); + }) verifyUrl('[ff02::2:ff00:0]:8080', { host: 'ff02::2:ff00:0', port: 8080, ipv6: true - }); + }) verifyUrl('[1afc:0:a33:85a3::ff2f]:7474', { host: '1afc:0:a33:85a3::ff2f', port: 7474, ipv6: true - }); + }) verifyUrl('[ff0a::101]:1000', { host: 'ff0a::101', port: 1000, ipv6: true - }); + }) verifyUrl('[2a05:d018:270:f400:6d8c:d425:c5f:97f3]:7475', { host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', port: 7475, ipv6: true - }); + }) verifyUrl('[fe80::1%lo0]:7475', { host: 'fe80::1%lo0', port: 7475, ipv6: true - }); - }); + }) + }) it('should parse URL with scheme and host name', () => { verifyUrl('ftp://localhost', { scheme: 'ftp', host: 'localhost' - }); + }) verifyUrl('https://neo4j.com', { scheme: 'https', host: 'neo4j.com' - }); + }) verifyUrl('wss://some-neo4j-server.com', { scheme: 'wss', host: 'some-neo4j-server.com' - }); + }) verifyUrl('bolt://ec2-34-242-76-91.eu-west-1.compute.aws.com', { scheme: 'bolt', host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com' - }); - }); + }) + }) it('should parse URL with scheme and IPv4 address', () => { verifyUrl('bolt+routing://127.0.0.1', { scheme: 'bolt+routing', host: '127.0.0.1' - }); + }) verifyUrl('http://10.10.192.0', { scheme: 'http', host: '10.10.192.0' - }); + }) verifyUrl('ws://172.10.5.1', { scheme: 'ws', host: '172.10.5.1' - }); + }) verifyUrl('bolt://34.242.76.91', { scheme: 'bolt', host: '34.242.76.91' - }); - }); + }) + }) it('should parse URL with scheme and IPv6 address', () => { verifyUrl('https://[::1]', { scheme: 'https', host: '::1', ipv6: true - }); + }) verifyUrl('http://[ff02::2:ff00:0]', { scheme: 'http', host: 'ff02::2:ff00:0', ipv6: true - }); + }) verifyUrl('bolt+routing://[1afc:0:a33:85a3::ff2f]', { scheme: 'bolt+routing', host: '1afc:0:a33:85a3::ff2f', ipv6: true - }); + }) verifyUrl('bolt://[ff0a::101]', { scheme: 'bolt', host: 'ff0a::101', ipv6: true - }); + }) verifyUrl('bolt+routing://[2a05:d018:270:f400:6d8c:d425:c5f:97f3]', { scheme: 'bolt+routing', host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', ipv6: true - }); + }) verifyUrl('bolt+routing://[fe80::1%lo0]', { scheme: 'bolt+routing', host: 'fe80::1%lo0', ipv6: true - }); - }); + }) + }) it('should parse URL with scheme, host name and port', () => { verifyUrl('http://localhost:8080', { scheme: 'http', host: 'localhost', port: 8080 - }); + }) verifyUrl('bolt://neo4j.com:42', { scheme: 'bolt', host: 'neo4j.com', port: 42 - }); + }) verifyUrl('bolt+routing://some-neo4j-server.com:12000', { scheme: 'bolt+routing', host: 'some-neo4j-server.com', port: 12000 - }); + }) verifyUrl('wss://ec2-34-242-76-91.eu-west-1.compute.aws.com:2626', { scheme: 'wss', host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', port: 2626 - }); - }); + }) + }) it('should parse URL with scheme, IPv4 address and port', () => { verifyUrl('bolt://127.0.0.1:9091', { scheme: 'bolt', host: '127.0.0.1', port: 9091 - }); + }) verifyUrl('bolt://10.10.192.0:7447', { scheme: 'bolt', host: '10.10.192.0', port: 7447 - }); + }) verifyUrl('bolt+routing://172.10.5.1:8888', { scheme: 'bolt+routing', host: '172.10.5.1', port: 8888 - }); + }) verifyUrl('https://34.242.76.91:42', { scheme: 'https', host: '34.242.76.91', port: 42 - }); - }); + }) + }) it('should parse URL with scheme, IPv6 address and port', () => { verifyUrl('http://[::1]:9123', { @@ -489,305 +497,341 @@ describe('url-util', () => { host: '::1', port: 9123, ipv6: true - }); + }) verifyUrl('bolt://[ff02::2:ff00:0]:3831', { scheme: 'bolt', host: 'ff02::2:ff00:0', port: 3831, ipv6: true - }); + }) verifyUrl('bolt+routing://[1afc:0:a33:85a3::ff2f]:50505', { scheme: 'bolt+routing', host: '1afc:0:a33:85a3::ff2f', port: 50505, ipv6: true - }); + }) verifyUrl('ftp://[ff0a::101]:4242', { scheme: 'ftp', host: 'ff0a::101', port: 4242, ipv6: true - }); + }) verifyUrl('wss://[2a05:d018:270:f400:6d8c:d425:c5f:97f3]:22', { scheme: 'wss', host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', port: 22, ipv6: true - }); + }) verifyUrl('wss://[fe80::1%lo0]:22', { scheme: 'wss', host: 'fe80::1%lo0', port: 22, ipv6: true - }); - }); + }) + }) it('should parse URL with scheme, host name, port and query', () => { verifyUrl('http://localhost:3032/?key1=value1&key2=value2', { scheme: 'http', host: 'localhost', port: 3032, - query: {key1: 'value1', key2: 'value2'} - }); + query: { key1: 'value1', key2: 'value2' } + }) verifyUrl('https://neo4j.com:7575?foo=bar&baz=qux', { scheme: 'https', host: 'neo4j.com', port: 7575, - query: {foo: 'bar', baz: 'qux'} - }); + query: { foo: 'bar', baz: 'qux' } + }) verifyUrl('bolt+routing://some-neo4j-server.com:14500?key=value', { scheme: 'bolt+routing', host: 'some-neo4j-server.com', port: 14500, - query: {key: 'value'} - }); - - verifyUrl('ws://ec2-34-242-76-91.eu-west-1.compute.aws.com:30270?a=1&b=2&c=3&d=4', { - scheme: 'ws', - host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', - port: 30270, - query: {a: '1', b: '2', c: '3', d: '4'} - }); - }); + query: { key: 'value' } + }) + + verifyUrl( + 'ws://ec2-34-242-76-91.eu-west-1.compute.aws.com:30270?a=1&b=2&c=3&d=4', + { + scheme: 'ws', + host: 'ec2-34-242-76-91.eu-west-1.compute.aws.com', + port: 30270, + query: { a: '1', b: '2', c: '3', d: '4' } + } + ) + }) it('should parse URL with scheme, IPv4 address, port and query', () => { verifyUrl('bolt://127.0.0.1:30399?key1=value1&key2=value2', { scheme: 'bolt', host: '127.0.0.1', port: 30399, - query: {key1: 'value1', key2: 'value2'} - }); + query: { key1: 'value1', key2: 'value2' } + }) verifyUrl('bolt+routing://10.10.192.0:12100/?foo=bar&baz=qux', { scheme: 'bolt+routing', host: '10.10.192.0', port: 12100, - query: {foo: 'bar', baz: 'qux'} - }); + query: { foo: 'bar', baz: 'qux' } + }) verifyUrl('bolt://172.10.5.1:22?a=1&b=2&c=3&d=4', { scheme: 'bolt', host: '172.10.5.1', port: 22, - query: {a: '1', b: '2', c: '3', d: '4'} - }); + query: { a: '1', b: '2', c: '3', d: '4' } + }) verifyUrl('http://34.242.76.91:1829?key=value', { scheme: 'http', host: '34.242.76.91', port: 1829, - query: {key: 'value'} - }); - }); + query: { key: 'value' } + }) + }) it('should parse URL with scheme, IPv6 address, port and query', () => { verifyUrl('https://[::1]:4217?key=value', { scheme: 'https', host: '::1', port: 4217, - query: {key: 'value'}, + query: { key: 'value' }, ipv6: true - }); + }) verifyUrl('bolt+routing://[ff02::2:ff00:0]:22/?animal1=apa&animal2=dog', { scheme: 'bolt+routing', host: 'ff02::2:ff00:0', port: 22, - query: {animal1: 'apa', animal2: 'dog'}, + query: { animal1: 'apa', animal2: 'dog' }, ipv6: true - }); + }) verifyUrl('bolt://[1afc:0:a33:85a3::ff2f]:4242?a=1&b=2&c=3&d=4', { scheme: 'bolt', host: '1afc:0:a33:85a3::ff2f', port: 4242, - query: {a: '1', b: '2', c: '3', d: '4'}, + query: { a: '1', b: '2', c: '3', d: '4' }, ipv6: true - }); + }) verifyUrl('wss://[ff0a::101]:24240?foo=bar&baz=qux', { scheme: 'wss', host: 'ff0a::101', port: 24240, - query: {foo: 'bar', baz: 'qux'}, + query: { foo: 'bar', baz: 'qux' }, ipv6: true - }); + }) - verifyUrl('https://[2a05:d018:270:f400:6d8c:d425:c5f:97f3]:42?key1=value1&key2=value2', { - scheme: 'https', - host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', - port: 42, - query: {key1: 'value1', key2: 'value2'}, - ipv6: true - }); + verifyUrl( + 'https://[2a05:d018:270:f400:6d8c:d425:c5f:97f3]:42?key1=value1&key2=value2', + { + scheme: 'https', + host: '2a05:d018:270:f400:6d8c:d425:c5f:97f3', + port: 42, + query: { key1: 'value1', key2: 'value2' }, + ipv6: true + } + ) verifyUrl('https://[fe80::1%lo0]:4242?key1=value1', { scheme: 'https', host: 'fe80::1%lo0', port: 4242, - query: {key1: 'value1'}, + query: { key1: 'value1' }, ipv6: true - }); - }); + }) + }) it('should fail to parse URL without host', () => { - expect(() => parse('http://')).toThrow(); - expect(() => parse('bolt://')).toThrow(); - expect(() => parse('bolt+routing://')).toThrow(); - }); + expect(() => parse('http://')).toThrow() + expect(() => parse('bolt://')).toThrow() + expect(() => parse('bolt+routing://')).toThrow() + }) it('should fail to parse URL with duplicated query parameters', () => { - expect(() => parse('bolt://localhost/?key=value1&key=value2')).toThrow(); - expect(() => parse('bolt://localhost:8080/?key=value1&key=value2')).toThrow(); - - expect(() => parse('bolt+routing://10.10.127.5?key=value1&key=value2')).toThrow(); - expect(() => parse('bolt+routing://10.10.127.5:8080?key=value1&key=value2')).toThrow(); - - expect(() => parse('https://[ff0a::101]?key=value1&key=value2')).toThrow(); - expect(() => parse('https://[ff0a::101]:8080?key=value1&key=value2')).toThrow(); - }); + expect(() => parse('bolt://localhost/?key=value1&key=value2')).toThrow() + expect(() => + parse('bolt://localhost:8080/?key=value1&key=value2') + ).toThrow() + + expect(() => + parse('bolt+routing://10.10.127.5?key=value1&key=value2') + ).toThrow() + expect(() => + parse('bolt+routing://10.10.127.5:8080?key=value1&key=value2') + ).toThrow() + + expect(() => parse('https://[ff0a::101]?key=value1&key=value2')).toThrow() + expect(() => + parse('https://[ff0a::101]:8080?key=value1&key=value2') + ).toThrow() + }) it('should fail to parse URL with empty query key', () => { - expect(() => parse('bolt://localhost?=value')).toThrow(); - expect(() => parse('bolt://localhost:8080?=value')).toThrow(); + expect(() => parse('bolt://localhost?=value')).toThrow() + expect(() => parse('bolt://localhost:8080?=value')).toThrow() - expect(() => parse('bolt+routing://10.10.127.5?=value')).toThrow(); - expect(() => parse('bolt+routing://10.10.127.5:8080?=value')).toThrow(); + expect(() => parse('bolt+routing://10.10.127.5?=value')).toThrow() + expect(() => parse('bolt+routing://10.10.127.5:8080?=value')).toThrow() - expect(() => parse('https://[ff0a::101]/?value=')).toThrow(); - expect(() => parse('https://[ff0a::101]:8080/?=value')).toThrow(); - }); + expect(() => parse('https://[ff0a::101]/?value=')).toThrow() + expect(() => parse('https://[ff0a::101]:8080/?=value')).toThrow() + }) it('should fail to parse URL with empty query value', () => { - expect(() => parse('bolt://localhost?key=')).toThrow(); - expect(() => parse('bolt://localhost:8080?key=')).toThrow(); + expect(() => parse('bolt://localhost?key=')).toThrow() + expect(() => parse('bolt://localhost:8080?key=')).toThrow() - expect(() => parse('bolt+routing://10.10.127.5/?key=')).toThrow(); - expect(() => parse('bolt+routing://10.10.127.5:8080/?key=')).toThrow(); + expect(() => parse('bolt+routing://10.10.127.5/?key=')).toThrow() + expect(() => parse('bolt+routing://10.10.127.5:8080/?key=')).toThrow() - expect(() => parse('https://[ff0a::101]?key=')).toThrow(); - expect(() => parse('https://[ff0a::101]:8080?key=')).toThrow(); - }); + expect(() => parse('https://[ff0a::101]?key=')).toThrow() + expect(() => parse('https://[ff0a::101]:8080?key=')).toThrow() + }) it('should fail to parse URL with no query value', () => { - expect(() => parse('bolt://localhost?key')).toThrow(); - expect(() => parse('bolt://localhost:8080?key')).toThrow(); + expect(() => parse('bolt://localhost?key')).toThrow() + expect(() => parse('bolt://localhost:8080?key')).toThrow() - expect(() => parse('bolt+routing://10.10.127.5/?key')).toThrow(); - expect(() => parse('bolt+routing://10.10.127.5:8080/?key')).toThrow(); + expect(() => parse('bolt+routing://10.10.127.5/?key')).toThrow() + expect(() => parse('bolt+routing://10.10.127.5:8080/?key')).toThrow() - expect(() => parse('https://[ff0a::101]?key')).toThrow(); - expect(() => parse('https://[ff0a::101]:8080?key')).toThrow(); - }); + expect(() => parse('https://[ff0a::101]?key')).toThrow() + expect(() => parse('https://[ff0a::101]:8080?key')).toThrow() + }) it('should fail to parse non-strings', () => { - expect(() => parse({})).toThrowError(TypeError); - expect(() => parse(['bolt://localhost:2020'])).toThrowError(TypeError); - expect(() => parse(() => 'bolt://localhost:8888')).toThrowError(TypeError); - }); + expect(() => parse({})).toThrowError(TypeError) + expect(() => parse(['bolt://localhost:2020'])).toThrowError(TypeError) + expect(() => parse(() => 'bolt://localhost:8888')).toThrowError(TypeError) + }) it('should format IPv4 address', () => { - expect(urlUtil.formatIPv4Address('127.0.0.1', 4242)).toEqual('127.0.0.1:4242'); - expect(urlUtil.formatIPv4Address('192.168.10.10', 8080)).toEqual('192.168.10.10:8080'); - expect(urlUtil.formatIPv4Address('8.8.8.8', 80)).toEqual('8.8.8.8:80'); - }); + expect(urlUtil.formatIPv4Address('127.0.0.1', 4242)).toEqual( + '127.0.0.1:4242' + ) + expect(urlUtil.formatIPv4Address('192.168.10.10', 8080)).toEqual( + '192.168.10.10:8080' + ) + expect(urlUtil.formatIPv4Address('8.8.8.8', 80)).toEqual('8.8.8.8:80') + }) it('should format IPv6 address', () => { - expect(urlUtil.formatIPv6Address('::1', 1200)).toEqual('[::1]:1200'); - expect(urlUtil.formatIPv6Address('ff0a::101', 8080)).toEqual('[ff0a::101]:8080'); + expect(urlUtil.formatIPv6Address('::1', 1200)).toEqual('[::1]:1200') + expect(urlUtil.formatIPv6Address('ff0a::101', 8080)).toEqual( + '[ff0a::101]:8080' + ) - expect(urlUtil.formatIPv6Address('[::1]', 42)).toEqual('[::1]:42'); - expect(urlUtil.formatIPv6Address('[1afc:0:a33:85a3::ff2f]', 20201)).toEqual('[1afc:0:a33:85a3::ff2f]:20201'); - }); + expect(urlUtil.formatIPv6Address('[::1]', 42)).toEqual('[::1]:42') + expect(urlUtil.formatIPv6Address('[1afc:0:a33:85a3::ff2f]', 20201)).toEqual( + '[1afc:0:a33:85a3::ff2f]:20201' + ) + }) it('should fail to format partially escaped IPv6 address', () => { - expect(() => urlUtil.formatIPv6Address('[::1', 1000)).toThrow(); - expect(() => urlUtil.formatIPv6Address('::1]', 2000)).toThrow(); + expect(() => urlUtil.formatIPv6Address('[::1', 1000)).toThrow() + expect(() => urlUtil.formatIPv6Address('::1]', 2000)).toThrow() - expect(() => urlUtil.formatIPv6Address('[1afc:0:a33:85a3::ff2f', 3000)).toThrow(); - expect(() => urlUtil.formatIPv6Address('1afc:0:a33:85a3::ff2f]', 4000)).toThrow(); - }); + expect(() => + urlUtil.formatIPv6Address('[1afc:0:a33:85a3::ff2f', 3000) + ).toThrow() + expect(() => + urlUtil.formatIPv6Address('1afc:0:a33:85a3::ff2f]', 4000) + ).toThrow() + }) it('should use default ports when no port specified', () => { - expect(parse('bolt://localhost').port).toEqual(urlUtil.defaultPortForScheme('bolt')); - expect(parse('bolt+routing://localhost').port).toEqual(urlUtil.defaultPortForScheme('bolt')); - - expect(parse('http://localhost').port).toEqual(urlUtil.defaultPortForScheme('http')); - expect(parse('https://localhost').port).toEqual(urlUtil.defaultPortForScheme('https')); - }); + expect(parse('bolt://localhost').port).toEqual( + urlUtil.defaultPortForScheme('bolt') + ) + expect(parse('bolt+routing://localhost').port).toEqual( + urlUtil.defaultPortForScheme('bolt') + ) + + expect(parse('http://localhost').port).toEqual( + urlUtil.defaultPortForScheme('http') + ) + expect(parse('https://localhost').port).toEqual( + urlUtil.defaultPortForScheme('https') + ) + }) it('should parse URLs with port 80', () => { - ['http', 'https', 'ws', 'wss', 'bolt', 'bolt+routing', 'neo4j'].forEach(scheme => { - verifyUrl(`${scheme}://localhost:80`, { - scheme: scheme, - host: 'localhost', - port: 80 - }); - }); - - ['localhost', '127.0.0.1', '192.168.10.29'].forEach(host => { + ;['http', 'https', 'ws', 'wss', 'bolt', 'bolt+routing', 'neo4j'].forEach( + scheme => { + verifyUrl(`${scheme}://localhost:80`, { + scheme: scheme, + host: 'localhost', + port: 80 + }) + } + ) + ;['localhost', '127.0.0.1', '192.168.10.29'].forEach(host => { verifyUrl(`${host}:80`, { host: host, port: 80 - }); - }); - - ['::1', '1afc:0:a33:85a3::ff2f'].forEach(host => { + }) + }) + ;['::1', '1afc:0:a33:85a3::ff2f'].forEach(host => { verifyUrl(`[${host}]:80`, { host: host, port: 80, ipv6: true - }); - }); - }); + }) + }) + }) - function verifyUrl(urlString, expectedUrl) { - const url = parse(urlString); + function verifyUrl (urlString, expectedUrl) { + const url = parse(urlString) if (expectedUrl.scheme) { - expect(url.scheme).toEqual(expectedUrl.scheme); + expect(url.scheme).toEqual(expectedUrl.scheme) } else { - expect(url.scheme).toBeNull(); + expect(url.scheme).toBeNull() } - expect(url.host).toBeDefined(); - expect(url.host).not.toBeNull(); - expect(url.host).toEqual(expectedUrl.host); + expect(url.host).toBeDefined() + expect(url.host).not.toBeNull() + expect(url.host).toEqual(expectedUrl.host) if (expectedUrl.port) { - expect(url.port).toEqual(expectedUrl.port); + expect(url.port).toEqual(expectedUrl.port) } else { - expect(url.port).toEqual(urlUtil.defaultPortForScheme(expectedUrl.scheme)); + expect(url.port).toEqual(urlUtil.defaultPortForScheme(expectedUrl.scheme)) } - verifyHostAndPort(url, expectedUrl); + verifyHostAndPort(url, expectedUrl) if (expectedUrl.query) { - expect(url.query).toEqual(expectedUrl.query); + expect(url.query).toEqual(expectedUrl.query) } else { - expect(url.query).toEqual({}); + expect(url.query).toEqual({}) } } - function verifyHostAndPort(url, expectedUrl) { - const port = expectedUrl.port === 0 || expectedUrl.port ? expectedUrl.port : urlUtil.defaultPortForScheme(expectedUrl.scheme); + function verifyHostAndPort (url, expectedUrl) { + const port = + expectedUrl.port === 0 || expectedUrl.port + ? expectedUrl.port + : urlUtil.defaultPortForScheme(expectedUrl.scheme) if (expectedUrl.ipv6) { - expect(url.hostAndPort).toEqual(`[${expectedUrl.host}]:${port}`); + expect(url.hostAndPort).toEqual(`[${expectedUrl.host}]:${port}`) } else { - expect(url.hostAndPort).toEqual(`${expectedUrl.host}:${port}`); + expect(url.hostAndPort).toEqual(`${expectedUrl.host}:${port}`) } } - function parse(url) { - return urlUtil.parseDatabaseUrl(url); + function parse (url) { + return urlUtil.parseDatabaseUrl(url) } - -}); +}) diff --git a/test/internal/utf8.test.js b/test/internal/utf8.test.js index 68bb54212..ae72523f6 100644 --- a/test/internal/utf8.test.js +++ b/test/internal/utf8.test.js @@ -17,147 +17,147 @@ * limitations under the License. */ -import CombinedBuffer from '../../src/v1/internal/buf/combined-buf'; -import {alloc, utf8} from '../../src/v1/internal/node'; +import CombinedBuffer from '../../src/v1/internal/buf/combined-buf' +import { alloc, utf8 } from '../../src/v1/internal/node' describe('utf8', () => { - it('should have a nice clean buffer position after serializing', () => { // When - const buffer = utf8.encode('hello, world!'); + const buffer = utf8.encode('hello, world!') // Then - expect( buffer.position ).toBe( 0 ); - }); + expect(buffer.position).toBe(0) + }) it('should respect position of single buffer', () => { // When - const buffer = utf8.encode('hello, world!'); - buffer.readInt8(); - const decoded = utf8.decode(buffer, buffer.length - 1); + const buffer = utf8.encode('hello, world!') + buffer.readInt8() + const decoded = utf8.decode(buffer, buffer.length - 1) // Then - expect( decoded ).toBe( "ello, world!" ); + expect(decoded).toBe('ello, world!') expect(buffer.position).toEqual(13) - }); - + }) it('should be able to decode substring', () => { // When - const buffer = utf8.encode('hello, world!'); - buffer.readInt8(); - const decoded = utf8.decode(buffer, 3); + const buffer = utf8.encode('hello, world!') + buffer.readInt8() + const decoded = utf8.decode(buffer, 3) // Then - expect( decoded ).toBe( "ell" ); + expect(decoded).toBe('ell') expect(buffer.position).toEqual(4) - }); + }) it('should read/write utf8', () => { - expect( packAndUnpack( "" ) ).toBe( "" ); - expect( packAndUnpack( "åäö123" ) ).toBe( "åäö123" ); - }); + expect(packAndUnpack('')).toBe('') + expect(packAndUnpack('åäö123')).toBe('åäö123') + }) it('should decode utf8 from a complete combined buffer', () => { // Given - const msg = 'asåfqwer'; - const buf = utf8.encode(msg); - const bufa = buf.readSlice(3); - const bufb = buf.readSlice(3); - const bufc = buf.readSlice(3); - const combined = new CombinedBuffer([bufa, bufb, bufc]); + const msg = 'asåfqwer' + const buf = utf8.encode(msg) + const bufa = buf.readSlice(3) + const bufb = buf.readSlice(3) + const bufc = buf.readSlice(3) + const combined = new CombinedBuffer([bufa, bufb, bufc]) // When - const decoded = utf8.decode(combined, combined.length); + const decoded = utf8.decode(combined, combined.length) // Then - expect(decoded).toBe(msg); - }); + expect(decoded).toBe(msg) + }) it('should decode utf8 from part of a combined buffer', () => { // Given - const msg = 'asåfq'; - const expectMsg = msg.substring(0, msg.length - 1); - const buf = utf8.encode(msg); - const bufa = buf.readSlice(3); - const bufb = buf.readSlice(3); - const unrelatedData = alloc(3); - const combined = new CombinedBuffer([bufa, bufb, unrelatedData]); - - // When + const msg = 'asåfq' + const expectMsg = msg.substring(0, msg.length - 1) + const buf = utf8.encode(msg) + const bufa = buf.readSlice(3) + const bufb = buf.readSlice(3) + const unrelatedData = alloc(3) + const combined = new CombinedBuffer([bufa, bufb, unrelatedData]) + + // When // We read all but the unrelatedData and the last character of bufb - const decoded = utf8.decode(combined, combined.length - 1 - unrelatedData.length); + const decoded = utf8.decode( + combined, + combined.length - 1 - unrelatedData.length + ) // Then - expect(decoded).toBe(expectMsg); - }); + expect(decoded).toBe(expectMsg) + }) it('should respect the position in the combined buffer', () => { // Given - const msg = 'abcdefgh'; - const buf = utf8.encode(msg); - const bufa = buf.readSlice(4); - const bufb = buf.readSlice(4); - const combined = new CombinedBuffer([bufa, bufb]); - //move position forward - combined.readInt8(); - combined.readInt8(); + const msg = 'abcdefgh' + const buf = utf8.encode(msg) + const bufa = buf.readSlice(4) + const bufb = buf.readSlice(4) + const combined = new CombinedBuffer([bufa, bufb]) + // move position forward + combined.readInt8() + combined.readInt8() // When - const decoded = utf8.decode(combined, combined.length - 2); - + const decoded = utf8.decode(combined, combined.length - 2) // Then - expect(decoded).toEqual("cdefgh"); + expect(decoded).toEqual('cdefgh') expect(combined.position).toBe(8) - }); + }) it('should be able to decode a substring in a combined buffer across buffers', () => { // Given - const msg = 'abcdefghijkl'; - const buf = utf8.encode(msg); - const bufa = buf.readSlice(4); - const bufb = buf.readSlice(4); - const bufc = buf.readSlice(4); - const combined = new CombinedBuffer([bufa, bufb, bufc]); - //move position forward - combined.readInt8(); - combined.readInt8(); - combined.readInt8(); - combined.readInt8(); - combined.readInt8(); + const msg = 'abcdefghijkl' + const buf = utf8.encode(msg) + const bufa = buf.readSlice(4) + const bufb = buf.readSlice(4) + const bufc = buf.readSlice(4) + const combined = new CombinedBuffer([bufa, bufb, bufc]) + // move position forward + combined.readInt8() + combined.readInt8() + combined.readInt8() + combined.readInt8() + combined.readInt8() // When - const decoded = utf8.decode(combined, 4); + const decoded = utf8.decode(combined, 4) // Then - expect(decoded).toBe("fghi"); + expect(decoded).toBe('fghi') expect(combined.position).toBe(9) - }); + }) it('should be able to decode a substring in a combined within buffer', () => { // Given - const msg = 'abcdefghijkl'; - const buf = utf8.encode(msg); - const bufa = buf.readSlice(4); - const bufb = buf.readSlice(4); - const bufc = buf.readSlice(4); - const combined = new CombinedBuffer([bufa, bufb, bufc]); - //move position forward - combined.readInt8(); - combined.readInt8(); - combined.readInt8(); - combined.readInt8(); - combined.readInt8(); + const msg = 'abcdefghijkl' + const buf = utf8.encode(msg) + const bufa = buf.readSlice(4) + const bufb = buf.readSlice(4) + const bufc = buf.readSlice(4) + const combined = new CombinedBuffer([bufa, bufb, bufc]) + // move position forward + combined.readInt8() + combined.readInt8() + combined.readInt8() + combined.readInt8() + combined.readInt8() // When - const decoded = utf8.decode(combined, 2); + const decoded = utf8.decode(combined, 2) // Then - expect(decoded).toBe("fg"); + expect(decoded).toBe('fg') expect(combined.position).toBe(7) - }); -}); + }) +}) -function packAndUnpack( str ) { - const buffer = utf8.encode(str); - return utf8.decode( buffer, buffer.length ); +function packAndUnpack (str) { + const buffer = utf8.encode(str) + return utf8.decode(buffer, buffer.length) } diff --git a/test/internal/util.test.js b/test/internal/util.test.js index cafa7003a..ef05199a2 100644 --- a/test/internal/util.test.js +++ b/test/internal/util.test.js @@ -17,203 +17,209 @@ * limitations under the License. */ -import * as util from '../../src/v1/internal/util'; -import {int} from '../../src/v1'; +import * as util from '../../src/v1/internal/util' +import { int } from '../../src/v1' describe('util', () => { - it('should check empty objects', () => { - expect(util.isEmptyObjectOrNull(null)).toBeTruthy(); - expect(util.isEmptyObjectOrNull({})).toBeTruthy(); + expect(util.isEmptyObjectOrNull(null)).toBeTruthy() + expect(util.isEmptyObjectOrNull({})).toBeTruthy() - expect(util.isEmptyObjectOrNull([])).toBeFalsy(); + expect(util.isEmptyObjectOrNull([])).toBeFalsy() const func = () => { - return 42; - }; - expect(util.isEmptyObjectOrNull(func)).toBeFalsy(); - - expect(util.isEmptyObjectOrNull()).toBeFalsy(); - expect(util.isEmptyObjectOrNull(undefined)).toBeFalsy(); - expect(util.isEmptyObjectOrNull(0)).toBeFalsy(); - expect(util.isEmptyObjectOrNull('')).toBeFalsy(); - expect(util.isEmptyObjectOrNull('abc')).toBeFalsy(); - expect(util.isEmptyObjectOrNull({foo: 'bar'})).toBeFalsy(); - }); + return 42 + } + expect(util.isEmptyObjectOrNull(func)).toBeFalsy() + + expect(util.isEmptyObjectOrNull()).toBeFalsy() + expect(util.isEmptyObjectOrNull(undefined)).toBeFalsy() + expect(util.isEmptyObjectOrNull(0)).toBeFalsy() + expect(util.isEmptyObjectOrNull('')).toBeFalsy() + expect(util.isEmptyObjectOrNull('abc')).toBeFalsy() + expect(util.isEmptyObjectOrNull({ foo: 'bar' })).toBeFalsy() + }) it('should check strings', () => { - verifyValidString(''); - verifyValidString(new String('foo')); - verifyValidString(String('foo')); - verifyValidString("hi!"); - - verifyInvalidString({}); - verifyInvalidString({foo: 1}); - verifyInvalidString([]); - verifyInvalidString(['1']); - verifyInvalidString([1, '2']); - verifyInvalidString(console.log); - }); + verifyValidString('') + verifyValidString(String('foo')) + verifyValidString(String('foo')) + verifyValidString('hi!') + + verifyInvalidString({}) + verifyInvalidString({ foo: 1 }) + verifyInvalidString([]) + verifyInvalidString(['1']) + verifyInvalidString([1, '2']) + verifyInvalidString(console.log) + }) it('should check cypher statements (non-empty strings)', () => { - verifyValidString(new String('foo')); - verifyValidString(String('foo')); - verifyValidString("foo"); - - verifyInvalidCypherStatement(''); - verifyInvalidCypherStatement('\n'); - verifyInvalidCypherStatement('\t'); - verifyInvalidCypherStatement('\r'); - verifyInvalidCypherStatement(' '); - verifyInvalidCypherStatement(' \n\r'); - verifyInvalidCypherStatement({}); - verifyInvalidCypherStatement({foo: 1}); - verifyInvalidCypherStatement([]); - verifyInvalidCypherStatement(['1']); - verifyInvalidCypherStatement([1, '2']); - verifyInvalidCypherStatement(console.log); - }); + verifyValidString(String('foo')) + verifyValidString(String('foo')) + verifyValidString('foo') + + verifyInvalidCypherStatement('') + verifyInvalidCypherStatement('\n') + verifyInvalidCypherStatement('\t') + verifyInvalidCypherStatement('\r') + verifyInvalidCypherStatement(' ') + verifyInvalidCypherStatement(' \n\r') + verifyInvalidCypherStatement({}) + verifyInvalidCypherStatement({ foo: 1 }) + verifyInvalidCypherStatement([]) + verifyInvalidCypherStatement(['1']) + verifyInvalidCypherStatement([1, '2']) + verifyInvalidCypherStatement(console.log) + }) it('should check valid query parameters', () => { - verifyValidQueryParameters(null); - verifyValidQueryParameters(undefined); - verifyValidQueryParameters({}); - verifyValidQueryParameters({a: 1, b: 2, c: 3}); - verifyValidQueryParameters({foo: 'bar', baz: 'qux'}); - }); + verifyValidQueryParameters(null) + verifyValidQueryParameters(undefined) + verifyValidQueryParameters({}) + verifyValidQueryParameters({ a: 1, b: 2, c: 3 }) + verifyValidQueryParameters({ foo: 'bar', baz: 'qux' }) + }) it('should check invalid query parameters', () => { - verifyInvalidQueryParameters('parameter'); - verifyInvalidQueryParameters(123); - verifyInvalidQueryParameters([]); - verifyInvalidQueryParameters([1, 2, 3]); - verifyInvalidQueryParameters([null]); - verifyInvalidQueryParameters(['1', '2', '3']); - verifyInvalidQueryParameters(() => [1, 2, 3]); - verifyInvalidQueryParameters(() => ''); - verifyInvalidQueryParameters(() => null); - }); + verifyInvalidQueryParameters('parameter') + verifyInvalidQueryParameters(123) + verifyInvalidQueryParameters([]) + verifyInvalidQueryParameters([1, 2, 3]) + verifyInvalidQueryParameters([null]) + verifyInvalidQueryParameters(['1', '2', '3']) + verifyInvalidQueryParameters(() => [1, 2, 3]) + verifyInvalidQueryParameters(() => '') + verifyInvalidQueryParameters(() => null) + }) it('should check numbers and integers', () => { - verifyValidNumber(0); - verifyValidNumber(1); - verifyValidNumber(42); - verifyValidNumber(-42); - verifyValidNumber(12.001); - verifyValidNumber(-493.423); - - verifyInvalidNumber(int(0)); - verifyInvalidNumber(int(1)); - verifyInvalidNumber(int(147123)); - verifyInvalidNumber(''); - verifyInvalidNumber('42'); - verifyInvalidNumber([]); - verifyInvalidNumber([42]); - verifyInvalidNumber({}); - verifyInvalidNumber({value: 42}); - }); + verifyValidNumber(0) + verifyValidNumber(1) + verifyValidNumber(42) + verifyValidNumber(-42) + verifyValidNumber(12.001) + verifyValidNumber(-493.423) + + verifyInvalidNumber(int(0)) + verifyInvalidNumber(int(1)) + verifyInvalidNumber(int(147123)) + verifyInvalidNumber('') + verifyInvalidNumber('42') + verifyInvalidNumber([]) + verifyInvalidNumber([42]) + verifyInvalidNumber({}) + verifyInvalidNumber({ value: 42 }) + }) it('should check numbers and integers', () => { - verifyValidNumberOrInteger(0); - verifyValidNumberOrInteger(1); - verifyValidNumberOrInteger(42); - verifyValidNumberOrInteger(-42); - verifyValidNumberOrInteger(12.001); - verifyValidNumberOrInteger(-493.423); - - verifyValidNumberOrInteger(int(0)); - verifyValidNumberOrInteger(int(42)); - verifyValidNumberOrInteger(int(1241)); - verifyValidNumberOrInteger(int(441)); - verifyValidNumberOrInteger(int(-100500)); - - verifyInvalidNumberOrInteger(''); - verifyInvalidNumberOrInteger('42'); - verifyInvalidNumberOrInteger([]); - verifyInvalidNumberOrInteger([42]); - verifyInvalidNumberOrInteger({}); - verifyInvalidNumberOrInteger({value: 42}); - }); + verifyValidNumberOrInteger(0) + verifyValidNumberOrInteger(1) + verifyValidNumberOrInteger(42) + verifyValidNumberOrInteger(-42) + verifyValidNumberOrInteger(12.001) + verifyValidNumberOrInteger(-493.423) + + verifyValidNumberOrInteger(int(0)) + verifyValidNumberOrInteger(int(42)) + verifyValidNumberOrInteger(int(1241)) + verifyValidNumberOrInteger(int(441)) + verifyValidNumberOrInteger(int(-100500)) + + verifyInvalidNumberOrInteger('') + verifyInvalidNumberOrInteger('42') + verifyInvalidNumberOrInteger([]) + verifyInvalidNumberOrInteger([42]) + verifyInvalidNumberOrInteger({}) + verifyInvalidNumberOrInteger({ value: 42 }) + }) it('should check dates', () => { - verifyValidDate(new Date()); - verifyValidDate(new Date(0)); - verifyValidDate(new Date(-1)); - verifyValidDate(new Date(2000, 10, 10)); - verifyValidDate(new Date(2000, 10, 10, 10, 10, 10, 10)); - - verifyInvalidDate(new Date('not a valid date')); - verifyInvalidDate(new Date({})); - verifyInvalidDate(new Date([])); - - verifyInvalidDate({}); - verifyInvalidDate([]); - verifyInvalidDate('2007-04-05T12:30-02:00'); - verifyInvalidDate(2019); - }); + verifyValidDate(new Date()) + verifyValidDate(new Date(0)) + verifyValidDate(new Date(-1)) + verifyValidDate(new Date(2000, 10, 10)) + verifyValidDate(new Date(2000, 10, 10, 10, 10, 10, 10)) + + verifyInvalidDate(new Date('not a valid date')) + verifyInvalidDate(new Date({})) + verifyInvalidDate(new Date([])) + + verifyInvalidDate({}) + verifyInvalidDate([]) + verifyInvalidDate('2007-04-05T12:30-02:00') + verifyInvalidDate(2019) + }) it('should check objects', () => { - expect(util.isObject(42)).toBeFalsy(); - expect(util.isObject([])).toBeFalsy(); - expect(util.isObject(() => 'Hello')).toBeFalsy(); - expect(util.isObject('string')).toBeFalsy(); + expect(util.isObject(42)).toBeFalsy() + expect(util.isObject([])).toBeFalsy() + expect(util.isObject(() => 'Hello')).toBeFalsy() + expect(util.isObject('string')).toBeFalsy() - expect(util.isObject({})).toBeTruthy(); - expect(util.isObject({key1: 1, key2: '2'})).toBeTruthy(); - }); + expect(util.isObject({})).toBeTruthy() + expect(util.isObject({ key1: 1, key2: '2' })).toBeTruthy() + }) it('should assert on objects', () => { - expect(() => util.assertObject(42, '')).toThrowError(TypeError); - expect(() => util.assertObject([], '')).toThrowError(TypeError); - expect(() => util.assertObject(() => 'Hello', '')).toThrowError(TypeError); - expect(() => util.assertObject('string', '')).toThrowError(TypeError); + expect(() => util.assertObject(42, '')).toThrowError(TypeError) + expect(() => util.assertObject([], '')).toThrowError(TypeError) + expect(() => util.assertObject(() => 'Hello', '')).toThrowError(TypeError) + expect(() => util.assertObject('string', '')).toThrowError(TypeError) - expect(() => util.assertObject({}, '')).not.toThrow(); - expect(() => util.assertObject({key1: 1, key2: '2'}, '')).not.toThrow(); - }); + expect(() => util.assertObject({}, '')).not.toThrow() + expect(() => util.assertObject({ key1: 1, key2: '2' }, '')).not.toThrow() + }) - function verifyValidString(str) { - expect(util.assertString(str, 'Test string')).toBe(str); + function verifyValidString (str) { + expect(util.assertString(str, 'Test string')).toBe(str) } - function verifyInvalidString(str) { - expect(() => util.assertString(str, 'Test string')).toThrowError(TypeError); + function verifyInvalidString (str) { + expect(() => util.assertString(str, 'Test string')).toThrowError(TypeError) } - function verifyValidNumber(obj) { - expect(util.assertNumber(obj, 'Test number')).toBe(obj); + function verifyValidNumber (obj) { + expect(util.assertNumber(obj, 'Test number')).toBe(obj) } - function verifyInvalidNumber(obj) { - expect(() => util.assertNumber(obj, 'Test number')).toThrowError(TypeError); + function verifyInvalidNumber (obj) { + expect(() => util.assertNumber(obj, 'Test number')).toThrowError(TypeError) } - function verifyValidNumberOrInteger(obj) { - expect(util.assertNumberOrInteger(obj, 'Test object')).toEqual(obj); + function verifyValidNumberOrInteger (obj) { + expect(util.assertNumberOrInteger(obj, 'Test object')).toEqual(obj) } - function verifyInvalidNumberOrInteger(obj) { - expect(() => util.assertNumberOrInteger(obj, 'Test object')).toThrowError(TypeError); + function verifyInvalidNumberOrInteger (obj) { + expect(() => util.assertNumberOrInteger(obj, 'Test object')).toThrowError( + TypeError + ) } - function verifyInvalidCypherStatement(str) { - expect(() => util.validateStatementAndParameters(str, {})).toThrowError(TypeError); + function verifyInvalidCypherStatement (str) { + expect(() => util.validateStatementAndParameters(str, {})).toThrowError( + TypeError + ) } - function verifyValidQueryParameters(obj) { - expect(() => util.validateStatementAndParameters('RETURN 1', obj)).not.toThrow(); + function verifyValidQueryParameters (obj) { + expect(() => + util.validateStatementAndParameters('RETURN 1', obj) + ).not.toThrow() } - function verifyInvalidQueryParameters(obj) { - expect(() => util.validateStatementAndParameters('RETURN 1', obj)).toThrowError(TypeError); + function verifyInvalidQueryParameters (obj) { + expect(() => + util.validateStatementAndParameters('RETURN 1', obj) + ).toThrowError(TypeError) } - function verifyValidDate(obj) { - expect(util.assertValidDate(obj, 'Test date')).toBe(obj); + function verifyValidDate (obj) { + expect(util.assertValidDate(obj, 'Test date')).toBe(obj) } - function verifyInvalidDate(obj) { - expect(() => util.assertValidDate(obj, 'Test date')).toThrowError(TypeError); + function verifyInvalidDate (obj) { + expect(() => util.assertValidDate(obj, 'Test date')).toThrowError(TypeError) } - -}); +}) diff --git a/test/types/index.test.ts b/test/types/index.test.ts index ad6148356..6ba5653cd 100644 --- a/test/types/index.test.ts +++ b/test/types/index.test.ts @@ -17,78 +17,111 @@ * limitations under the License. */ -import neo4j from "../../types/index"; +import neo4j from '../../types/index' -const driver1: neo4j.Driver = neo4j.driver("bolt+routing://localhost"); -const driver2: neo4j.Driver = neo4j.driver("bolt://localhost:7687", neo4j.auth.basic("neo4j", "password")); +const driver1: neo4j.Driver = neo4j.driver('bolt+routing://localhost') +const driver2: neo4j.Driver = neo4j.driver( + 'bolt://localhost:7687', + neo4j.auth.basic('neo4j', 'password') +) -const sessionModeRead: string = neo4j.session.READ; -const sessionModeWrite: string = neo4j.session.WRITE; +const sessionModeRead: string = neo4j.session.READ +const sessionModeWrite: string = neo4j.session.WRITE -const readSession = driver1.session(neo4j.session.READ); -const writeSession = driver1.session(neo4j.session.WRITE); +const readSession = driver1.session(neo4j.session.READ) +const writeSession = driver1.session(neo4j.session.WRITE) -const int1: neo4j.Integer = neo4j.int(42); -const int2: neo4j.Integer = neo4j.int("42"); -const int3: neo4j.Integer = neo4j.int(neo4j.int(42)); -const int4: neo4j.Integer = neo4j.int({low: 1, high: 1}); +const int1: neo4j.Integer = neo4j.int(42) +const int2: neo4j.Integer = neo4j.int('42') +const int3: neo4j.Integer = neo4j.int(neo4j.int(42)) +const int4: neo4j.Integer = neo4j.int({ low: 1, high: 1 }) -const isInt1: boolean = neo4j.isInt({}); -const isInt2: boolean = neo4j.isInt(neo4j.int("42")); +const isInt1: boolean = neo4j.isInt({}) +const isInt2: boolean = neo4j.isInt(neo4j.int('42')) -const toNumber1: number = neo4j.integer.toNumber(1); -const toNumber2: number = neo4j.integer.toNumber("1"); -const toNumber3: number = neo4j.integer.toNumber({high: 0, low: 0}); -const toNumber4: number = neo4j.integer.toNumber(int1); +const toNumber1: number = neo4j.integer.toNumber(1) +const toNumber2: number = neo4j.integer.toNumber('1') +const toNumber3: number = neo4j.integer.toNumber({ high: 0, low: 0 }) +const toNumber4: number = neo4j.integer.toNumber(int1) -const toString1: string = neo4j.integer.toString(1); -const toString2: string = neo4j.integer.toString("1"); -const toString3: string = neo4j.integer.toString({high: 0, low: 0}); -const toString4: string = neo4j.integer.toString(int1); +const toString1: string = neo4j.integer.toString(1) +const toString2: string = neo4j.integer.toString('1') +const toString3: string = neo4j.integer.toString({ high: 0, low: 0 }) +const toString4: string = neo4j.integer.toString(int1) -const inSafeRange1: boolean = neo4j.integer.inSafeRange(1); -const inSafeRange2: boolean = neo4j.integer.inSafeRange("1"); -const inSafeRange3: boolean = neo4j.integer.inSafeRange({high: 0, low: 0}); -const inSafeRange4: boolean = neo4j.integer.inSafeRange(int1); +const inSafeRange1: boolean = neo4j.integer.inSafeRange(1) +const inSafeRange2: boolean = neo4j.integer.inSafeRange('1') +const inSafeRange3: boolean = neo4j.integer.inSafeRange({ high: 0, low: 0 }) +const inSafeRange4: boolean = neo4j.integer.inSafeRange(int1) -const isPoint1: boolean = neo4j.spatial.isPoint({}); -const isPoint2: boolean = neo4j.isPoint({}); +const isPoint1: boolean = neo4j.spatial.isPoint({}) +const isPoint2: boolean = neo4j.isPoint({}) -const isDuration1: boolean = neo4j.temporal.isDuration({}); -const isDuration2: boolean = neo4j.isDuration({}); +const isDuration1: boolean = neo4j.temporal.isDuration({}) +const isDuration2: boolean = neo4j.isDuration({}) -const isLocalTime1: boolean = neo4j.temporal.isLocalTime({}); -const isLocalTime2: boolean = neo4j.isLocalTime({}); +const isLocalTime1: boolean = neo4j.temporal.isLocalTime({}) +const isLocalTime2: boolean = neo4j.isLocalTime({}) -const isTime1: boolean = neo4j.temporal.isTime({}); -const isTime2: boolean = neo4j.isTime({}); +const isTime1: boolean = neo4j.temporal.isTime({}) +const isTime2: boolean = neo4j.isTime({}) -const isDate1: boolean = neo4j.temporal.isDate({}); -const isDate2: boolean = neo4j.isDate({}); +const isDate1: boolean = neo4j.temporal.isDate({}) +const isDate2: boolean = neo4j.isDate({}) -const isLocalDateTime1: boolean = neo4j.temporal.isLocalDateTime({}); -const isLocalDateTime2: boolean = neo4j.isLocalDateTime({}); +const isLocalDateTime1: boolean = neo4j.temporal.isLocalDateTime({}) +const isLocalDateTime2: boolean = neo4j.isLocalDateTime({}) -const isDateTime1: boolean = neo4j.temporal.isDateTime({}); -const isDateTime2: boolean = neo4j.isDateTime({}); +const isDateTime1: boolean = neo4j.temporal.isDateTime({}) +const isDateTime2: boolean = neo4j.isDateTime({}) -const serviceUnavailable: string = neo4j.error.SERVICE_UNAVAILABLE; -const sessionExpired: string = neo4j.error.SESSION_EXPIRED; -const protocolError: string = neo4j.error.PROTOCOL_ERROR; +const serviceUnavailable: string = neo4j.error.SERVICE_UNAVAILABLE +const sessionExpired: string = neo4j.error.SESSION_EXPIRED +const protocolError: string = neo4j.error.PROTOCOL_ERROR -const error1: neo4j.Neo4jError = new neo4j.Neo4jError("Error message"); -const error2: neo4j.Neo4jError = new neo4j.Neo4jError("Error message", "Error code"); +const error1: neo4j.Neo4jError = new neo4j.Neo4jError('Error message') +const error2: neo4j.Neo4jError = new neo4j.Neo4jError( + 'Error message', + 'Error code' +) -const result: neo4j.Result = readSession.run(""); +const result: neo4j.Result = readSession.run('') result.then(value => { - const resultSummary: neo4j.ResultSummary = value.summary; -}); - -const point: neo4j.Point = new neo4j.types.Point(int1, 1, 2, 3); -const duration: neo4j.Duration = new neo4j.types.Duration(int1, int1, int1, int1); -const localTime: neo4j.LocalTime = new neo4j.types.LocalTime(int1, int1, int1, int1); -const time: neo4j.Time = new neo4j.types.Time(int1, int1, int1, int1, int1); -const date: neo4j.Date = new neo4j.types.Date(int1, int1, int1); -const localDateTime: neo4j.LocalDateTime = new neo4j.types.LocalDateTime(int1, int1, int1, int1, int1, int1, int1); -const dateTime: neo4j.DateTime = new neo4j.types.DateTime(int1, int1, int1, int1, int1, int1, int1, int1); + const resultSummary: neo4j.ResultSummary = value.summary +}) + +const point: neo4j.Point = new neo4j.types.Point(int1, 1, 2, 3) +const duration: neo4j.Duration = new neo4j.types.Duration( + int1, + int1, + int1, + int1 +) +const localTime: neo4j.LocalTime = new neo4j.types.LocalTime( + int1, + int1, + int1, + int1 +) +const time: neo4j.Time = new neo4j.types.Time(int1, int1, int1, int1, int1) +const date: neo4j.Date = new neo4j.types.Date(int1, int1, int1) +const localDateTime: neo4j.LocalDateTime = new neo4j.types.LocalDateTime( + int1, + int1, + int1, + int1, + int1, + int1, + int1 +) +const dateTime: neo4j.DateTime = new neo4j.types.DateTime( + int1, + int1, + int1, + int1, + int1, + int1, + int1, + int1 +) diff --git a/test/types/v1/driver.test.ts b/test/types/v1/driver.test.ts index db3ac4bb6..583435068 100644 --- a/test/types/v1/driver.test.ts +++ b/test/types/v1/driver.test.ts @@ -17,80 +17,94 @@ * limitations under the License. */ -import Driver, {AuthToken, Config, EncryptionLevel, LoadBalancingStrategy, READ, SessionMode, TrustStrategy, WRITE} from "../../../types/v1/driver"; -import {Parameters} from "../../../types/v1/statement-runner"; -import Session from "../../../types/v1/session"; -import {Neo4jError} from "../../../types/v1/error"; -import {ServerInfo} from "../../../types/v1/result-summary"; - -const dummy: any = null; - -const authToken: AuthToken = dummy; -const scheme: string = authToken.scheme; -const principal: string = authToken.principal; -const credentials: string = authToken.credentials; -const realm1: undefined = authToken.realm; -const realm2: string = authToken.realm; -const parameters1: undefined = authToken.parameters; -const parameters2: { [key: string]: any } = <{ [key: string]: any }>authToken.parameters; -const parameters3: Parameters = authToken.parameters; - -const encryptionLevel: EncryptionLevel = dummy; -const encryptionLevelStr: string = encryptionLevel; - -const trustStrategy: TrustStrategy = dummy; -const trustStrategyStr: string = trustStrategy; - -const config: Config = dummy; -const encrypted: undefined | boolean | EncryptionLevel = config.encrypted; -const trust: undefined | TrustStrategy = config.trust; -const trustedCertificates: undefined | string[] = config.trustedCertificates; -const knownHosts: undefined | string = config.knownHosts; -const connectionPoolSize: undefined | number = config.connectionPoolSize; -const maxTransactionRetryTime: undefined | number = config.maxTransactionRetryTime; -const loadBalancingStrategy1: undefined | LoadBalancingStrategy = config.loadBalancingStrategy; -const loadBalancingStrategy2: undefined | string = config.loadBalancingStrategy; -const maxConnectionLifetime: undefined | number = config.maxConnectionLifetime; -const connectionTimeout: undefined | number = config.connectionTimeout; -const disableLosslessIntegers: undefined | boolean = config.disableLosslessIntegers; - -const sessionMode: SessionMode = dummy; -const sessionModeStr: string = sessionMode; - -const readMode1: SessionMode = READ; -const readMode2: string = READ; - -const writeMode1: SessionMode = WRITE; -const writeMode2: string = WRITE; - -const driver: Driver = dummy; - -const session1: Session = driver.session(); -const session2: Session = driver.session("READ"); -const session3: Session = driver.session(READ); -const session4: Session = driver.session("WRITE"); -const session5: Session = driver.session(WRITE); -const session6: Session = driver.session(READ, "bookmark1"); -const session7: Session = driver.session(WRITE, "bookmark2"); - -session1.run("RETURN 1").then(result => { - session1.close(); +import Driver, { + AuthToken, + Config, + EncryptionLevel, + LoadBalancingStrategy, + READ, + SessionMode, + TrustStrategy, + WRITE +} from '../../../types/v1/driver' +import { Parameters } from '../../../types/v1/statement-runner' +import Session from '../../../types/v1/session' +import { Neo4jError } from '../../../types/v1/error' +import { ServerInfo } from '../../../types/v1/result-summary' + +const dummy: any = null + +const authToken: AuthToken = dummy +const scheme: string = authToken.scheme +const principal: string = authToken.principal +const credentials: string = authToken.credentials +const realm1: undefined = authToken.realm +const realm2: string = authToken.realm +const parameters1: undefined = authToken.parameters +const parameters2: { [key: string]: any } = <{ [key: string]: any }>( + authToken.parameters +) +const parameters3: Parameters = authToken.parameters + +const encryptionLevel: EncryptionLevel = dummy +const encryptionLevelStr: string = encryptionLevel + +const trustStrategy: TrustStrategy = dummy +const trustStrategyStr: string = trustStrategy + +const config: Config = dummy +const encrypted: undefined | boolean | EncryptionLevel = config.encrypted +const trust: undefined | TrustStrategy = config.trust +const trustedCertificates: undefined | string[] = config.trustedCertificates +const knownHosts: undefined | string = config.knownHosts +const connectionPoolSize: undefined | number = config.connectionPoolSize +const maxTransactionRetryTime: undefined | number = + config.maxTransactionRetryTime +const loadBalancingStrategy1: undefined | LoadBalancingStrategy = + config.loadBalancingStrategy +const loadBalancingStrategy2: undefined | string = config.loadBalancingStrategy +const maxConnectionLifetime: undefined | number = config.maxConnectionLifetime +const connectionTimeout: undefined | number = config.connectionTimeout +const disableLosslessIntegers: undefined | boolean = + config.disableLosslessIntegers + +const sessionMode: SessionMode = dummy +const sessionModeStr: string = sessionMode + +const readMode1: SessionMode = READ +const readMode2: string = READ + +const writeMode1: SessionMode = WRITE +const writeMode2: string = WRITE + +const driver: Driver = dummy + +const session1: Session = driver.session() +const session2: Session = driver.session('READ') +const session3: Session = driver.session(READ) +const session4: Session = driver.session('WRITE') +const session5: Session = driver.session(WRITE) +const session6: Session = driver.session(READ, 'bookmark1') +const session7: Session = driver.session(WRITE, 'bookmark2') + +session1.run('RETURN 1').then(result => { + session1.close() result.records.forEach(record => { - console.log(record); - }); -}); + console.log(record) + }) +}) -const close: void = driver.close(); +const close: void = driver.close() driver.onCompleted = (serverInfo: ServerInfo) => { - console.log(serverInfo.version); - console.log(serverInfo.address); -}; + console.log(serverInfo.version) + console.log(serverInfo.address) +} -driver.onCompleted({version: "Neo4j/3.2.0", address: "localhost:7687"}); +driver.onCompleted({ version: 'Neo4j/3.2.0', address: 'localhost:7687' }) driver.onError = (error: Neo4jError) => { - console.log(error); -}; + console.log(error) +} -driver.onError(new Neo4jError("message", "code")); +driver.onError(new Neo4jError('message', 'code')) diff --git a/test/types/v1/error.test.ts b/test/types/v1/error.test.ts index 2c22881f6..c030e505d 100644 --- a/test/types/v1/error.test.ts +++ b/test/types/v1/error.test.ts @@ -17,14 +17,20 @@ * limitations under the License. */ -import {Neo4jError, newError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from "../../../types/v1/error"; +import { + Neo4jError, + newError, + PROTOCOL_ERROR, + SERVICE_UNAVAILABLE, + SESSION_EXPIRED +} from '../../../types/v1/error' -const serviceUnavailable: string = SERVICE_UNAVAILABLE; -const sessionExpired: string = SESSION_EXPIRED; -const protocolError: string = PROTOCOL_ERROR; +const serviceUnavailable: string = SERVICE_UNAVAILABLE +const sessionExpired: string = SESSION_EXPIRED +const protocolError: string = PROTOCOL_ERROR -const error1: Neo4jError = new Neo4jError("Message"); -const error2: Neo4jError = new Neo4jError("Message", "Code"); +const error1: Neo4jError = new Neo4jError('Message') +const error2: Neo4jError = new Neo4jError('Message', 'Code') -const error3: Neo4jError = newError("Message"); -const error4: Neo4jError = newError("Message", "Code"); +const error3: Neo4jError = newError('Message') +const error4: Neo4jError = newError('Message', 'Code') diff --git a/test/types/v1/graph-types.test.ts b/test/types/v1/graph-types.test.ts index c148120ae..6c7b5fa53 100644 --- a/test/types/v1/graph-types.test.ts +++ b/test/types/v1/graph-types.test.ts @@ -17,62 +17,78 @@ * limitations under the License. */ -import {Node, Path, PathSegment, Relationship, UnboundRelationship} from "../../../types/v1/graph-types"; -import Integer, {int} from "../../../types/v1/integer"; +import { + Node, + Path, + PathSegment, + Relationship, + UnboundRelationship +} from '../../../types/v1/graph-types' +import Integer, { int } from '../../../types/v1/integer' -const node1: Node = new Node(int(1), ["Person", "Employee"], {name: "Alice"}); -const node1String: string = node1.toString(); -const node1Id: Integer = node1.identity; -const node1Labels: string[] = node1.labels; -const node1Props: object = node1.properties; +const node1: Node = new Node(int(1), ['Person', 'Employee'], { name: 'Alice' }) +const node1String: string = node1.toString() +const node1Id: Integer = node1.identity +const node1Labels: string[] = node1.labels +const node1Props: object = node1.properties -const node2: Node = new Node(2, ["Person", "Employee"], {name: "Alice"}); -const node2Id: number = node2.identity; +const node2: Node = new Node(2, ['Person', 'Employee'], { + name: 'Alice' +}) +const node2Id: number = node2.identity -const rel1: Relationship = new Relationship(int(1), int(2), int(3), "KNOWS", {since: 12345}); -const rel1String: string = rel1.toString(); -const rel1Id: Integer = rel1.identity; -const rel1Start: Integer = rel1.start; -const rel1End: Integer = rel1.end; -const rel1Type: string = rel1.type; -const rel1Props: object = rel1.properties; +const rel1: Relationship = new Relationship(int(1), int(2), int(3), 'KNOWS', { + since: 12345 +}) +const rel1String: string = rel1.toString() +const rel1Id: Integer = rel1.identity +const rel1Start: Integer = rel1.start +const rel1End: Integer = rel1.end +const rel1Type: string = rel1.type +const rel1Props: object = rel1.properties -const rel2: UnboundRelationship = new UnboundRelationship(int(1), "KNOWS", {since: 12345}); -const rel2String: string = rel2.toString(); -const rel3: Relationship = rel2.bind(int(1), int(2)); -const rel2Id: Integer = rel2.identity; -const rel2Type: string = rel2.type; -const rel2Props: object = rel2.properties; +const rel2: UnboundRelationship = new UnboundRelationship(int(1), 'KNOWS', { + since: 12345 +}) +const rel2String: string = rel2.toString() +const rel3: Relationship = rel2.bind(int(1), int(2)) +const rel2Id: Integer = rel2.identity +const rel2Type: string = rel2.type +const rel2Props: object = rel2.properties -const rel4: Relationship = new Relationship(2, 3, 4, "KNOWS", {since: 12345}); -const rel4Id: number = rel4.identity; -const rel4Start: number = rel4.start; -const rel4End: number = rel4.end; +const rel4: Relationship = new Relationship(2, 3, 4, 'KNOWS', { + since: 12345 +}) +const rel4Id: number = rel4.identity +const rel4Start: number = rel4.start +const rel4End: number = rel4.end -const rel5: UnboundRelationship = new UnboundRelationship(5, "KNOWS", {since: 12345}); -const rel5Id: number = rel5.identity; -const rel6 = rel5.bind(24, 42); -const rel6Id: number = rel6.identity; -const rel6Start: number = rel6.start; -const rel6End: number = rel6.end; +const rel5: UnboundRelationship = new UnboundRelationship(5, 'KNOWS', { + since: 12345 +}) +const rel5Id: number = rel5.identity +const rel6 = rel5.bind(24, 42) +const rel6Id: number = rel6.identity +const rel6Start: number = rel6.start +const rel6End: number = rel6.end -const pathSegment1: PathSegment = new PathSegment(node1, rel1, node1); -const pathSegment1Start: Node = pathSegment1.start; -const pathSegment1Rel: Relationship = pathSegment1.relationship; -const pathSegment1End: Node = pathSegment1.end; +const pathSegment1: PathSegment = new PathSegment(node1, rel1, node1) +const pathSegment1Start: Node = pathSegment1.start +const pathSegment1Rel: Relationship = pathSegment1.relationship +const pathSegment1End: Node = pathSegment1.end -const pathSegment2: PathSegment = new PathSegment(node2, rel4, node2); -const pathSegment2Start: Node = pathSegment2.start; -const pathSegment2Rel: Relationship = pathSegment2.relationship; -const pathSegment2End: Node = pathSegment2.end; +const pathSegment2: PathSegment = new PathSegment(node2, rel4, node2) +const pathSegment2Start: Node = pathSegment2.start +const pathSegment2Rel: Relationship = pathSegment2.relationship +const pathSegment2End: Node = pathSegment2.end -const path1: Path = new Path(node1, node1, [pathSegment1]); -const path1Start: Node = path1.start; -const path1End: Node = path1.end; -const path1Segments: PathSegment[] = path1.segments; -const path1Length: number = path1.length; +const path1: Path = new Path(node1, node1, [pathSegment1]) +const path1Start: Node = path1.start +const path1End: Node = path1.end +const path1Segments: PathSegment[] = path1.segments +const path1Length: number = path1.length -const path2: Path = new Path(node2, node2, [pathSegment2]); -const path2Start: Node = path2.start; -const path2End: Node = path2.end; -const path2Segments: PathSegment[] = path2.segments; +const path2: Path = new Path(node2, node2, [pathSegment2]) +const path2Start: Node = path2.start +const path2End: Node = path2.end +const path2Segments: PathSegment[] = path2.segments diff --git a/test/types/v1/index.test.ts b/test/types/v1/index.test.ts index 4a97ff2e3..b2fb53c8e 100644 --- a/test/types/v1/index.test.ts +++ b/test/types/v1/index.test.ts @@ -17,56 +17,91 @@ * limitations under the License. */ -import v1, {auth, AuthToken, Config, driver, error, session, spatial, temporal} from "../../../types/v1/index"; - -import Driver from "../../../types/v1/driver"; - -const dummy: any = null; - -const config: Config = dummy; - -const basicAuthToken1: AuthToken = auth.basic("neo4j", "password"); -const basicAuthToken2: AuthToken = auth.basic("neo4j", "password", "realm"); - -const kerberosAuthToken1: AuthToken = auth.kerberos("base64EncodedTicket"); - -const customAuthToken1: AuthToken = auth.custom("neo4j", "password", "realm", "scheme"); -const customAuthToken2: AuthToken = auth.custom("neo4j", "password", "realm", "scheme", {"key": "value"}); - -const basicAuthToken3: AuthToken = v1.auth.basic("neo4j", "password"); -const basicAuthToken4: AuthToken = v1.auth.basic("neo4j", "password", "realm"); - -const kerberosAuthToken2: AuthToken = v1.auth.kerberos("base64EncodedTicket"); - -const customAuthToken3: AuthToken = v1.auth.custom("neo4j", "password", "realm", "scheme"); -const customAuthToken4: AuthToken = v1.auth.custom("neo4j", "password", "realm", "scheme", {"key": "value"}); - -const driver1: Driver = driver("bolt://localhost:7687"); -const driver2: Driver = driver("bolt://localhost:7687", basicAuthToken1); -const driver3: Driver = driver("bolt://localhost:7687", basicAuthToken1, config); - -const driver4: Driver = v1.driver("bolt://localhost:7687"); -const driver5: Driver = v1.driver("bolt://localhost:7687", basicAuthToken1); -const driver6: Driver = v1.driver("bolt://localhost:7687", basicAuthToken1, config); - -const readMode1: string = session.READ; -const writeMode1: string = session.WRITE; - -const readMode2: string = v1.session.READ; -const writeMode2: string = v1.session.WRITE; - -const serviceUnavailable1: string = error.SERVICE_UNAVAILABLE; -const sessionExpired1: string = error.SESSION_EXPIRED; -const protocolError1: string = error.PROTOCOL_ERROR; - -const serviceUnavailable2: string = v1.error.SERVICE_UNAVAILABLE; -const sessionExpired2: string = v1.error.SESSION_EXPIRED; -const protocolError2: string = v1.error.PROTOCOL_ERROR; - -const isNeo4jPoint: boolean = spatial.isPoint({}); -const isNeo4jDate: boolean = temporal.isDate({}); -const isNeo4jDateTime: boolean = temporal.isDateTime({}); -const isNeo4jDuration: boolean = temporal.isDuration({}); -const isNeo4jLocalDateTime: boolean = temporal.isLocalDateTime({}); -const isNeo4jLocalTime: boolean = temporal.isLocalTime({}); -const isNeo4jTime: boolean = temporal.isTime({}); +import v1, { + auth, + AuthToken, + Config, + driver, + error, + session, + spatial, + temporal +} from '../../../types/v1/index' + +import Driver from '../../../types/v1/driver' + +const dummy: any = null + +const config: Config = dummy + +const basicAuthToken1: AuthToken = auth.basic('neo4j', 'password') +const basicAuthToken2: AuthToken = auth.basic('neo4j', 'password', 'realm') + +const kerberosAuthToken1: AuthToken = auth.kerberos('base64EncodedTicket') + +const customAuthToken1: AuthToken = auth.custom( + 'neo4j', + 'password', + 'realm', + 'scheme' +) +const customAuthToken2: AuthToken = auth.custom( + 'neo4j', + 'password', + 'realm', + 'scheme', + { key: 'value' } +) + +const basicAuthToken3: AuthToken = v1.auth.basic('neo4j', 'password') +const basicAuthToken4: AuthToken = v1.auth.basic('neo4j', 'password', 'realm') + +const kerberosAuthToken2: AuthToken = v1.auth.kerberos('base64EncodedTicket') + +const customAuthToken3: AuthToken = v1.auth.custom( + 'neo4j', + 'password', + 'realm', + 'scheme' +) +const customAuthToken4: AuthToken = v1.auth.custom( + 'neo4j', + 'password', + 'realm', + 'scheme', + { key: 'value' } +) + +const driver1: Driver = driver('bolt://localhost:7687') +const driver2: Driver = driver('bolt://localhost:7687', basicAuthToken1) +const driver3: Driver = driver('bolt://localhost:7687', basicAuthToken1, config) + +const driver4: Driver = v1.driver('bolt://localhost:7687') +const driver5: Driver = v1.driver('bolt://localhost:7687', basicAuthToken1) +const driver6: Driver = v1.driver( + 'bolt://localhost:7687', + basicAuthToken1, + config +) + +const readMode1: string = session.READ +const writeMode1: string = session.WRITE + +const readMode2: string = v1.session.READ +const writeMode2: string = v1.session.WRITE + +const serviceUnavailable1: string = error.SERVICE_UNAVAILABLE +const sessionExpired1: string = error.SESSION_EXPIRED +const protocolError1: string = error.PROTOCOL_ERROR + +const serviceUnavailable2: string = v1.error.SERVICE_UNAVAILABLE +const sessionExpired2: string = v1.error.SESSION_EXPIRED +const protocolError2: string = v1.error.PROTOCOL_ERROR + +const isNeo4jPoint: boolean = spatial.isPoint({}) +const isNeo4jDate: boolean = temporal.isDate({}) +const isNeo4jDateTime: boolean = temporal.isDateTime({}) +const isNeo4jDuration: boolean = temporal.isDuration({}) +const isNeo4jLocalDateTime: boolean = temporal.isLocalDateTime({}) +const isNeo4jLocalTime: boolean = temporal.isLocalTime({}) +const isNeo4jTime: boolean = temporal.isTime({}) diff --git a/test/types/v1/integer.test.ts b/test/types/v1/integer.test.ts index c159087bc..d617f8773 100644 --- a/test/types/v1/integer.test.ts +++ b/test/types/v1/integer.test.ts @@ -17,168 +17,174 @@ * limitations under the License. */ -import Integer, {inSafeRange, int, isInt, toNumber, toString} from "../../../types/v1/integer"; - -const int1 = new Integer(); -const int2 = new Integer(1); -const int3 = new Integer(1, 2); - -const high: number = int1.high; -const low: number = int1.low; - -const safe: boolean = int1.inSafeRange(); +import Integer, { + inSafeRange, + int, + isInt, + toNumber, + toString +} from '../../../types/v1/integer' + +const int1 = new Integer() +const int2 = new Integer(1) +const int3 = new Integer(1, 2) + +const high: number = int1.high +const low: number = int1.low + +const safe: boolean = int1.inSafeRange() if (safe) { - const i: number = int1.toInt(); - console.log(i); + const i: number = int1.toInt() + console.log(i) - const n: number = int1.toNumber(); + const n: number = int1.toNumber() console.log(n) } -const str: string = int2.toString(16); +const str: string = int2.toString(16) -const highBits: number = int3.getHighBits(); -const lowBits: number = int3.getLowBits(); -const numBitsAbs: number = int3.getNumBitsAbs(); +const highBits: number = int3.getHighBits() +const lowBits: number = int3.getLowBits() +const numBitsAbs: number = int3.getNumBitsAbs() -const isZero: boolean = int1.isZero(); -const isNegative: boolean = int1.isNegative(); -const isPositive: boolean = int1.isPositive(); -const isOdd: boolean = int1.isOdd(); -const isEven: boolean = int1.isEven(); +const isZero: boolean = int1.isZero() +const isNegative: boolean = int1.isNegative() +const isPositive: boolean = int1.isPositive() +const isOdd: boolean = int1.isOdd() +const isEven: boolean = int1.isEven() -const eq1: boolean = int1.equals(int2); -const eq2: boolean = int1.equals(42); -const eq3: boolean = int1.equals("42"); +const eq1: boolean = int1.equals(int2) +const eq2: boolean = int1.equals(42) +const eq3: boolean = int1.equals('42') -const neq1: boolean = int1.notEquals(int2); -const neq2: boolean = int1.notEquals(42); -const neq3: boolean = int1.notEquals("42"); - -const lt1: boolean = int1.lessThan(int2); -const lt2: boolean = int1.lessThan(42); -const lt3: boolean = int1.lessThan("42"); - -const lte1: boolean = int1.lessThanOrEqual(int2); -const lte2: boolean = int1.lessThanOrEqual(42); -const lte3: boolean = int1.lessThanOrEqual("42"); +const neq1: boolean = int1.notEquals(int2) +const neq2: boolean = int1.notEquals(42) +const neq3: boolean = int1.notEquals('42') + +const lt1: boolean = int1.lessThan(int2) +const lt2: boolean = int1.lessThan(42) +const lt3: boolean = int1.lessThan('42') + +const lte1: boolean = int1.lessThanOrEqual(int2) +const lte2: boolean = int1.lessThanOrEqual(42) +const lte3: boolean = int1.lessThanOrEqual('42') -const gt1: boolean = int1.greaterThan(int2); -const gt2: boolean = int1.greaterThan(42); -const gt3: boolean = int1.greaterThan("42"); - -const gte1: boolean = int1.greaterThanOrEqual(int2); -const gte2: boolean = int1.greaterThanOrEqual(42); -const gte3: boolean = int1.greaterThanOrEqual("42"); - -const cmp1: number = int2.compare(int3); -const cmp2: number = int2.compare(42); -const cmp3: number = int2.compare("42"); - -const negated: Integer = int3.negate(); - -const add1: Integer = int1.add(int2); -const add2: Integer = int1.add(42); -const add3: Integer = int1.add("42"); - -const subtract1: Integer = int1.subtract(int2); -const subtract2: Integer = int1.subtract(42); -const subtract3: Integer = int1.subtract("42"); - -const multiply1: Integer = int1.multiply(int2); -const multiply2: Integer = int1.multiply(42); -const multiply3: Integer = int1.multiply("42"); - -const div1: Integer = int1.div(int2); -const div2: Integer = int1.div(42); -const div3: Integer = int1.div("42"); - -const modulo1: Integer = int1.modulo(int2); -const modulo2: Integer = int1.modulo(42); -const modulo3: Integer = int1.modulo("42"); - -const not: Integer = int3.not(); - -const and1: Integer = int3.and(int2); -const and2: Integer = int3.and(42); -const and3: Integer = int3.and("42"); - -const or1: Integer = int3.or(int2); -const or2: Integer = int3.or(42); -const or3: Integer = int3.or("42"); - -const xor1: Integer = int3.xor(int2); -const xor2: Integer = int3.xor(42); -const xor3: Integer = int3.xor("42"); - -const shiftLeft: Integer = int2.shiftLeft(int1); -const shiftRight: Integer = int2.shiftRight(int1); - -const isIntegerProp: boolean = Integer.__isInteger__; -const isInteger: boolean = Integer.isInteger({}); - -const fromInt: Integer = Integer.fromInt(42); -const fromNumber: Integer = Integer.fromNumber(42); -const fromBits: Integer = Integer.fromBits(1, 2); -const fromStr1: Integer = Integer.fromString("123"); -const fromStr2: Integer = Integer.fromString("123", 10); - -const fromValue1: Integer = Integer.fromValue(int1); -const fromValue2: Integer = Integer.fromValue(42); -const fromValue3: Integer = Integer.fromValue("42"); -const fromValue4: Integer = Integer.fromValue({low: 1, high: 2}); - -const toNumber1: number = Integer.toNumber(int3); -const toNumber2: number = Integer.toNumber(42); -const toNumber3: number = Integer.toNumber("42"); -const toNumber4: number = Integer.toNumber({low: 2, high: 1}); - -const toStr1: string = Integer.toString(int3); -const toStr2: string = Integer.toString(42); -const toStr3: string = Integer.toString("42"); -const toStr4: string = Integer.toString({low: 1, high: 1}); - -const toStr5: string = Integer.toString(int3, 10); -const toStr6: string = Integer.toString(42, 2); -const toStr7: string = Integer.toString("42", 16); -const toStr8: string = Integer.toString({low: 1, high: 1}, 10); - -const inSafeRange1: boolean = Integer.inSafeRange(int3); -const inSafeRange2: boolean = Integer.inSafeRange(42); -const inSafeRange3: boolean = Integer.inSafeRange("42"); -const inSafeRange4: boolean = Integer.inSafeRange({low: 2, high: 2}); - -const zero: Integer = Integer.ZERO; -const one: Integer = Integer.ONE; -const negOne: Integer = Integer.NEG_ONE; -const max: Integer = Integer.MAX_VALUE; -const min: Integer = Integer.MIN_VALUE; -const minSafe: Integer = Integer.MIN_SAFE_VALUE; -const maxSafe: Integer = Integer.MAX_SAFE_VALUE; - -const intFunc1: Integer = int(int1); -const intFunc2: Integer = int(42); -const intFunc3: Integer = int("42"); -const intFunc4: Integer = int({low: 0, high: 1}); - -const isIntFunc: boolean = isInt({}); - -const inSafeRangeFunc1: boolean = inSafeRange(int2); -const inSafeRangeFunc2: boolean = inSafeRange(42); -const inSafeRangeFunc3: boolean = inSafeRange("42"); -const inSafeRangeFunc4: boolean = inSafeRange({low: 1, high: 1}); - -const toNumberFunc1: number = toNumber(int3); -const toNumberFunc2: number = toNumber(42); -const toNumberFunc3: number = toNumber("42"); -const toNumberFunc4: number = toNumber({low: 1, high: 1}); - -const toStringFunc1: string = toString(int3); -const toStringFunc2: string = toString(42); -const toStringFunc3: string = toString("42"); -const toStringFunc4: string = toString({low: 1, high: 1}); - -const toStringFunc5: string = toString(int3, 2); -const toStringFunc6: string = toString(42, 2); -const toStringFunc7: string = toString("42", 10); -const toStringFunc8: string = toString({low: 1, high: 1}, 16); +const gt1: boolean = int1.greaterThan(int2) +const gt2: boolean = int1.greaterThan(42) +const gt3: boolean = int1.greaterThan('42') + +const gte1: boolean = int1.greaterThanOrEqual(int2) +const gte2: boolean = int1.greaterThanOrEqual(42) +const gte3: boolean = int1.greaterThanOrEqual('42') + +const cmp1: number = int2.compare(int3) +const cmp2: number = int2.compare(42) +const cmp3: number = int2.compare('42') + +const negated: Integer = int3.negate() + +const add1: Integer = int1.add(int2) +const add2: Integer = int1.add(42) +const add3: Integer = int1.add('42') + +const subtract1: Integer = int1.subtract(int2) +const subtract2: Integer = int1.subtract(42) +const subtract3: Integer = int1.subtract('42') + +const multiply1: Integer = int1.multiply(int2) +const multiply2: Integer = int1.multiply(42) +const multiply3: Integer = int1.multiply('42') + +const div1: Integer = int1.div(int2) +const div2: Integer = int1.div(42) +const div3: Integer = int1.div('42') + +const modulo1: Integer = int1.modulo(int2) +const modulo2: Integer = int1.modulo(42) +const modulo3: Integer = int1.modulo('42') + +const not: Integer = int3.not() + +const and1: Integer = int3.and(int2) +const and2: Integer = int3.and(42) +const and3: Integer = int3.and('42') + +const or1: Integer = int3.or(int2) +const or2: Integer = int3.or(42) +const or3: Integer = int3.or('42') + +const xor1: Integer = int3.xor(int2) +const xor2: Integer = int3.xor(42) +const xor3: Integer = int3.xor('42') + +const shiftLeft: Integer = int2.shiftLeft(int1) +const shiftRight: Integer = int2.shiftRight(int1) + +const isIntegerProp: boolean = Integer.__isInteger__ +const isInteger: boolean = Integer.isInteger({}) + +const fromInt: Integer = Integer.fromInt(42) +const fromNumber: Integer = Integer.fromNumber(42) +const fromBits: Integer = Integer.fromBits(1, 2) +const fromStr1: Integer = Integer.fromString('123') +const fromStr2: Integer = Integer.fromString('123', 10) + +const fromValue1: Integer = Integer.fromValue(int1) +const fromValue2: Integer = Integer.fromValue(42) +const fromValue3: Integer = Integer.fromValue('42') +const fromValue4: Integer = Integer.fromValue({ low: 1, high: 2 }) + +const toNumber1: number = Integer.toNumber(int3) +const toNumber2: number = Integer.toNumber(42) +const toNumber3: number = Integer.toNumber('42') +const toNumber4: number = Integer.toNumber({ low: 2, high: 1 }) + +const toStr1: string = Integer.toString(int3) +const toStr2: string = Integer.toString(42) +const toStr3: string = Integer.toString('42') +const toStr4: string = Integer.toString({ low: 1, high: 1 }) + +const toStr5: string = Integer.toString(int3, 10) +const toStr6: string = Integer.toString(42, 2) +const toStr7: string = Integer.toString('42', 16) +const toStr8: string = Integer.toString({ low: 1, high: 1 }, 10) + +const inSafeRange1: boolean = Integer.inSafeRange(int3) +const inSafeRange2: boolean = Integer.inSafeRange(42) +const inSafeRange3: boolean = Integer.inSafeRange('42') +const inSafeRange4: boolean = Integer.inSafeRange({ low: 2, high: 2 }) + +const zero: Integer = Integer.ZERO +const one: Integer = Integer.ONE +const negOne: Integer = Integer.NEG_ONE +const max: Integer = Integer.MAX_VALUE +const min: Integer = Integer.MIN_VALUE +const minSafe: Integer = Integer.MIN_SAFE_VALUE +const maxSafe: Integer = Integer.MAX_SAFE_VALUE + +const intFunc1: Integer = int(int1) +const intFunc2: Integer = int(42) +const intFunc3: Integer = int('42') +const intFunc4: Integer = int({ low: 0, high: 1 }) + +const isIntFunc: boolean = isInt({}) + +const inSafeRangeFunc1: boolean = inSafeRange(int2) +const inSafeRangeFunc2: boolean = inSafeRange(42) +const inSafeRangeFunc3: boolean = inSafeRange('42') +const inSafeRangeFunc4: boolean = inSafeRange({ low: 1, high: 1 }) + +const toNumberFunc1: number = toNumber(int3) +const toNumberFunc2: number = toNumber(42) +const toNumberFunc3: number = toNumber('42') +const toNumberFunc4: number = toNumber({ low: 1, high: 1 }) + +const toStringFunc1: string = toString(int3) +const toStringFunc2: string = toString(42) +const toStringFunc3: string = toString('42') +const toStringFunc4: string = toString({ low: 1, high: 1 }) + +const toStringFunc5: string = toString(int3, 2) +const toStringFunc6: string = toString(42, 2) +const toStringFunc7: string = toString('42', 10) +const toStringFunc8: string = toString({ low: 1, high: 1 }, 16) diff --git a/test/types/v1/record.test.ts b/test/types/v1/record.test.ts index b6232bbd5..e332ab1f9 100644 --- a/test/types/v1/record.test.ts +++ b/test/types/v1/record.test.ts @@ -17,33 +17,29 @@ * limitations under the License. */ -import Record from "../../../types/v1/record"; +import Record from '../../../types/v1/record' -const record1 = new Record(["name", "age"], ["Alice", 20]); -const record2 = new Record(["name", "age"], ["Bob", 22], {"key": "value"}); +const record1 = new Record(['name', 'age'], ['Alice', 20]) +const record2 = new Record(['name', 'age'], ['Bob', 22], { key: 'value' }) -const record1Keys: string[] = record1.keys; -const record1Length: number = record1.length; +const record1Keys: string[] = record1.keys +const record1Length: number = record1.length -const record1Object: object = record1.toObject(); +const record1Object: object = record1.toObject() -record1.forEach(() => { -}); +record1.forEach(() => {}) -record1.forEach((value: any) => { -}); +record1.forEach((value: any) => {}) -record1.forEach((value: any, key: string) => { -}); +record1.forEach((value: any, key: string) => {}) -record1.forEach((value: any, key: string, record: Record) => { -}); +record1.forEach((value: any, key: string, record: Record) => {}) -const record1Has: boolean = record1.has(42); -const record2Has: boolean = record1.has("key"); +const record1Has: boolean = record1.has(42) +const record2Has: boolean = record1.has('key') -const record1Get1: any = record1.get(42); -const record2Get1: any = record2.get("key"); +const record1Get1: any = record1.get(42) +const record2Get1: any = record2.get('key') -const record1Get2: object = record1.get(42); -const record2Get2: string[] = record2.get("key"); +const record1Get2: object = record1.get(42) +const record2Get2: string[] = record2.get('key') diff --git a/test/types/v1/result-summary.test.ts b/test/types/v1/result-summary.test.ts index 7a99471c6..884b35a3d 100644 --- a/test/types/v1/result-summary.test.ts +++ b/test/types/v1/result-summary.test.ts @@ -17,74 +17,83 @@ * limitations under the License. */ -import ResultSummary, {Notification, NotificationPosition, Plan, ProfiledPlan, ServerInfo, StatementStatistic} from "../../../types/v1/result-summary"; -import Integer from "../../../types/v1/integer"; +import ResultSummary, { + Notification, + NotificationPosition, + Plan, + ProfiledPlan, + ServerInfo, + StatementStatistic +} from '../../../types/v1/result-summary' +import Integer from '../../../types/v1/integer' -const dummy: any = null; +const dummy: any = null -const sum1: ResultSummary = dummy; +const sum1: ResultSummary = dummy -const stmt = sum1.statement; -const stmtText: string = stmt.text; -const stmtParams: object = stmt.parameters; +const stmt = sum1.statement +const stmtText: string = stmt.text +const stmtParams: object = stmt.parameters -const str: string = sum1.statementType; +const str: string = sum1.statementType -const counters: StatementStatistic = sum1.counters; +const counters: StatementStatistic = sum1.counters -const containsUpdates: boolean = counters.containsUpdates(); -const nodesCreated: number = counters.nodesCreated(); -const nodesDeleted: number = counters.nodesDeleted(); -const relationshipsCreated: number = counters.relationshipsCreated(); -const relationshipsDeleted: number = counters.relationshipsDeleted(); -const propertiesSet: number = counters.propertiesSet(); -const labelsAdded: number = counters.labelsAdded(); -const labelsRemoved: number = counters.labelsRemoved(); -const indexesAdded: number = counters.indexesAdded(); -const indexesRemoved: number = counters.indexesRemoved(); -const constraintsAdded: number = counters.constraintsAdded(); -const constraintsRemoved: number = counters.constraintsRemoved(); +const containsUpdates: boolean = counters.containsUpdates() +const nodesCreated: number = counters.nodesCreated() +const nodesDeleted: number = counters.nodesDeleted() +const relationshipsCreated: number = counters.relationshipsCreated() +const relationshipsDeleted: number = counters.relationshipsDeleted() +const propertiesSet: number = counters.propertiesSet() +const labelsAdded: number = counters.labelsAdded() +const labelsRemoved: number = counters.labelsRemoved() +const indexesAdded: number = counters.indexesAdded() +const indexesRemoved: number = counters.indexesRemoved() +const constraintsAdded: number = counters.constraintsAdded() +const constraintsRemoved: number = counters.constraintsRemoved() -const plan: Plan = sum1.plan; -const planOperatorType: string = plan.operatorType; -const planIdentifiers: string[] = plan.identifiers; -const planArguments: { [key: string]: string } = plan.arguments; -const planChildren: Plan[] = plan.children; +const plan: Plan = sum1.plan +const planOperatorType: string = plan.operatorType +const planIdentifiers: string[] = plan.identifiers +const planArguments: { [key: string]: string } = plan.arguments +const planChildren: Plan[] = plan.children -const profile: ProfiledPlan = sum1.profile; -const profileOperatorType: string = profile.operatorType; -const profileIdentifiers: string[] = profile.identifiers; -const profileArguments: { [key: string]: string } = profile.arguments; -const profileDbHits: number = profile.dbHits; -const profileRows: number = profile.rows; -const profileChildren: ProfiledPlan[] = profile.children; +const profile: ProfiledPlan = sum1.profile +const profileOperatorType: string = profile.operatorType +const profileIdentifiers: string[] = profile.identifiers +const profileArguments: { [key: string]: string } = profile.arguments +const profileDbHits: number = profile.dbHits +const profileRows: number = profile.rows +const profileChildren: ProfiledPlan[] = profile.children -const notifications: Notification[] = sum1.notifications; -const notification: Notification = notifications[0]; -const code: string = notification.code; -const title: string = notification.title; -const description: string = notification.description; -const severity: string = notification.severity; -const position1: NotificationPosition | {} = notification.position; -const position2: NotificationPosition = notification.position; -const offset: number = position2.offset; -const line: number = position2.line; -const column: number = position2.column; +const notifications: Notification[] = sum1.notifications +const notification: Notification = notifications[0] +const code: string = notification.code +const title: string = notification.title +const description: string = notification.description +const severity: string = notification.severity +const position1: NotificationPosition | {} = notification.position +const position2: NotificationPosition = ( + notification.position +) +const offset: number = position2.offset +const line: number = position2.line +const column: number = position2.column -const server: ServerInfo = sum1.server; -const address: string = server.address; -const version: string = server.version; +const server: ServerInfo = sum1.server +const address: string = server.address +const version: string = server.version -const resultConsumedAfter1: Integer = sum1.resultConsumedAfter; -const resultAvailableAfter1: Integer = sum1.resultAvailableAfter; +const resultConsumedAfter1: Integer = sum1.resultConsumedAfter +const resultAvailableAfter1: Integer = sum1.resultAvailableAfter -const hasPlan: boolean = sum1.hasPlan(); -const hasProfile: boolean = sum1.hasProfile(); +const hasPlan: boolean = sum1.hasPlan() +const hasProfile: boolean = sum1.hasProfile() -const sum2: ResultSummary = dummy; -const resultConsumedAfter2: number = sum2.resultConsumedAfter; -const resultAvailableAfter2: number = sum2.resultAvailableAfter; +const sum2: ResultSummary = dummy +const resultConsumedAfter2: number = sum2.resultConsumedAfter +const resultAvailableAfter2: number = sum2.resultAvailableAfter -const sum3: ResultSummary = dummy; -const resultConsumedAfter3: Integer = sum3.resultConsumedAfter; -const resultAvailableAfter3: Integer = sum3.resultAvailableAfter; +const sum3: ResultSummary = dummy +const resultConsumedAfter3: Integer = sum3.resultConsumedAfter +const resultAvailableAfter3: Integer = sum3.resultAvailableAfter diff --git a/test/types/v1/result.test.ts b/test/types/v1/result.test.ts index d8649bf98..ec506e2c1 100644 --- a/test/types/v1/result.test.ts +++ b/test/types/v1/result.test.ts @@ -17,34 +17,36 @@ * limitations under the License. */ -import Result from "../../../types/v1/result"; -import Record from "../../../types/v1/record"; -import ResultSummary from "../../../types/v1/result-summary"; +import Result from '../../../types/v1/result' +import Record from '../../../types/v1/record' +import ResultSummary from '../../../types/v1/result-summary' -const dummy: any = null; +const dummy: any = null -const res: Result = dummy; +const res: Result = dummy -res.then(value => { - const records: Record[] = value.records; - const summary: ResultSummary = value.summary; -}).catch(error => { - console.log(error); -}); +res + .then(value => { + const records: Record[] = value.records + const summary: ResultSummary = value.summary + }) + .catch(error => { + console.log(error) + }) -res.subscribe({}); +res.subscribe({}) res.subscribe({ onNext: (record: Record) => console.log(record) -}); +}) res.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error) -}); +}) res.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error), onCompleted: (summary: ResultSummary) => console.log(summary) -}); +}) diff --git a/test/types/v1/session.test.ts b/test/types/v1/session.test.ts index 607a9c546..f63018c55 100644 --- a/test/types/v1/session.test.ts +++ b/test/types/v1/session.test.ts @@ -17,125 +17,154 @@ * limitations under the License. */ -import Session, {TransactionConfig} from "../../../types/v1/session"; -import Transaction from "../../../types/v1/transaction"; -import Record from "../../../types/v1/record"; -import Result, {StatementResult} from "../../../types/v1/result"; -import ResultSummary from "../../../types/v1/result-summary"; -import Integer from "../../../types/v1/integer"; - -const dummy: any = null; -const intValue: Integer = Integer.fromInt(42); - -const session: Session = dummy; - -const txConfig1: TransactionConfig = {}; -const txConfig2: TransactionConfig = {timeout: 5000}; -const txConfig3: TransactionConfig = {timeout: intValue}; -const txConfig4: TransactionConfig = {metadata: {}}; -const txConfig5: TransactionConfig = {metadata: {key1: 'value1', key2: 5, key3: {a: 'a', b: 'b'}, key4: [1, 2, 3]}}; -const txConfig6: TransactionConfig = {timeout: 2000, metadata: {key1: 'value1', key2: 2}}; -const txConfig7: TransactionConfig = {timeout: intValue, metadata: {key1: 'value1', key2: 2}}; - -const tx1: Transaction = session.beginTransaction(); -const bookmark: null | string = session.lastBookmark(); +import Session, { TransactionConfig } from '../../../types/v1/session' +import Transaction from '../../../types/v1/transaction' +import Record from '../../../types/v1/record' +import Result, { StatementResult } from '../../../types/v1/result' +import ResultSummary from '../../../types/v1/result-summary' +import Integer from '../../../types/v1/integer' + +const dummy: any = null +const intValue: Integer = Integer.fromInt(42) + +const session: Session = dummy + +const txConfig1: TransactionConfig = {} +const txConfig2: TransactionConfig = { timeout: 5000 } +const txConfig3: TransactionConfig = { timeout: intValue } +const txConfig4: TransactionConfig = { metadata: {} } +const txConfig5: TransactionConfig = { + metadata: { + key1: 'value1', + key2: 5, + key3: { a: 'a', b: 'b' }, + key4: [1, 2, 3] + } +} +const txConfig6: TransactionConfig = { + timeout: 2000, + metadata: { key1: 'value1', key2: 2 } +} +const txConfig7: TransactionConfig = { + timeout: intValue, + metadata: { key1: 'value1', key2: 2 } +} + +const tx1: Transaction = session.beginTransaction() +const bookmark: null | string = session.lastBookmark() const promise1: Promise = session.readTransaction((tx: Transaction) => { - return 10; -}); + return 10 +}) const promise2: Promise = session.readTransaction((tx: Transaction) => { - return Promise.resolve("42") -}); - -const promise3: Promise = session.writeTransaction((tx: Transaction) => { - return 10; -}); - -const promise4: Promise = session.writeTransaction((tx: Transaction) => { - return Promise.resolve("42") -}); - -const close1: void = session.close(); + return Promise.resolve('42') +}) + +const promise3: Promise = session.writeTransaction( + (tx: Transaction) => { + return 10 + } +) + +const promise4: Promise = session.writeTransaction( + (tx: Transaction) => { + return Promise.resolve('42') + } +) + +const close1: void = session.close() const close2: void = session.close(() => { - console.log("Session closed"); -}); - -const result1: Result = session.run("RETURN 1"); -result1.then((res: StatementResult) => { - const records: Record[] = res.records; - const summary: ResultSummary = res.summary; - console.log(records); - console.log(summary); -}).catch((error: Error) => { - console.log(error); -}); - -const result2: Result = session.run("RETURN 2"); -result2.subscribe({}); + console.log('Session closed') +}) + +const result1: Result = session.run('RETURN 1') +result1 + .then((res: StatementResult) => { + const records: Record[] = res.records + const summary: ResultSummary = res.summary + console.log(records) + console.log(summary) + }) + .catch((error: Error) => { + console.log(error) + }) + +const result2: Result = session.run('RETURN 2') +result2.subscribe({}) result2.subscribe({ onNext: (record: Record) => console.log(record) -}); +}) result2.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error) -}); +}) result2.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error), onCompleted: (summary: ResultSummary) => console.log(summary) -}); - -const result3: Result = session.run("RETURN $value", {value: "42"}); -result3.then((res: StatementResult) => { - const records: Record[] = res.records; - const summary: ResultSummary = res.summary; - console.log(records); - console.log(summary); -}).catch((error: Error) => { - console.log(error); -}); - -const result4: Result = session.run("RETURN $value", {value: "42"}); -result4.subscribe({}); +}) + +const result3: Result = session.run('RETURN $value', { value: '42' }) +result3 + .then((res: StatementResult) => { + const records: Record[] = res.records + const summary: ResultSummary = res.summary + console.log(records) + console.log(summary) + }) + .catch((error: Error) => { + console.log(error) + }) + +const result4: Result = session.run('RETURN $value', { value: '42' }) +result4.subscribe({}) result4.subscribe({ onNext: (record: Record) => console.log(record) -}); +}) result4.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error) -}); +}) result4.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error), onCompleted: (summary: ResultSummary) => console.log(summary) -}); - -const result5: Result = session.run("RETURN $value", {value: "42"}, txConfig1); -result5.then((res: StatementResult) => { - const records: Record[] = res.records; - const summary: ResultSummary = res.summary; - console.log(records); - console.log(summary); -}).catch((error: Error) => { - console.log(error); -}); - -const result6: Result = session.run("RETURN $value", {value: "42"}, txConfig2); -result6.subscribe({}); +}) + +const result5: Result = session.run('RETURN $value', { value: '42' }, txConfig1) +result5 + .then((res: StatementResult) => { + const records: Record[] = res.records + const summary: ResultSummary = res.summary + console.log(records) + console.log(summary) + }) + .catch((error: Error) => { + console.log(error) + }) + +const result6: Result = session.run('RETURN $value', { value: '42' }, txConfig2) +result6.subscribe({}) result6.subscribe({ onNext: (record: Record) => console.log(record) -}); +}) result6.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error) -}); +}) result6.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error), onCompleted: (summary: ResultSummary) => console.log(summary) -}); - -const tx2: Transaction = session.beginTransaction(txConfig2); -const promise5: Promise = session.readTransaction((tx: Transaction) => "", txConfig3); -const promise6: Promise = session.writeTransaction((tx: Transaction) => 42, txConfig4); +}) + +const tx2: Transaction = session.beginTransaction(txConfig2) +const promise5: Promise = session.readTransaction( + (tx: Transaction) => '', + txConfig3 +) +const promise6: Promise = session.writeTransaction( + (tx: Transaction) => 42, + txConfig4 +) diff --git a/test/types/v1/spatial-types.test.ts b/test/types/v1/spatial-types.test.ts index 6b9e83ba0..fdeadee5c 100644 --- a/test/types/v1/spatial-types.test.ts +++ b/test/types/v1/spatial-types.test.ts @@ -17,30 +17,30 @@ * limitations under the License. */ -import {isPoint, Point} from "../../../types/v1/spatial-types"; -import Integer, {int} from "../../../types/v1/integer"; +import { isPoint, Point } from '../../../types/v1/spatial-types' +import Integer, { int } from '../../../types/v1/integer' -const point1: Point = new Point(int(1), 2, 3); -const srid1: Integer = point1.srid; -const x1: number = point1.x; -const y1: number = point1.y; +const point1: Point = new Point(int(1), 2, 3) +const srid1: Integer = point1.srid +const x1: number = point1.x +const y1: number = point1.y -const point2: Point = new Point(1, 2, 3); -const srid2: number = point2.srid; -const x2: number = point2.x; -const y2: number = point2.y; +const point2: Point = new Point(1, 2, 3) +const srid2: number = point2.srid +const x2: number = point2.x +const y2: number = point2.y -const point3: Point = new Point(int(1), 2, 3, 4); -const srid3: Integer = point3.srid; -const x3: number = point3.x; -const y3: number = point3.y; -const z3: number | undefined = point3.z; +const point3: Point = new Point(int(1), 2, 3, 4) +const srid3: Integer = point3.srid +const x3: number = point3.x +const y3: number = point3.y +const z3: number | undefined = point3.z -const point4: Point = new Point(1, 2, 3, 4); -const srid4: number = point4.srid; -const x4: number = point4.x; -const y4: number = point4.y; -const z4: number | undefined = point4.z; +const point4: Point = new Point(1, 2, 3, 4) +const srid4: number = point4.srid +const x4: number = point4.x +const y4: number = point4.y +const z4: number | undefined = point4.z -const isPoint1: boolean = isPoint(point1); -const isPoint2: boolean = isPoint({}); +const isPoint1: boolean = isPoint(point1) +const isPoint2: boolean = isPoint({}) diff --git a/test/types/v1/temporal-types.test.ts b/test/types/v1/temporal-types.test.ts index 6f429a309..ec7a80633 100644 --- a/test/types/v1/temporal-types.test.ts +++ b/test/types/v1/temporal-types.test.ts @@ -30,135 +30,199 @@ import { LocalDateTime, LocalTime, Time -} from "../../../types/v1/temporal-types"; -import Integer, {int} from "../../../types/v1/integer"; -import {StandardDate} from "../../../types/v1/graph-types"; - -const duration1: Duration = new Duration(int(1), int(1), int(1), int(1)); -const months1: Integer = duration1.months; -const days1: Integer = duration1.days; -const seconds1: Integer = duration1.seconds; -const nanoseconds1: Integer = duration1.nanoseconds; - -const duration2: Duration = new Duration(1, 1, 1, 1); -const months2: number = duration2.months; -const days2: number = duration2.days; -const seconds2: number = duration2.seconds; -const nanoseconds2: number = duration2.nanoseconds; - -const localTime1: LocalTime = new LocalTime(int(1), int(1), int(1), int(1)); -const localTime1Hour1: Integer = localTime1.hour; -const localTime1Minute1: Integer = localTime1.minute; -const localTime1Second1: Integer = localTime1.second; -const localTime1Nanosecond1: Integer = localTime1.nanosecond; - -const localTime2: LocalTime = new LocalTime(1, 1, 1, 1); -const localTime2Hour1: number = localTime2.hour; -const localTime2Minute1: number = localTime2.minute; -const localTime2Second1: number = localTime2.second; -const localTime2Nanosecond1: number = localTime2.nanosecond; - -const time1: Time = new Time(int(1), int(1), int(1), int(1), int(1)); -const offset1: Integer = time1.timeZoneOffsetSeconds; -const hour1: Integer = time1.hour; -const minute1: Integer = time1.minute; -const second1: Integer = time1.second; -const nanosecond1: Integer = time1.nanosecond; - -const time2: Time = new Time(1, 1, 1, 1, 1); -const offset2: number = time2.timeZoneOffsetSeconds; -const hour2: number = time2.hour; -const minute2: number = time2.minute; -const second2: number = time2.second; -const nanosecond2: number = time2.nanosecond; - -const date1: Date = new Date(int(1), int(1), int(1)); -const date1Year1: Integer = date1.year; -const date1Month1: Integer = date1.month; -const date1Day1: Integer = date1.day; - -const date2: Date = new Date(1, 1, 1); -const date2Year1: number = date2.year; -const date2Month1: number = date2.month; -const date2Day1: number = date2.day; - -const localDateTime1: LocalDateTime = new LocalDateTime(int(1), int(1), int(1), int(1), int(1), int(1), int(1)); -const year1: Integer = localDateTime1.year; -const month1: Integer = localDateTime1.month; -const day1: Integer = localDateTime1.day; -const hour3: Integer = localDateTime1.hour; -const minute3: Integer = localDateTime1.minute; -const second3: Integer = localDateTime1.second; -const nanosecond3: Integer = localDateTime1.nanosecond; - -const localDateTime2: LocalDateTime = new LocalDateTime(1, 1, 1, 1, 1, 1, 1); -const year2: number = localDateTime2.year; -const month2: number = localDateTime2.month; -const day2: number = localDateTime2.day; -const hour4: number = localDateTime2.hour; -const minute4: number = localDateTime2.minute; -const second4: number = localDateTime2.second; -const nanosecond4: number = localDateTime2.nanosecond; - -const dateTime1: DateTime = new DateTime(int(1), int(1), int(1), int(1), int(1), int(1), int(1), int(1), undefined); -const zoneId1: string | undefined = dateTime1.timeZoneId; -const offset3: Integer | undefined = dateTime1.timeZoneOffsetSeconds; -const year3: Integer = dateTime1.year; -const month3: Integer = dateTime1.month; -const day3: Integer = dateTime1.day; -const hour5: Integer = dateTime1.hour; -const minute5: Integer = dateTime1.minute; -const second5: Integer = dateTime1.second; -const nanosecond5: Integer = dateTime1.nanosecond; - -const dateTime2: DateTime = new DateTime(1, 1, 1, 1, 1, 1, 1, 1, undefined); -const zoneId2: string | undefined = dateTime2.timeZoneId; -const offset4: number | undefined = dateTime2.timeZoneOffsetSeconds; -const year4: number = dateTime2.year; -const month4: number = dateTime2.month; -const day4: number = dateTime2.day; -const hour6: number = dateTime2.hour; -const minute6: number = dateTime2.minute; -const second6: number = dateTime2.second; -const nanosecond6: number = dateTime2.nanosecond; - -const dateTime3: DateTime = new DateTime(int(1), int(1), int(1), int(1), int(1), int(1), int(1), undefined, "UTC"); -const zoneId3: string | undefined = dateTime3.timeZoneId; -const offset5: Integer | undefined = dateTime3.timeZoneOffsetSeconds; -const year5: Integer = dateTime3.year; -const month5: Integer = dateTime3.month; -const day5: Integer = dateTime3.day; -const hour7: Integer = dateTime3.hour; -const minute7: Integer = dateTime3.minute; -const second7: Integer = dateTime3.second; -const nanosecond7: Integer = dateTime3.nanosecond; - -const dateTime4: DateTime = new DateTime(1, 1, 1, 1, 1, 1, 1, undefined, "UTC"); -const zoneId4: string | undefined = dateTime4.timeZoneId; -const offset6: number | undefined = dateTime4.timeZoneOffsetSeconds; -const year6: number = dateTime4.year; -const month6: number = dateTime4.month; -const day6: number = dateTime4.day; -const hour8: number = dateTime4.hour; -const minute8: number = dateTime4.minute; -const second8: number = dateTime4.second; -const nanosecond8: number = dateTime4.nanosecond; - -const isDurationValue: boolean = isDuration(duration1); -const isLocalTimeValue: boolean = isLocalTime(localTime1); -const isTimeValue: boolean = isTime(time1); -const isDateValue: boolean = isDate(date1); -const isLocalDateTimeValue: boolean = isLocalDateTime(localDateTime1); -const isDateTimeValue: boolean = isDateTime(dateTime1); - -const dummy: any = null; -const standardDate: StandardDate = dummy; -const localTime3: LocalTime = LocalTime.fromStandardDate(standardDate); -const localTime4: LocalTime = LocalTime.fromStandardDate(standardDate, 42); -const time3: Time = Time.fromStandardDate(standardDate); -const time4: Time = Time.fromStandardDate(standardDate, 42); -const date3: Date = Date.fromStandardDate(standardDate); -const localDateTime3: LocalDateTime = LocalDateTime.fromStandardDate(standardDate); -const localDateTime4: LocalDateTime = LocalDateTime.fromStandardDate(standardDate, 42); -const dateTime5: DateTime = DateTime.fromStandardDate(standardDate); -const dateTime6: DateTime = DateTime.fromStandardDate(standardDate, 42); +} from '../../../types/v1/temporal-types' +import Integer, { int } from '../../../types/v1/integer' +import { StandardDate } from '../../../types/v1/graph-types' + +const duration1: Duration = new Duration(int(1), int(1), int(1), int(1)) +const months1: Integer = duration1.months +const days1: Integer = duration1.days +const seconds1: Integer = duration1.seconds +const nanoseconds1: Integer = duration1.nanoseconds + +const duration2: Duration = new Duration(1, 1, 1, 1) +const months2: number = duration2.months +const days2: number = duration2.days +const seconds2: number = duration2.seconds +const nanoseconds2: number = duration2.nanoseconds + +const localTime1: LocalTime = new LocalTime(int(1), int(1), int(1), int(1)) +const localTime1Hour1: Integer = localTime1.hour +const localTime1Minute1: Integer = localTime1.minute +const localTime1Second1: Integer = localTime1.second +const localTime1Nanosecond1: Integer = localTime1.nanosecond + +const localTime2: LocalTime = new LocalTime(1, 1, 1, 1) +const localTime2Hour1: number = localTime2.hour +const localTime2Minute1: number = localTime2.minute +const localTime2Second1: number = localTime2.second +const localTime2Nanosecond1: number = localTime2.nanosecond + +const time1: Time = new Time(int(1), int(1), int(1), int(1), int(1)) +const offset1: Integer = time1.timeZoneOffsetSeconds +const hour1: Integer = time1.hour +const minute1: Integer = time1.minute +const second1: Integer = time1.second +const nanosecond1: Integer = time1.nanosecond + +const time2: Time = new Time(1, 1, 1, 1, 1) +const offset2: number = time2.timeZoneOffsetSeconds +const hour2: number = time2.hour +const minute2: number = time2.minute +const second2: number = time2.second +const nanosecond2: number = time2.nanosecond + +const date1: Date = new Date(int(1), int(1), int(1)) +const date1Year1: Integer = date1.year +const date1Month1: Integer = date1.month +const date1Day1: Integer = date1.day + +const date2: Date = new Date(1, 1, 1) +const date2Year1: number = date2.year +const date2Month1: number = date2.month +const date2Day1: number = date2.day + +const localDateTime1: LocalDateTime = new LocalDateTime( + int(1), + int(1), + int(1), + int(1), + int(1), + int(1), + int(1) +) +const year1: Integer = localDateTime1.year +const month1: Integer = localDateTime1.month +const day1: Integer = localDateTime1.day +const hour3: Integer = localDateTime1.hour +const minute3: Integer = localDateTime1.minute +const second3: Integer = localDateTime1.second +const nanosecond3: Integer = localDateTime1.nanosecond + +const localDateTime2: LocalDateTime = new LocalDateTime( + 1, + 1, + 1, + 1, + 1, + 1, + 1 +) +const year2: number = localDateTime2.year +const month2: number = localDateTime2.month +const day2: number = localDateTime2.day +const hour4: number = localDateTime2.hour +const minute4: number = localDateTime2.minute +const second4: number = localDateTime2.second +const nanosecond4: number = localDateTime2.nanosecond + +const dateTime1: DateTime = new DateTime( + int(1), + int(1), + int(1), + int(1), + int(1), + int(1), + int(1), + int(1), + undefined +) +const zoneId1: string | undefined = dateTime1.timeZoneId +const offset3: Integer | undefined = dateTime1.timeZoneOffsetSeconds +const year3: Integer = dateTime1.year +const month3: Integer = dateTime1.month +const day3: Integer = dateTime1.day +const hour5: Integer = dateTime1.hour +const minute5: Integer = dateTime1.minute +const second5: Integer = dateTime1.second +const nanosecond5: Integer = dateTime1.nanosecond + +const dateTime2: DateTime = new DateTime( + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + undefined +) +const zoneId2: string | undefined = dateTime2.timeZoneId +const offset4: number | undefined = dateTime2.timeZoneOffsetSeconds +const year4: number = dateTime2.year +const month4: number = dateTime2.month +const day4: number = dateTime2.day +const hour6: number = dateTime2.hour +const minute6: number = dateTime2.minute +const second6: number = dateTime2.second +const nanosecond6: number = dateTime2.nanosecond + +const dateTime3: DateTime = new DateTime( + int(1), + int(1), + int(1), + int(1), + int(1), + int(1), + int(1), + undefined, + 'UTC' +) +const zoneId3: string | undefined = dateTime3.timeZoneId +const offset5: Integer | undefined = dateTime3.timeZoneOffsetSeconds +const year5: Integer = dateTime3.year +const month5: Integer = dateTime3.month +const day5: Integer = dateTime3.day +const hour7: Integer = dateTime3.hour +const minute7: Integer = dateTime3.minute +const second7: Integer = dateTime3.second +const nanosecond7: Integer = dateTime3.nanosecond + +const dateTime4: DateTime = new DateTime( + 1, + 1, + 1, + 1, + 1, + 1, + 1, + undefined, + 'UTC' +) +const zoneId4: string | undefined = dateTime4.timeZoneId +const offset6: number | undefined = dateTime4.timeZoneOffsetSeconds +const year6: number = dateTime4.year +const month6: number = dateTime4.month +const day6: number = dateTime4.day +const hour8: number = dateTime4.hour +const minute8: number = dateTime4.minute +const second8: number = dateTime4.second +const nanosecond8: number = dateTime4.nanosecond + +const isDurationValue: boolean = isDuration(duration1) +const isLocalTimeValue: boolean = isLocalTime(localTime1) +const isTimeValue: boolean = isTime(time1) +const isDateValue: boolean = isDate(date1) +const isLocalDateTimeValue: boolean = isLocalDateTime(localDateTime1) +const isDateTimeValue: boolean = isDateTime(dateTime1) + +const dummy: any = null +const standardDate: StandardDate = dummy +const localTime3: LocalTime = LocalTime.fromStandardDate(standardDate) +const localTime4: LocalTime = LocalTime.fromStandardDate( + standardDate, + 42 +) +const time3: Time = Time.fromStandardDate(standardDate) +const time4: Time = Time.fromStandardDate(standardDate, 42) +const date3: Date = Date.fromStandardDate(standardDate) +const localDateTime3: LocalDateTime = LocalDateTime.fromStandardDate( + standardDate +) +const localDateTime4: LocalDateTime = LocalDateTime.fromStandardDate( + standardDate, + 42 +) +const dateTime5: DateTime = DateTime.fromStandardDate(standardDate) +const dateTime6: DateTime = DateTime.fromStandardDate(standardDate, 42) diff --git a/test/types/v1/transaction.test.ts b/test/types/v1/transaction.test.ts index 642cec5d6..9064843fa 100644 --- a/test/types/v1/transaction.test.ts +++ b/test/types/v1/transaction.test.ts @@ -17,76 +17,84 @@ * limitations under the License. */ -import Transaction from "../../../types/v1/transaction"; -import Record from "../../../types/v1/record"; -import Result, {StatementResult} from "../../../types/v1/result"; -import ResultSummary from "../../../types/v1/result-summary"; +import Transaction from '../../../types/v1/transaction' +import Record from '../../../types/v1/record' +import Result, { StatementResult } from '../../../types/v1/result' +import ResultSummary from '../../../types/v1/result-summary' -const dummy: any = null; +const dummy: any = null -const tx: Transaction = dummy; +const tx: Transaction = dummy -const isOpen: boolean = tx.isOpen(); -console.log(isOpen); +const isOpen: boolean = tx.isOpen() +console.log(isOpen) -const result1: Result = tx.run("RETURN 1"); -result1.then((res: StatementResult) => { - const records: Record[] = res.records; - const summary: ResultSummary = res.summary; - console.log(records); - console.log(summary); -}).catch((error: Error) => { - console.log(error); -}); +const result1: Result = tx.run('RETURN 1') +result1 + .then((res: StatementResult) => { + const records: Record[] = res.records + const summary: ResultSummary = res.summary + console.log(records) + console.log(summary) + }) + .catch((error: Error) => { + console.log(error) + }) -const result2: Result = tx.run("RETURN 2"); -result2.subscribe({}); +const result2: Result = tx.run('RETURN 2') +result2.subscribe({}) result2.subscribe({ onNext: (record: Record) => console.log(record) -}); +}) result2.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error) -}); +}) result2.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error), onCompleted: (summary: ResultSummary) => console.log(summary) -}); +}) -const result3: Result = tx.run("RETURN $value", {value: "42"}); -result3.then((res: StatementResult) => { - const records: Record[] = res.records; - const summary: ResultSummary = res.summary; - console.log(records); - console.log(summary); -}).catch((error: Error) => { - console.log(error); -}); +const result3: Result = tx.run('RETURN $value', { value: '42' }) +result3 + .then((res: StatementResult) => { + const records: Record[] = res.records + const summary: ResultSummary = res.summary + console.log(records) + console.log(summary) + }) + .catch((error: Error) => { + console.log(error) + }) -const result4: Result = tx.run("RETURN $value", {value: "42"}); -result4.subscribe({}); +const result4: Result = tx.run('RETURN $value', { value: '42' }) +result4.subscribe({}) result4.subscribe({ onNext: (record: Record) => console.log(record) -}); +}) result4.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error) -}); +}) result4.subscribe({ onNext: (record: Record) => console.log(record), onError: (error: Error) => console.log(error), onCompleted: (summary: ResultSummary) => console.log(summary) -}); +}) -tx.commit().then((res: StatementResult) => { - console.log(res); -}).catch((error: Error) => { - console.log(error); -}); +tx.commit() + .then((res: StatementResult) => { + console.log(res) + }) + .catch((error: Error) => { + console.log(error) + }) -tx.rollback().then((res: StatementResult) => { - console.log(res); -}).catch((error: Error) => { - console.log(error); -}); +tx.rollback() + .then((res: StatementResult) => { + console.log(res) + }) + .catch((error: Error) => { + console.log(error) + }) diff --git a/test/v1/auth.test.js b/test/v1/auth.test.js index 731143910..1264107c9 100644 --- a/test/v1/auth.test.js +++ b/test/v1/auth.test.js @@ -17,57 +17,58 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; +import neo4j from '../../src/v1' describe('auth', () => { - it('should use correct username and password in basic auth', () => { - const token = neo4j.auth.basic('cat', 'dog'); + const token = neo4j.auth.basic('cat', 'dog') expect(token).toEqual({ scheme: 'basic', principal: 'cat', credentials: 'dog' - }); - }); + }) + }) it('should support realm in basic auth', () => { - const token = neo4j.auth.basic('cat', 'dog', 'apartment'); + const token = neo4j.auth.basic('cat', 'dog', 'apartment') expect(token).toEqual({ scheme: 'basic', principal: 'cat', credentials: 'dog', realm: 'apartment' - }); - }); + }) + }) it('should use correct ticket in kerberos', () => { - const token = neo4j.auth.kerberos('my-ticket'); + const token = neo4j.auth.kerberos('my-ticket') expect(token).toEqual({ scheme: 'kerberos', principal: '', credentials: 'my-ticket' - }); - }); + }) + }) it('should construct correct custom auth', () => { - const token = neo4j.auth.custom('cat', 'dog', 'apartment', 'pets'); + const token = neo4j.auth.custom('cat', 'dog', 'apartment', 'pets') expect(token).toEqual({ scheme: 'pets', principal: 'cat', credentials: 'dog', realm: 'apartment' - }); - }); + }) + }) it('should support parameters in custom auth', () => { - const token = neo4j.auth.custom('cat', 'dog', 'apartment', 'pets', {key1: 'value1', key2: 42}); + const token = neo4j.auth.custom('cat', 'dog', 'apartment', 'pets', { + key1: 'value1', + key2: 42 + }) expect(token).toEqual({ scheme: 'pets', principal: 'cat', credentials: 'dog', realm: 'apartment', - parameters: {key1: 'value1', key2: 42} - }); - }); - -}); + parameters: { key1: 'value1', key2: 42 } + }) + }) +}) diff --git a/test/v1/bolt-v3.test.js b/test/v1/bolt-v3.test.js index c2d3a697c..96c4074a2 100644 --- a/test/v1/bolt-v3.test.js +++ b/test/v1/bolt-v3.test.js @@ -17,459 +17,578 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import {ServerVersion, VERSION_3_5_0} from '../../src/v1/internal/server-version'; - -const TX_CONFIG_WITH_METADATA = {metadata: {a: 1, b: 2}}; -const TX_CONFIG_WITH_TIMEOUT = {timeout: 42}; - -const INVALID_TIMEOUT_VALUES = [0, -1, -42, '15 seconds', [1, 2, 3]]; -const INVALID_METADATA_VALUES = ['metadata', ['1', '2', '3'], () => 'hello world']; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import { + ServerVersion, + VERSION_3_5_0 +} from '../../src/v1/internal/server-version' + +const TX_CONFIG_WITH_METADATA = { metadata: { a: 1, b: 2 } } +const TX_CONFIG_WITH_TIMEOUT = { timeout: 42 } + +const INVALID_TIMEOUT_VALUES = [0, -1, -42, '15 seconds', [1, 2, 3]] +const INVALID_METADATA_VALUES = [ + 'metadata', + ['1', '2', '3'], + () => 'hello world' +] describe('Bolt V3 API', () => { - - let driver; - let session; - let serverVersion; - let originalTimeout; + let driver + let session + let serverVersion + let originalTimeout beforeEach(done => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - session = driver.session(); - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + session = driver.session() + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000 session.run('MATCH (n) DETACH DELETE n').then(result => { - serverVersion = ServerVersion.fromString(result.summary.server.version); - done(); - }); - }); + serverVersion = ServerVersion.fromString(result.summary.server.version) + done() + }) + }) afterEach(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - session.close(); - driver.close(); - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + session.close() + driver.close() + }) it('should set transaction metadata for auto-commit transaction', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } const metadata = { a: 'hello world', b: 424242, c: [true, false, true] - }; + } // call listTransactions procedure that should list itself with the specified metadata - session.run('CALL dbms.listTransactions()', {}, {metadata: metadata}) + session + .run('CALL dbms.listTransactions()', {}, { metadata: metadata }) .then(result => { - const receivedMetadata = result.records[0].get('metaData'); - expect(receivedMetadata).toEqual(metadata); - done(); + const receivedMetadata = result.records[0].get('metaData') + expect(receivedMetadata).toEqual(metadata) + done() }) .catch(error => { - done.fail(error); - }); - }); + done.fail(error) + }) + }) it('should set transaction timeout for auto-commit transaction', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } - session.run('CREATE (:Node)') // create a dummy node + session + .run('CREATE (:Node)') // create a dummy node .then(() => { - const otherSession = driver.session(); - const tx = otherSession.beginTransaction(); + const otherSession = driver.session() + const tx = otherSession.beginTransaction() tx.run('MATCH (n:Node) SET n.prop = 1') // lock dummy node but keep the transaction open .then(() => { // run a query in an auto-commit transaction with timeout and try to update the locked dummy node - session.run('MATCH (n:Node) SET n.prop = $newValue', {newValue: 2}, {timeout: 1}) + session + .run( + 'MATCH (n:Node) SET n.prop = $newValue', + { newValue: 2 }, + { timeout: 1 } + ) .then(() => done.fail('Failure expected')) .catch(error => { - expectTransactionTerminatedError(error); + expectTransactionTerminatedError(error) tx.rollback() .then(() => otherSession.close()) .then(() => done()) - .catch(error => done.fail(error)); - }); - }); - }); - }); + .catch(error => done.fail(error)) + }) + }) + }) + }) it('should set transaction metadata with read transaction function', done => { - testTransactionMetadataWithTransactionFunctions(true, done); - }); + testTransactionMetadataWithTransactionFunctions(true, done) + }) it('should set transaction metadata with write transaction function', done => { - testTransactionMetadataWithTransactionFunctions(false, done); - }); + testTransactionMetadataWithTransactionFunctions(false, done) + }) it('should fail auto-commit transaction with metadata when database does not support Bolt V3', done => { - testAutoCommitTransactionConfigWhenBoltV3NotSupported(TX_CONFIG_WITH_METADATA, done); - }); + testAutoCommitTransactionConfigWhenBoltV3NotSupported( + TX_CONFIG_WITH_METADATA, + done + ) + }) it('should fail auto-commit transaction with timeout when database does not support Bolt V3', done => { - testAutoCommitTransactionConfigWhenBoltV3NotSupported(TX_CONFIG_WITH_TIMEOUT, done); - }); + testAutoCommitTransactionConfigWhenBoltV3NotSupported( + TX_CONFIG_WITH_TIMEOUT, + done + ) + }) it('should fail read transaction function with metadata when database does not support Bolt V3', done => { - testTransactionFunctionConfigWhenBoltV3NotSupported(true, TX_CONFIG_WITH_METADATA, done); - }); + testTransactionFunctionConfigWhenBoltV3NotSupported( + true, + TX_CONFIG_WITH_METADATA, + done + ) + }) it('should fail read transaction function with timeout when database does not support Bolt V3', done => { - testTransactionFunctionConfigWhenBoltV3NotSupported(true, TX_CONFIG_WITH_TIMEOUT, done); - }); + testTransactionFunctionConfigWhenBoltV3NotSupported( + true, + TX_CONFIG_WITH_TIMEOUT, + done + ) + }) it('should fail write transaction function with metadata when database does not support Bolt V3', done => { - testTransactionFunctionConfigWhenBoltV3NotSupported(false, TX_CONFIG_WITH_METADATA, done); - }); + testTransactionFunctionConfigWhenBoltV3NotSupported( + false, + TX_CONFIG_WITH_METADATA, + done + ) + }) it('should fail write transaction function with timeout when database does not support Bolt V3', done => { - testTransactionFunctionConfigWhenBoltV3NotSupported(false, TX_CONFIG_WITH_TIMEOUT, done); - }); + testTransactionFunctionConfigWhenBoltV3NotSupported( + false, + TX_CONFIG_WITH_TIMEOUT, + done + ) + }) it('should set transaction metadata for explicit transactions', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } const metadata = { a: 12345, b: 'string', c: [1, 2, 3] - }; + } - const tx = session.beginTransaction({metadata: metadata}); + const tx = session.beginTransaction({ metadata: metadata }) // call listTransactions procedure that should list itself with the specified metadata tx.run('CALL dbms.listTransactions()') .then(result => { - const receivedMetadata = result.records[0].get('metaData'); - expect(receivedMetadata).toEqual(metadata); + const receivedMetadata = result.records[0].get('metaData') + expect(receivedMetadata).toEqual(metadata) tx.commit() .then(() => done()) - .catch(error => done.fail(error)); + .catch(error => done.fail(error)) }) .catch(error => { - done.fail(error); - }); - }); + done.fail(error) + }) + }) it('should set transaction timeout for explicit transactions', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } - session.run('CREATE (:Node)') // create a dummy node + session + .run('CREATE (:Node)') // create a dummy node .then(() => { - const otherSession = driver.session(); - const otherTx = otherSession.beginTransaction(); - otherTx.run('MATCH (n:Node) SET n.prop = 1') // lock dummy node but keep the transaction open + const otherSession = driver.session() + const otherTx = otherSession.beginTransaction() + otherTx + .run('MATCH (n:Node) SET n.prop = 1') // lock dummy node but keep the transaction open .then(() => { // run a query in an explicit transaction with timeout and try to update the locked dummy node - const tx = session.beginTransaction({timeout: 1}); - tx.run('MATCH (n:Node) SET n.prop = $newValue', {newValue: 2}) + const tx = session.beginTransaction({ timeout: 1 }) + tx.run('MATCH (n:Node) SET n.prop = $newValue', { newValue: 2 }) .then(() => done.fail('Failure expected')) .catch(error => { - expectTransactionTerminatedError(error); + expectTransactionTerminatedError(error) - otherTx.rollback() + otherTx + .rollback() .then(() => otherSession.close()) .then(() => done()) - .catch(error => done.fail(error)); - }); - }); - }); - }); + .catch(error => done.fail(error)) + }) + }) + }) + }) it('should fail to run in explicit transaction with metadata when database does not support Bolt V3', done => { - testRunInExplicitTransactionWithConfigWhenBoltV3NotSupported(TX_CONFIG_WITH_METADATA, done); - }); + testRunInExplicitTransactionWithConfigWhenBoltV3NotSupported( + TX_CONFIG_WITH_METADATA, + done + ) + }) it('should fail to run in explicit transaction with timeout when database does not support Bolt V3', done => { - testRunInExplicitTransactionWithConfigWhenBoltV3NotSupported(TX_CONFIG_WITH_TIMEOUT, done); - }); + testRunInExplicitTransactionWithConfigWhenBoltV3NotSupported( + TX_CONFIG_WITH_TIMEOUT, + done + ) + }) it('should fail to commit explicit transaction with metadata when database does not support Bolt V3', done => { - testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported(true, TX_CONFIG_WITH_METADATA, done); - }); + testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported( + true, + TX_CONFIG_WITH_METADATA, + done + ) + }) it('should fail to commit explicit transaction with timeout when database does not support Bolt V3', done => { - testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported(true, TX_CONFIG_WITH_TIMEOUT, done); - }); + testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported( + true, + TX_CONFIG_WITH_TIMEOUT, + done + ) + }) it('should fail to rollback explicit transaction with metadata when database does not support Bolt V3', done => { - testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported(false, TX_CONFIG_WITH_METADATA, done); - }); + testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported( + false, + TX_CONFIG_WITH_METADATA, + done + ) + }) it('should fail to rollback explicit transaction with timeout when database does not support Bolt V3', done => { - testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported(false, TX_CONFIG_WITH_TIMEOUT, done); - }); + testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported( + false, + TX_CONFIG_WITH_TIMEOUT, + done + ) + }) it('should fail to run auto-commit transaction with invalid timeout', () => { INVALID_TIMEOUT_VALUES.forEach(invalidValue => - expect(() => session.run('RETURN $x', {x: 42}, {timeout: invalidValue})).toThrow()); - }); + expect(() => + session.run('RETURN $x', { x: 42 }, { timeout: invalidValue }) + ).toThrow() + ) + }) it('should fail to run auto-commit transaction with invalid metadata', () => { INVALID_METADATA_VALUES.forEach(invalidValue => - expect(() => session.run('RETURN $x', {x: 42}, {metadata: invalidValue})).toThrow()); - }); + expect(() => + session.run('RETURN $x', { x: 42 }, { metadata: invalidValue }) + ).toThrow() + ) + }) it('should fail to begin explicit transaction with invalid timeout', () => { INVALID_TIMEOUT_VALUES.forEach(invalidValue => - expect(() => session.beginTransaction({timeout: invalidValue})).toThrow()); - }); + expect(() => + session.beginTransaction({ timeout: invalidValue }) + ).toThrow() + ) + }) it('should fail to begin explicit transaction with invalid metadata', () => { INVALID_METADATA_VALUES.forEach(invalidValue => - expect(() => session.beginTransaction({metadata: invalidValue})).toThrow()); - }); + expect(() => + session.beginTransaction({ metadata: invalidValue }) + ).toThrow() + ) + }) it('should fail to run read transaction function with invalid timeout', () => { INVALID_TIMEOUT_VALUES.forEach(invalidValue => - expect(() => session.readTransaction(tx => tx.run('RETURN 1'), {timeout: invalidValue})).toThrow()); - }); + expect(() => + session.readTransaction(tx => tx.run('RETURN 1'), { + timeout: invalidValue + }) + ).toThrow() + ) + }) it('should fail to run read transaction function with invalid metadata', () => { INVALID_METADATA_VALUES.forEach(invalidValue => - expect(() => session.readTransaction(tx => tx.run('RETURN 1'), {metadata: invalidValue})).toThrow()); - }); + expect(() => + session.readTransaction(tx => tx.run('RETURN 1'), { + metadata: invalidValue + }) + ).toThrow() + ) + }) it('should fail to run write transaction function with invalid timeout', () => { INVALID_TIMEOUT_VALUES.forEach(invalidValue => - expect(() => session.writeTransaction(tx => tx.run('RETURN 1'), {timeout: invalidValue})).toThrow()); - }); + expect(() => + session.writeTransaction(tx => tx.run('RETURN 1'), { + timeout: invalidValue + }) + ).toThrow() + ) + }) it('should fail to run write transaction function with invalid metadata', () => { INVALID_METADATA_VALUES.forEach(invalidValue => - expect(() => session.writeTransaction(tx => tx.run('RETURN 1'), {metadata: invalidValue})).toThrow()); - }); + expect(() => + session.writeTransaction(tx => tx.run('RETURN 1'), { + metadata: invalidValue + }) + ).toThrow() + ) + }) it('should use bookmarks for auto commit transactions', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } - const initialBookmark = session.lastBookmark(); + const initialBookmark = session.lastBookmark() session.run('CREATE ()').then(() => { - const bookmark1 = session.lastBookmark(); - expect(bookmark1).not.toBeNull(); - expect(bookmark1).toBeDefined(); - expect(bookmark1).not.toEqual(initialBookmark); + const bookmark1 = session.lastBookmark() + expect(bookmark1).not.toBeNull() + expect(bookmark1).toBeDefined() + expect(bookmark1).not.toEqual(initialBookmark) session.run('CREATE ()').then(() => { - const bookmark2 = session.lastBookmark(); - expect(bookmark2).not.toBeNull(); - expect(bookmark2).toBeDefined(); - expect(bookmark2).not.toEqual(initialBookmark); - expect(bookmark2).not.toEqual(bookmark1); + const bookmark2 = session.lastBookmark() + expect(bookmark2).not.toBeNull() + expect(bookmark2).toBeDefined() + expect(bookmark2).not.toEqual(initialBookmark) + expect(bookmark2).not.toEqual(bookmark1) session.run('CREATE ()').then(() => { - const bookmark3 = session.lastBookmark(); - expect(bookmark3).not.toBeNull(); - expect(bookmark3).toBeDefined(); - expect(bookmark3).not.toEqual(initialBookmark); - expect(bookmark3).not.toEqual(bookmark1); - expect(bookmark3).not.toEqual(bookmark2); - - done(); - }); - }); - }); - }); + const bookmark3 = session.lastBookmark() + expect(bookmark3).not.toBeNull() + expect(bookmark3).toBeDefined() + expect(bookmark3).not.toEqual(initialBookmark) + expect(bookmark3).not.toEqual(bookmark1) + expect(bookmark3).not.toEqual(bookmark2) + + done() + }) + }) + }) + }) it('should use bookmarks for auto commit and explicit transactions', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } - const initialBookmark = session.lastBookmark(); + const initialBookmark = session.lastBookmark() - const tx1 = session.beginTransaction(); + const tx1 = session.beginTransaction() tx1.run('CREATE ()').then(() => { tx1.commit().then(() => { - const bookmark1 = session.lastBookmark(); - expect(bookmark1).not.toBeNull(); - expect(bookmark1).toBeDefined(); - expect(bookmark1).not.toEqual(initialBookmark); + const bookmark1 = session.lastBookmark() + expect(bookmark1).not.toBeNull() + expect(bookmark1).toBeDefined() + expect(bookmark1).not.toEqual(initialBookmark) session.run('CREATE ()').then(() => { - const bookmark2 = session.lastBookmark(); - expect(bookmark2).not.toBeNull(); - expect(bookmark2).toBeDefined(); - expect(bookmark2).not.toEqual(initialBookmark); - expect(bookmark2).not.toEqual(bookmark1); + const bookmark2 = session.lastBookmark() + expect(bookmark2).not.toBeNull() + expect(bookmark2).toBeDefined() + expect(bookmark2).not.toEqual(initialBookmark) + expect(bookmark2).not.toEqual(bookmark1) - const tx2 = session.beginTransaction(); + const tx2 = session.beginTransaction() tx2.run('CREATE ()').then(() => { tx2.commit().then(() => { - const bookmark3 = session.lastBookmark(); - expect(bookmark3).not.toBeNull(); - expect(bookmark3).toBeDefined(); - expect(bookmark3).not.toEqual(initialBookmark); - expect(bookmark3).not.toEqual(bookmark1); - expect(bookmark3).not.toEqual(bookmark2); - - done(); - }); - }); - }); - }); - }); - }); + const bookmark3 = session.lastBookmark() + expect(bookmark3).not.toBeNull() + expect(bookmark3).toBeDefined() + expect(bookmark3).not.toEqual(initialBookmark) + expect(bookmark3).not.toEqual(bookmark1) + expect(bookmark3).not.toEqual(bookmark2) + + done() + }) + }) + }) + }) + }) + }) it('should use bookmarks for auto commit transactions and transaction functions', done => { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } - const initialBookmark = session.lastBookmark(); + const initialBookmark = session.lastBookmark() + + session + .writeTransaction(tx => tx.run('CREATE ()')) + .then(() => { + const bookmark1 = session.lastBookmark() + expect(bookmark1).not.toBeNull() + expect(bookmark1).toBeDefined() + expect(bookmark1).not.toEqual(initialBookmark) - session.writeTransaction(tx => tx.run('CREATE ()')).then(() => { - const bookmark1 = session.lastBookmark(); - expect(bookmark1).not.toBeNull(); - expect(bookmark1).toBeDefined(); - expect(bookmark1).not.toEqual(initialBookmark); + session.run('CREATE ()').then(() => { + const bookmark2 = session.lastBookmark() + expect(bookmark2).not.toBeNull() + expect(bookmark2).toBeDefined() + expect(bookmark2).not.toEqual(initialBookmark) + expect(bookmark2).not.toEqual(bookmark1) + + session + .writeTransaction(tx => tx.run('CREATE ()')) + .then(() => { + const bookmark3 = session.lastBookmark() + expect(bookmark3).not.toBeNull() + expect(bookmark3).toBeDefined() + expect(bookmark3).not.toEqual(initialBookmark) + expect(bookmark3).not.toEqual(bookmark1) + expect(bookmark3).not.toEqual(bookmark2) + + done() + }) + }) + }) + }) - session.run('CREATE ()').then(() => { - const bookmark2 = session.lastBookmark(); - expect(bookmark2).not.toBeNull(); - expect(bookmark2).toBeDefined(); - expect(bookmark2).not.toEqual(initialBookmark); - expect(bookmark2).not.toEqual(bookmark1); - - session.writeTransaction(tx => tx.run('CREATE ()')).then(() => { - const bookmark3 = session.lastBookmark(); - expect(bookmark3).not.toBeNull(); - expect(bookmark3).toBeDefined(); - expect(bookmark3).not.toEqual(initialBookmark); - expect(bookmark3).not.toEqual(bookmark1); - expect(bookmark3).not.toEqual(bookmark2); - - done(); - }); - }); - }); - }); - - function testTransactionMetadataWithTransactionFunctions(read, done) { + function testTransactionMetadataWithTransactionFunctions (read, done) { if (!databaseSupportsBoltV3()) { - done(); - return; + done() + return } const metadata = { foo: 'bar', baz: 42 - }; + } - const txFunctionWithMetadata = work => read - ? session.readTransaction(work, {metadata: metadata}) - : session.writeTransaction(work, {metadata: metadata}); + const txFunctionWithMetadata = work => + read + ? session.readTransaction(work, { metadata: metadata }) + : session.writeTransaction(work, { metadata: metadata }) txFunctionWithMetadata(tx => tx.run('CALL dbms.listTransactions()')) .then(result => { - const receivedMetadata = result.records[0].get('metaData'); - expect(receivedMetadata).toEqual(metadata); - done(); + const receivedMetadata = result.records[0].get('metaData') + expect(receivedMetadata).toEqual(metadata) + done() }) .catch(error => { - done.fail(error); - }); + done.fail(error) + }) } - function testAutoCommitTransactionConfigWhenBoltV3NotSupported(txConfig, done) { + function testAutoCommitTransactionConfigWhenBoltV3NotSupported ( + txConfig, + done + ) { if (databaseSupportsBoltV3()) { - done(); - return; + done() + return } - session.run('RETURN $x', {x: 42}, txConfig) + session + .run('RETURN $x', { x: 42 }, txConfig) .then(() => done.fail('Failure expected')) .catch(error => { - expectBoltV3NotSupportedError(error); - done(); - }); + expectBoltV3NotSupportedError(error) + done() + }) } - function testTransactionFunctionConfigWhenBoltV3NotSupported(read, txConfig, done) { + function testTransactionFunctionConfigWhenBoltV3NotSupported ( + read, + txConfig, + done + ) { if (databaseSupportsBoltV3()) { - done(); - return; + done() + return } - const txFunctionWithMetadata = work => read - ? session.readTransaction(work, txConfig) - : session.writeTransaction(work, txConfig); + const txFunctionWithMetadata = work => + read + ? session.readTransaction(work, txConfig) + : session.writeTransaction(work, txConfig) txFunctionWithMetadata(tx => tx.run('RETURN 42')) .then(() => done.fail('Failure expected')) .catch(error => { - expectBoltV3NotSupportedError(error); - done(); - }); + expectBoltV3NotSupportedError(error) + done() + }) } - function testRunInExplicitTransactionWithConfigWhenBoltV3NotSupported(txConfig, done) { + function testRunInExplicitTransactionWithConfigWhenBoltV3NotSupported ( + txConfig, + done + ) { if (databaseSupportsBoltV3()) { - done(); - return; + done() + return } - const tx = session.beginTransaction(txConfig); + const tx = session.beginTransaction(txConfig) tx.run('RETURN 42') .then(() => done.fail('Failure expected')) .catch(error => { - expectBoltV3NotSupportedError(error); - session.close(); - done(); - }); + expectBoltV3NotSupportedError(error) + session.close() + done() + }) } - function testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported(commit, txConfig, done) { + function testCloseExplicitTransactionWithConfigWhenBoltV3NotSupported ( + commit, + txConfig, + done + ) { if (databaseSupportsBoltV3()) { - done(); - return; + done() + return } - const tx = session.beginTransaction(txConfig); - const promise = commit ? tx.commit() : tx.rollback(); + const tx = session.beginTransaction(txConfig) + const promise = commit ? tx.commit() : tx.rollback() - promise.then(() => done.fail('Failure expected')) + promise + .then(() => done.fail('Failure expected')) .catch(error => { - expectBoltV3NotSupportedError(error); - session.close(); - done(); - }); + expectBoltV3NotSupportedError(error) + session.close() + done() + }) } - function expectBoltV3NotSupportedError(error) { - expect(error.message.indexOf('Driver is connected to the database that does not support transaction configuration')).toBeGreaterThan(-1); + function expectBoltV3NotSupportedError (error) { + expect( + error.message.indexOf( + 'Driver is connected to the database that does not support transaction configuration' + ) + ).toBeGreaterThan(-1) } - function expectTransactionTerminatedError(error) { - const hasExpectedMessage = error.message.toLowerCase().indexOf('transaction has been terminated') > -1; + function expectTransactionTerminatedError (error) { + const hasExpectedMessage = + error.message.toLowerCase().indexOf('transaction has been terminated') > + -1 if (!hasExpectedMessage) { - console.log(`Unexpected error with code: ${error.code}`, error); + console.log(`Unexpected error with code: ${error.code}`, error) } - expect(hasExpectedMessage).toBeTruthy(); + expect(hasExpectedMessage).toBeTruthy() } - function databaseSupportsBoltV3() { - return serverVersion.compareTo(VERSION_3_5_0) >= 0; + function databaseSupportsBoltV3 () { + return serverVersion.compareTo(VERSION_3_5_0) >= 0 } - -}); +}) diff --git a/test/v1/driver.test.js b/test/v1/driver.test.js index c63db928b..a04269d03 100644 --- a/test/v1/driver.test.js +++ b/test/v1/driver.test.js @@ -17,330 +17,382 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import FakeConnection from '../internal/fake-connection'; -import lolex from 'lolex'; -import {DEFAULT_ACQUISITION_TIMEOUT, DEFAULT_MAX_SIZE} from '../../src/v1/internal/pool-config'; -import { ServerVersion, VERSION_3_1_0, VERSION_4_0_0 } from '../../src/v1/internal/server-version'; -import testUtils from '../internal/test-utils'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import FakeConnection from '../internal/fake-connection' +import lolex from 'lolex' +import { + DEFAULT_ACQUISITION_TIMEOUT, + DEFAULT_MAX_SIZE +} from '../../src/v1/internal/pool-config' +import { + ServerVersion, + VERSION_3_1_0, + VERSION_4_0_0 +} from '../../src/v1/internal/server-version' +import testUtils from '../internal/test-utils' describe('driver', () => { - - let clock; - let driver; - let serverVersion; + let clock + let driver + let serverVersion beforeAll(done => { - const tmpDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); + const tmpDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) ServerVersion.fromDriver(tmpDriver).then(version => { - tmpDriver.close(); - serverVersion = version; - done(); - }); - }); + tmpDriver.close() + serverVersion = version + done() + }) + }) afterEach(() => { if (clock) { - clock.uninstall(); - clock = null; + clock.uninstall() + clock = null } if (driver) { - driver.close(); - driver = null; + driver.close() + driver = null } - }); + }) it('should expose sessions', () => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) // When - const session = driver.session(); + const session = driver.session() // Then - expect( session ).not.toBeNull(); - driver.close(); - }); + expect(session).not.toBeNull() + driver.close() + }) it('should handle connection errors', done => { // Given - driver = neo4j.driver("bolt://local-host", sharedNeo4j.authToken); + driver = neo4j.driver('bolt://local-host', sharedNeo4j.authToken) // Expect driver.onError = error => { - //the error message is different whether in browser or node - expect(error.message).not.toBeNull(); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - }; + // the error message is different whether in browser or node + expect(error.message).not.toBeNull() + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() + } // When - startNewTransaction(driver); - }, 10000); + startNewTransaction(driver) + }, 10000) it('should destroy failed connections', done => { // Given - driver = neo4j.driver('bolt://local-host', sharedNeo4j.authToken); + driver = neo4j.driver('bolt://local-host', sharedNeo4j.authToken) - const session = driver.session(); + const session = driver.session() - session.run('RETURN 1').catch(err => { - expect(driver._openConnections).toEqual({}); - - done(); - }); - }, 10000); + session.run('RETURN 1').catch(() => { + expect(driver._openConnections).toEqual({}) + done() + }) + }, 10000) it('should fail with correct error message when connecting to port 80', done => { if (testUtils.isClient()) { // good error message is not available in browser - done(); - return; + done() + return } - driver = neo4j.driver('bolt://localhost:80', sharedNeo4j.authToken); - - driver.session().run('RETURN 1').then(result => { - done.fail('Should not be able to connect. Result: ' + JSON.stringify(result)); - }).catch(error => { - const doesNotContainAddress = error.message.indexOf(':80') < 0; - if (doesNotContainAddress) { - done.fail(`Expected to contain ':80' but was: ${error.message}`); - } else { - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - } - }); - }); + driver = neo4j.driver('bolt://localhost:80', sharedNeo4j.authToken) + + driver + .session() + .run('RETURN 1') + .then(result => { + done.fail( + 'Should not be able to connect. Result: ' + JSON.stringify(result) + ) + }) + .catch(error => { + const doesNotContainAddress = error.message.indexOf(':80') < 0 + if (doesNotContainAddress) { + done.fail(`Expected to contain ':80' but was: ${error.message}`) + } else { + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() + } + }) + }) it('should handle wrong scheme', () => { - expect(() => neo4j.driver("tank://localhost", sharedNeo4j.authToken)) - .toThrow(new Error('Unknown scheme: tank')); - }); + expect(() => + neo4j.driver('tank://localhost', sharedNeo4j.authToken) + ).toThrow(new Error('Unknown scheme: tank')) + }) it('should handle URL parameter string', () => { - expect(() => neo4j.driver({uri: 'bolt://localhost'})).toThrowError(TypeError); + expect(() => neo4j.driver({ uri: 'bolt://localhost' })).toThrowError( + TypeError + ) - expect(() => neo4j.driver(['bolt:localhost'])).toThrowError(TypeError); + expect(() => neo4j.driver(['bolt:localhost'])).toThrowError(TypeError) expect(() => { - const driver = neo4j.driver(String('bolt://localhost'), sharedNeo4j.authToken); - return driver.session(); - }).toBeDefined(); - }); + const driver = neo4j.driver( + String('bolt://localhost'), + sharedNeo4j.authToken + ) + return driver.session() + }).toBeDefined() + }) it('should fail early on wrong credentials', done => { // Given - driver = neo4j.driver("bolt://localhost", wrongCredentials()); + driver = neo4j.driver('bolt://localhost', wrongCredentials()) // Expect driver.onError = err => { - //the error message is different whether in browser or node - expect(err.code).toEqual('Neo.ClientError.Security.Unauthorized'); - done(); - }; + // the error message is different whether in browser or node + expect(err.code).toEqual('Neo.ClientError.Security.Unauthorized') + done() + } // When - startNewTransaction(driver); - }); + startNewTransaction(driver) + }) it('should fail queries on wrong credentials', done => { - driver = neo4j.driver('bolt://localhost', wrongCredentials()); + driver = neo4j.driver('bolt://localhost', wrongCredentials()) - const session = driver.session(); + const session = driver.session() session.run('RETURN 1').catch(error => { - expect(error.code).toEqual('Neo.ClientError.Security.Unauthorized'); - done(); - }); - }); + expect(error.code).toEqual('Neo.ClientError.Security.Unauthorized') + done() + }) + }) it('should indicate success early on correct credentials', done => { // Given - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) // Expect driver.onCompleted = server => { - expect(server.address).toBeDefined(); - done(); - }; - }); + expect(server.address).toBeDefined() + done() + } + }) it('should be possible to pass a realm with basic auth tokens', done => { // Given - driver = neo4j.driver("bolt://localhost", neo4j.auth.basic(sharedNeo4j.username, sharedNeo4j.password, "native")); + driver = neo4j.driver( + 'bolt://localhost', + neo4j.auth.basic(sharedNeo4j.username, sharedNeo4j.password, 'native') + ) // Expect driver.onCompleted = server => { - expect(server.address).toBeDefined(); - done(); - }; - }); + expect(server.address).toBeDefined() + done() + } + }) it('should be possible to create custom auth tokens', done => { // Given - driver = neo4j.driver("bolt://localhost", neo4j.auth.custom(sharedNeo4j.username, sharedNeo4j.password, "native", "basic")); + driver = neo4j.driver( + 'bolt://localhost', + neo4j.auth.custom( + sharedNeo4j.username, + sharedNeo4j.password, + 'native', + 'basic' + ) + ) // Expect driver.onCompleted = server => { - expect(server.address).toBeDefined(); - done(); - }; - }); + expect(server.address).toBeDefined() + done() + } + }) it('should be possible to create custom auth tokens with additional parameters', done => { // Given - driver = neo4j.driver("bolt://localhost", neo4j.auth.custom(sharedNeo4j.username, sharedNeo4j.password, "native", "basic", {secret: 42})); + driver = neo4j.driver( + 'bolt://localhost', + neo4j.auth.custom( + sharedNeo4j.username, + sharedNeo4j.password, + 'native', + 'basic', + { secret: 42 } + ) + ) // Expect driver.onCompleted = server => { - expect(server.address).toBeDefined(); - done(); - }; - }); + expect(server.address).toBeDefined() + done() + } + }) it('should fail nicely when connecting with routing to standalone server', done => { if (serverVersion.compareTo(VERSION_4_0_0) >= 0) { - done(); - return; + done() + return } // Given - driver = neo4j.driver("bolt+routing://localhost", sharedNeo4j.authToken); + driver = neo4j.driver('bolt+routing://localhost', sharedNeo4j.authToken) // Expect driver.onError = error => { - expect(error.message).toContain('Could not perform discovery. No routing servers available.'); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - done(); - }; + expect(error.message).toContain( + 'Could not perform discovery. No routing servers available.' + ) + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + done() + } // When - startNewTransaction(driver); - }); + startNewTransaction(driver) + }) it('should have correct user agent', () => { - const directDriver = neo4j.driver("bolt://localhost"); - expect(directDriver._userAgent).toBe("neo4j-javascript/0.0.0-dev"); - directDriver.close(); + const directDriver = neo4j.driver('bolt://localhost') + expect(directDriver._userAgent).toBe('neo4j-javascript/0.0.0-dev') + directDriver.close() - const routingDriver = neo4j.driver("bolt+routing://localhost"); - expect(routingDriver._userAgent).toBe("neo4j-javascript/0.0.0-dev"); - routingDriver.close(); - }); + const routingDriver = neo4j.driver('bolt+routing://localhost') + expect(routingDriver._userAgent).toBe('neo4j-javascript/0.0.0-dev') + routingDriver.close() + }) it('should fail when TRUST_ON_FIRST_USE is used with routing', () => { const createRoutingDriverWithTOFU = () => { driver = neo4j.driver('bolt+routing://localhost', sharedNeo4j.username, { - encrypted: "ENCRYPTION_ON", - trust: 'TRUST_ON_FIRST_USE' - }); - }; + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_ON_FIRST_USE' + }) + } - expect(createRoutingDriverWithTOFU).toThrow(); - }); + expect(createRoutingDriverWithTOFU).toThrow() + }) it('should fail when bolt:// scheme used with routing params', () => { - expect(() => neo4j.driver('bolt://localhost:7687/?policy=my_policy')).toThrow(); - }); + expect(() => + neo4j.driver('bolt://localhost:7687/?policy=my_policy') + ).toThrow() + }) it('should sanitize pool setting values in the config', () => { - testConfigSanitizing('maxConnectionLifetime', 60 * 60 * 1000); - testConfigSanitizing('maxConnectionPoolSize', DEFAULT_MAX_SIZE); - testConfigSanitizing('connectionAcquisitionTimeout', DEFAULT_ACQUISITION_TIMEOUT); - }); + testConfigSanitizing('maxConnectionLifetime', 60 * 60 * 1000) + testConfigSanitizing('maxConnectionPoolSize', DEFAULT_MAX_SIZE) + testConfigSanitizing( + 'connectionAcquisitionTimeout', + DEFAULT_ACQUISITION_TIMEOUT + ) + }) it('should treat closed connections as invalid', () => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) - const connectionValid = driver._validateConnection(new FakeConnection().closed()); + const connectionValid = driver._validateConnection( + new FakeConnection().closed() + ) - expect(connectionValid).toBeFalsy(); - }); + expect(connectionValid).toBeFalsy() + }) it('should treat not old open connections as valid', () => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {maxConnectionLifetime: 10}); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + maxConnectionLifetime: 10 + }) - const connection = new FakeConnection().withCreationTimestamp(12); - clock = lolex.install(); - clock.setSystemTime(20); - const connectionValid = driver._validateConnection(connection); + const connection = new FakeConnection().withCreationTimestamp(12) + clock = lolex.install() + clock.setSystemTime(20) + const connectionValid = driver._validateConnection(connection) - expect(connectionValid).toBeTruthy(); - }); + expect(connectionValid).toBeTruthy() + }) it('should treat old open connections as invalid', () => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {maxConnectionLifetime: 10}); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + maxConnectionLifetime: 10 + }) - const connection = new FakeConnection().withCreationTimestamp(5); - clock = lolex.install(); - clock.setSystemTime(20); - const connectionValid = driver._validateConnection(connection); + const connection = new FakeConnection().withCreationTimestamp(5) + clock = lolex.install() + clock.setSystemTime(20) + const connectionValid = driver._validateConnection(connection) - expect(connectionValid).toBeFalsy(); - }); + expect(connectionValid).toBeFalsy() + }) it('should discard closed connections', done => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) - const session1 = driver.session(); + const session1 = driver.session() session1.run('CREATE () RETURN 42').then(() => { - session1.close(); + session1.close() // one connection should be established - const connections1 = openConnectionFrom(driver); - expect(connections1.length).toEqual(1); + const connections1 = openConnectionFrom(driver) + expect(connections1.length).toEqual(1) // close/break existing pooled connection - connections1.forEach(connection => connection.close()); + connections1.forEach(connection => connection.close()) - const session2 = driver.session(); + const session2 = driver.session() session2.run('RETURN 1').then(() => { - session2.close(); + session2.close() // existing connection should be disposed and new one should be created - const connections2 = openConnectionFrom(driver); - expect(connections2.length).toEqual(1); + const connections2 = openConnectionFrom(driver) + expect(connections2.length).toEqual(1) - expect(connections1[0]).not.toEqual(connections2[0]); + expect(connections1[0]).not.toEqual(connections2[0]) - done(); - }); - }); - }); + done() + }) + }) + }) it('should discard old connections', done => { - const maxLifetime = 100000; - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {maxConnectionLifetime: maxLifetime}); + const maxLifetime = 100000 + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + maxConnectionLifetime: maxLifetime + }) - const session1 = driver.session(); + const session1 = driver.session() session1.run('CREATE () RETURN 42').then(() => { - session1.close(); + session1.close() // one connection should be established - const connections1 = openConnectionFrom(driver); - expect(connections1.length).toEqual(1); + const connections1 = openConnectionFrom(driver) + expect(connections1.length).toEqual(1) // make existing connection look very old by advancing the `Date.now()` value - const currentTime = Date.now(); - clock = lolex.install(); - clock.setSystemTime(currentTime + maxLifetime * 2); + const currentTime = Date.now() + clock = lolex.install() + clock.setSystemTime(currentTime + maxLifetime * 2) - const session2 = driver.session(); + const session2 = driver.session() session2.run('RETURN 1').then(() => { - session2.close(); + session2.close() // old connection should be disposed and new one should be created - const connections2 = openConnectionFrom(driver); - expect(connections2.length).toEqual(1); + const connections2 = openConnectionFrom(driver) + expect(connections2.length).toEqual(1) - expect(connections1[0]).not.toEqual(connections2[0]); + expect(connections1[0]).not.toEqual(connections2[0]) - done(); - }); - }); - }); + done() + }) + }) + }) const exposedTypes = [ 'Node', @@ -350,41 +402,47 @@ describe('driver', () => { 'Relationship', 'Result', 'ResultSummary', - 'UnboundRelationship', - ]; + 'UnboundRelationship' + ] exposedTypes.forEach(type => { it(`should expose type ${type}`, () => { - expect(undefined === neo4j.types[type]).toBe(false); - }); - }); + expect(undefined === neo4j.types[type]).toBe(false) + }) + }) it('should connect to IPv6 address without port', done => { - testIPv6Connection('bolt://[::1]', done); - }); + testIPv6Connection('bolt://[::1]', done) + }) it('should connect to IPv6 address with port', done => { - testIPv6Connection('bolt://[::1]:7687', done); - }); + testIPv6Connection('bolt://[::1]:7687', done) + }) const nativeNumbers = [ - Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY, - Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, - -0, 0, - -42, 42, - -999, 999, - -1000, 1000, - -9000000, 9000000, - Number.MIN_SAFE_INTEGER + 1, Number.MAX_SAFE_INTEGER - 1 - ]; + Number.NEGATIVE_INFINITY, + Number.POSITIVE_INFINITY, + Number.MIN_SAFE_INTEGER, + Number.MAX_SAFE_INTEGER, + -0, + 0, + -42, + 42, + -999, + 999, + -1000, + 1000, + -9000000, + 9000000, + Number.MIN_SAFE_INTEGER + 1, + Number.MAX_SAFE_INTEGER - 1 + ] nativeNumbers.forEach(number => { - it(`should return native number ${number} when disableLosslessIntegers=true`, done => { - testNumberInReturnedRecord(number, number, done); - }); - - }); + testNumberInReturnedRecord(number, number, done) + }) + }) const integersWithNativeNumberEquivalent = [ [neo4j.int(0), 0], @@ -395,93 +453,101 @@ describe('driver', () => { [neo4j.int('-9007199254740992'), Number.NEGATIVE_INFINITY], // Number.MIN_SAFE_INTEGER - 1 [neo4j.int('9007199254740992'), Number.POSITIVE_INFINITY], // Number.MAX_SAFE_INTEGER + 1 [neo4j.int('-9007199254749999'), Number.NEGATIVE_INFINITY], // Number.MIN_SAFE_INTEGER - 9007 - [neo4j.int('9007199254749999'), Number.POSITIVE_INFINITY], // Number.MAX_SAFE_INTEGER + 9008 - ]; + [neo4j.int('9007199254749999'), Number.POSITIVE_INFINITY] // Number.MAX_SAFE_INTEGER + 9008 + ] integersWithNativeNumberEquivalent.forEach(integerWithNativeNumber => { - - const integer = integerWithNativeNumber[0]; - const nativeNumber = integerWithNativeNumber[1]; + const integer = integerWithNativeNumber[0] + const nativeNumber = integerWithNativeNumber[1] it(`should send Integer ${integer.toString()} and return native number ${nativeNumber} when disableLosslessIntegers=true`, done => { - testNumberInReturnedRecord(integer, nativeNumber, done); - }); - - }); + testNumberInReturnedRecord(integer, nativeNumber, done) + }) + }) - function testIPv6Connection(url, done) { + function testIPv6Connection (url, done) { if (serverVersion.compareTo(VERSION_3_1_0) < 0) { // IPv6 listen address only supported starting from neo4j 3.1, so let's ignore the rest - done(); - return; + done() + return } - driver = neo4j.driver(url, sharedNeo4j.authToken); + driver = neo4j.driver(url, sharedNeo4j.authToken) - const session = driver.session(); + const session = driver.session() session.run('RETURN 42').then(result => { - expect(result.records[0].get(0).toNumber()).toEqual(42); - session.close(); - done(); - }); + expect(result.records[0].get(0).toNumber()).toEqual(42) + session.close() + done() + }) } - function testNumberInReturnedRecord(inputNumber, expectedNumber, done) { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {disableLosslessIntegers: true}); + function testNumberInReturnedRecord (inputNumber, expectedNumber, done) { + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, { + disableLosslessIntegers: true + }) - const session = driver.session(); - session.run('RETURN $number AS n0, $number AS n1', {number: inputNumber}).then(result => { - session.close(); + const session = driver.session() + session + .run('RETURN $number AS n0, $number AS n1', { number: inputNumber }) + .then(result => { + session.close() - const records = result.records; - expect(records.length).toEqual(1); - const record = records[0]; + const records = result.records + expect(records.length).toEqual(1) + const record = records[0] - expect(record.get('n0')).toEqual(expectedNumber); - expect(record.get('n1')).toEqual(expectedNumber); + expect(record.get('n0')).toEqual(expectedNumber) + expect(record.get('n1')).toEqual(expectedNumber) - expect(record.get(0)).toEqual(expectedNumber); - expect(record.get(1)).toEqual(expectedNumber); + expect(record.get(0)).toEqual(expectedNumber) + expect(record.get(1)).toEqual(expectedNumber) - expect(record.toObject()).toEqual({n0: expectedNumber, n1: expectedNumber}); + expect(record.toObject()).toEqual({ + n0: expectedNumber, + n1: expectedNumber + }) - done(); - }); + done() + }) } /** * Starts new transaction to force new network connection. * @param {Driver} driver - the driver to use. */ - function startNewTransaction(driver) { - const session = driver.session(); - expect(session.beginTransaction()).toBeDefined(); + function startNewTransaction (driver) { + const session = driver.session() + expect(session.beginTransaction()).toBeDefined() } - function wrongCredentials() { - return neo4j.auth.basic('neo4j', 'who would use such a password'); + function wrongCredentials () { + return neo4j.auth.basic('neo4j', 'who would use such a password') } - function testConfigSanitizing(configProperty, defaultValue) { - validateConfigSanitizing({}, defaultValue); - validateConfigSanitizing({[configProperty]: 42}, 42); - validateConfigSanitizing({[configProperty]: 0}, 0); - validateConfigSanitizing({[configProperty]: '42'}, 42); - validateConfigSanitizing({[configProperty]: '042'}, 42); - validateConfigSanitizing({[configProperty]: -42}, Number.MAX_SAFE_INTEGER); + function testConfigSanitizing (configProperty, defaultValue) { + validateConfigSanitizing({}, defaultValue) + validateConfigSanitizing({ [configProperty]: 42 }, 42) + validateConfigSanitizing({ [configProperty]: 0 }, 0) + validateConfigSanitizing({ [configProperty]: '42' }, 42) + validateConfigSanitizing({ [configProperty]: '042' }, 42) + validateConfigSanitizing({ [configProperty]: -42 }, Number.MAX_SAFE_INTEGER) } - function validateConfigSanitizing(config, configProperty, expectedValue) { - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, config); + function validateConfigSanitizing (config, configProperty, expectedValue) { + const driver = neo4j.driver( + 'bolt://localhost', + sharedNeo4j.authToken, + config + ) try { - expect(driver._config[configProperty]).toEqual(expectedValue); + expect(driver._config[configProperty]).toEqual(expectedValue) } finally { - driver.close(); + driver.close() } } - function openConnectionFrom(driver) { - return Array.from(Object.values(driver._openConnections)); + function openConnectionFrom (driver) { + return Array.from(Object.values(driver._openConnections)) } - -}); +}) diff --git a/test/v1/examples.test.js b/test/v1/examples.test.js index a130b35fe..5cd139e08 100644 --- a/test/v1/examples.test.js +++ b/test/v1/examples.test.js @@ -17,8 +17,8 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' /** * The tests below are examples that get pulled into the Driver Manual using the tags inside the tests. @@ -28,618 +28,671 @@ import sharedNeo4j from '../internal/shared-neo4j'; * DO NOT modify these tests without ensuring they remain consistent with the equivalent examples in other drivers */ describe('examples', () => { + const neo4jV1 = neo4j - const neo4jV1 = neo4j; + let driverGlobal + let console + let originalTimeout - let driverGlobal; - let console; - let originalTimeout; + let testResultPromise + let resolveTestResultPromise - let testResultPromise; - let resolveTestResultPromise; - - const user = sharedNeo4j.username; - const password = sharedNeo4j.password; - const uri = 'bolt://localhost:7687'; + const user = sharedNeo4j.username + const password = sharedNeo4j.password + const uri = 'bolt://localhost:7687' beforeAll(() => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000; + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000 - driverGlobal = neo4j.driver(uri, sharedNeo4j.authToken); - }); + driverGlobal = neo4j.driver(uri, sharedNeo4j.authToken) + }) beforeEach(done => { - testResultPromise = new Promise((resolve, reject) => { - resolveTestResultPromise = resolve; - }); + resolveTestResultPromise = resolve + }) // Override console.log, to assert on stdout output - console = {log: resolveTestResultPromise}; + console = { log: resolveTestResultPromise } - const session = driverGlobal.session(); + const session = driverGlobal.session() session.run('MATCH (n) DETACH DELETE n').then(() => { session.close(() => { - done(); - }); - }); - }); + done() + }) + }) + }) afterAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - driverGlobal.close(); - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + driverGlobal.close() + }) it('autocommit transaction example', done => { - const driver = driverGlobal; + const driver = driverGlobal // tag::autocommit-transaction[] - function addPerson(name) { - const session = driver.session(); - return session.run('CREATE (a:Person {name: $name})', {name: name}).then(result => { - session.close(); - return result; - }); + function addPerson (name) { + const session = driver.session() + return session + .run('CREATE (a:Person {name: $name})', { name: name }) + .then(result => { + session.close() + return result + }) } // end::autocommit-transaction[] addPerson('Alice').then(() => { - const session = driver.session(); - session.run('MATCH (a:Person {name: $name}) RETURN count(a) AS result', {name: 'Alice'}).then(result => { - session.close(() => { - expect(result.records[0].get('result').toInt()).toEqual(1); - done(); - }); - }); - }); - }); + const session = driver.session() + session + .run('MATCH (a:Person {name: $name}) RETURN count(a) AS result', { + name: 'Alice' + }) + .then(result => { + session.close(() => { + expect(result.records[0].get('result').toInt()).toEqual(1) + done() + }) + }) + }) + }) it('basic auth example', done => { // tag::basic-auth[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)) // end::basic-auth[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('config connection pool example', done => { // tag::config-connection-pool[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), - { - maxConnectionLifetime: 3 * 60 * 60 * 1000, // 3 hours - maxConnectionPoolSize: 50, - connectionAcquisitionTimeout: 2 * 60 * 1000 // 120 seconds - } - ); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + maxConnectionLifetime: 3 * 60 * 60 * 1000, // 3 hours + maxConnectionPoolSize: 50, + connectionAcquisitionTimeout: 2 * 60 * 1000 // 120 seconds + }) // end::config-connection-pool[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('config connection timeout example', done => { // tag::config-connection-timeout[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), - { - connectionTimeout: 20 * 1000, // 20 seconds - } - ); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + connectionTimeout: 20 * 1000 // 20 seconds + }) // end::config-connection-timeout[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('config load balancing example', done => { // tag::config-load-balancing-strategy[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), - { - loadBalancingStrategy: "least_connected" - } - ); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + loadBalancingStrategy: 'least_connected' + }) // end::config-load-balancing-strategy[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('config max retry time example', done => { // tag::config-max-retry-time[] - const maxRetryTimeMs = 15 * 1000; // 15 seconds - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), - { - maxTransactionRetryTime: maxRetryTimeMs - } - ); + const maxRetryTimeMs = 15 * 1000 // 15 seconds + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + maxTransactionRetryTime: maxRetryTimeMs + }) // end::config-max-retry-time[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('config trust example', done => { // tag::config-trust[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), - { - encrypted: 'ENCRYPTION_ON', - trust: 'TRUST_ALL_CERTIFICATES' - } - ); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + encrypted: 'ENCRYPTION_ON', + trust: 'TRUST_ALL_CERTIFICATES' + }) // end::config-trust[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('config unencrypted example', done => { // tag::config-unencrypted[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), - { - encrypted: 'ENCRYPTION_OFF' - } - ); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + encrypted: 'ENCRYPTION_OFF' + }) // end::config-unencrypted[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) + /* eslint-disable no-unused-vars */ it('config custom resolver example', done => { // tag::config-custom-resolver[] - function createDriver(virtualUri, user, password, addresses) { + function createDriver (virtualUri, user, password, addresses) { return neo4j.driver(virtualUri, neo4j.auth.basic(user, password), { - resolver: (address) => addresses, - }); + resolver: address => addresses + }) } - function addPerson(name) { - const driver = createDriver("bolt+routing://x.acme.com", user, password, ['a.acme.com:7575', 'b.acme.com:7676', 'c.acme.com:8787']); - const session = driver.session(neo4j.WRITE); - - session.run('CREATE (n:Person { name: $name })', {name: name}).then(() => { - session.close(); - driver.close(); - }); + function addPerson (name) { + const driver = createDriver('bolt+routing://x.acme.com', user, password, [ + 'a.acme.com:7575', + 'b.acme.com:7676', + 'c.acme.com:8787' + ]) + const session = driver.session(neo4j.WRITE) + + session + .run('CREATE (n:Person { name: $name })', { name: name }) + .then(() => { + session.close() + driver.close() + }) } // end::config-custom-resolver[] - done(); - }); + done() + }) it('custom auth example', done => { - const principal = user; - const credentials = password; - const realm = undefined; - const scheme = 'basic'; - const parameters = {}; + const principal = user + const credentials = password + const realm = undefined + const scheme = 'basic' + const parameters = {} // tag::custom-auth[] - const driver = neo4j.driver(uri, neo4j.auth.custom(principal, credentials, realm, scheme, parameters)); + const driver = neo4j.driver( + uri, + neo4j.auth.custom(principal, credentials, realm, scheme, parameters) + ) // end::custom-auth[] driver.onCompleted = () => { - driver.close(); - done(); - }; - }); + driver.close() + done() + } + }) it('kerberos auth example', () => { - const ticket = 'a base64 encoded ticket'; + const ticket = 'a base64 encoded ticket' // tag::kerberos-auth[] - const driver = neo4j.driver(uri, neo4j.auth.kerberos(ticket)); + const driver = neo4j.driver(uri, neo4j.auth.kerberos(ticket)) // end::kerberos-auth[] - driver.close(); - }); + driver.close() + }) it('cypher error example', done => { - const driver = driverGlobal; - const personName = 'Bob'; + const driver = driverGlobal + const personName = 'Bob' // tag::cypher-error[] - const session = driver.session(); + const session = driver.session() - const readTxPromise = session.readTransaction(tx => tx.run('SELECT * FROM Employees WHERE name = $name', {name: personName})); + const readTxPromise = session.readTransaction(tx => + tx.run('SELECT * FROM Employees WHERE name = $name', { name: personName }) + ) readTxPromise.catch(error => { - session.close(); - console.log(error.message); - }); + session.close() + console.log(error.message) + }) // end::cypher-error[] testResultPromise.then(loggedMsg => { - expect(removeLineBreaks(loggedMsg)).toBe(removeLineBreaks( - 'Invalid input \'L\': expected \'t/T\' (line 1, column 3 (offset: 2))\n' + - '"SELECT * FROM Employees WHERE name = $name"\n' + - ' ^')); - done(); - }); - }); + expect(removeLineBreaks(loggedMsg)).toBe( + removeLineBreaks( + "Invalid input 'L': expected 't/T' (line 1, column 3 (offset: 2))\n" + + '"SELECT * FROM Employees WHERE name = $name"\n' + + ' ^' + ) + ) + done() + }) + }) it('driver lifecycle example', done => { // tag::driver-lifecycle[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)) driver.onCompleted = () => { - console.log('Driver created'); - }; + console.log('Driver created') + } driver.onError = error => { - console.log(error); - }; + console.log(error) + } - const session = driver.session(); + const session = driver.session() session.run('CREATE (i:Item)').then(() => { - session.close(); + session.close() // ... on application exit: - driver.close(); - }); + driver.close() + }) // end::driver-lifecycle[] testResultPromise.then(loggedMsg => { - expect(loggedMsg).toEqual('Driver created'); - done(); - }); - }); + expect(loggedMsg).toEqual('Driver created') + done() + }) + }) it('hello world example', done => { // tag::hello-world[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)); - const session = driver.session(); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)) + const session = driver.session() - const resultPromise = session.writeTransaction(tx => tx.run( - 'CREATE (a:Greeting) SET a.message = $message RETURN a.message + ", from node " + id(a)', - {message: 'hello, world'})); + const resultPromise = session.writeTransaction(tx => + tx.run( + 'CREATE (a:Greeting) SET a.message = $message RETURN a.message + ", from node " + id(a)', + { message: 'hello, world' } + ) + ) resultPromise.then(result => { - session.close(); + session.close() - const singleRecord = result.records[0]; - const greeting = singleRecord.get(0); + const singleRecord = result.records[0] + const greeting = singleRecord.get(0) - console.log(greeting); + console.log(greeting) // on application exit: - driver.close(); - }); + driver.close() + }) // end::hello-world[] testResultPromise.then(loggedMsg => { - expect(loggedMsg.indexOf('hello, world, from node') === 0).toBeTruthy(); - done(); - }); - }); + expect(loggedMsg.indexOf('hello, world, from node') === 0).toBeTruthy() + done() + }) + }) it('language guide page example', done => { const require = () => { - return {v1: neo4jV1}; - }; + return { v1: neo4jV1 } + } // tag::language-guide-page[] - const neo4j = require('neo4j-driver').v1; + const neo4j = require('neo4j-driver').v1 - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)); - const session = driver.session(); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password)) + const session = driver.session() - const personName = 'Alice'; + const personName = 'Alice' const resultPromise = session.run( 'CREATE (a:Person {name: $name}) RETURN a', - {name: personName} - ); + { name: personName } + ) resultPromise.then(result => { - session.close(); + session.close() - const singleRecord = result.records[0]; - const node = singleRecord.get(0); + const singleRecord = result.records[0] + const node = singleRecord.get(0) - console.log(node.properties.name); + console.log(node.properties.name) // on application exit: - driver.close(); - }); + driver.close() + }) // end::language-guide-page[] testResultPromise.then(loggedMsg => { - expect(loggedMsg).toEqual(personName); - done(); - }); - }); + expect(loggedMsg).toEqual(personName) + done() + }) + }) it('read write transaction example', done => { - const driver = driverGlobal; - const personName = 'Alice'; + const driver = driverGlobal + const personName = 'Alice' // tag::read-write-transaction[] - const session = driver.session(); + const session = driver.session() - const writeTxPromise = session.writeTransaction(tx => tx.run('CREATE (a:Person {name: $name})', {name: personName})); + const writeTxPromise = session.writeTransaction(tx => + tx.run('CREATE (a:Person {name: $name})', { name: personName }) + ) writeTxPromise.then(() => { - const readTxPromise = session.readTransaction(tx => tx.run('MATCH (a:Person {name: $name}) RETURN id(a)', {name: personName})); + const readTxPromise = session.readTransaction(tx => + tx.run('MATCH (a:Person {name: $name}) RETURN id(a)', { + name: personName + }) + ) readTxPromise.then(result => { - session.close(); + session.close() - const singleRecord = result.records[0]; - const createdNodeId = singleRecord.get(0); + const singleRecord = result.records[0] + const createdNodeId = singleRecord.get(0) - console.log('Matched created node with id: ' + createdNodeId); - }); - }); + console.log('Matched created node with id: ' + createdNodeId) + }) + }) // end::read-write-transaction[] testResultPromise.then(loggedMsg => { - expect(loggedMsg.indexOf('Matched created node with id') === 0).toBeTruthy(); - done(); - }); - }); + expect( + loggedMsg.indexOf('Matched created node with id') === 0 + ).toBeTruthy() + done() + }) + }) it('result consume example', done => { - const driver = driverGlobal; - const names = {nameA: 'Alice', nameB: 'Bob'}; - const tmpSession = driver.session(); - - tmpSession.run('CREATE (a:Person {name: $nameA}), (b:Person {name: $nameB})', names).then(() => { - tmpSession.close(() => { - - // tag::result-consume[] - const session = driver.session(); - const result = session.run('MATCH (a:Person) RETURN a.name ORDER BY a.name'); - const collectedNames = []; - - result.subscribe({ - onNext: record => { - const name = record.get(0); - collectedNames.push(name); - }, - onCompleted: () => { - session.close(); - - console.log('Names: ' + collectedNames.join(', ')); - }, - onError: error => { - console.log(error); - } - }); - // end::result-consume[] - }); - }); + const driver = driverGlobal + const names = { nameA: 'Alice', nameB: 'Bob' } + const tmpSession = driver.session() + + tmpSession + .run('CREATE (a:Person {name: $nameA}), (b:Person {name: $nameB})', names) + .then(() => { + tmpSession.close(() => { + // tag::result-consume[] + const session = driver.session() + const result = session.run( + 'MATCH (a:Person) RETURN a.name ORDER BY a.name' + ) + const collectedNames = [] + + result.subscribe({ + onNext: record => { + const name = record.get(0) + collectedNames.push(name) + }, + onCompleted: () => { + session.close() + + console.log('Names: ' + collectedNames.join(', ')) + }, + onError: error => { + console.log(error) + } + }) + // end::result-consume[] + }) + }) testResultPromise.then(loggedMsg => { - expect(loggedMsg).toEqual('Names: Alice, Bob'); - done(); - }); - }); + expect(loggedMsg).toEqual('Names: Alice, Bob') + done() + }) + }) it('result retain example', done => { - const driver = driverGlobal; - const companyName = 'Acme'; - const personNames = {nameA: 'Alice', nameB: 'Bob'}; - const tmpSession = driver.session(); - - tmpSession.run('CREATE (a:Person {name: $nameA}), (b:Person {name: $nameB})', personNames).then(() => { - tmpSession.close(() => { - - // tag::result-retain[] - const session = driver.session(); - - const readTxPromise = session.readTransaction(tx => tx.run('MATCH (a:Person) RETURN a.name AS name')); - - const addEmployeesPromise = readTxPromise.then(result => { - const nameRecords = result.records; - - let writeTxsPromise = Promise.resolve(); - for (let i = 0; i < nameRecords.length; i++) { - const name = nameRecords[i].get('name'); - - writeTxsPromise = writeTxsPromise.then(() => - session.writeTransaction(tx => - tx.run( - 'MATCH (emp:Person {name: $person_name}) ' + - 'MERGE (com:Company {name: $company_name}) ' + - 'MERGE (emp)-[:WORKS_FOR]->(com)', - {'person_name': name, 'company_name': companyName}))); - } - - return writeTxsPromise.then(() => nameRecords.length); - }); - - addEmployeesPromise.then(employeesCreated => { - session.close(); - console.log('Created ' + employeesCreated + ' employees'); - }); - // end::result-retain[] - }); - }); + const driver = driverGlobal + const companyName = 'Acme' + const personNames = { nameA: 'Alice', nameB: 'Bob' } + const tmpSession = driver.session() + + tmpSession + .run( + 'CREATE (a:Person {name: $nameA}), (b:Person {name: $nameB})', + personNames + ) + .then(() => { + tmpSession.close(() => { + // tag::result-retain[] + const session = driver.session() + + const readTxPromise = session.readTransaction(tx => + tx.run('MATCH (a:Person) RETURN a.name AS name') + ) + + const addEmployeesPromise = readTxPromise.then(result => { + const nameRecords = result.records + + let writeTxsPromise = Promise.resolve() + for (let i = 0; i < nameRecords.length; i++) { + const name = nameRecords[i].get('name') + + writeTxsPromise = writeTxsPromise.then(() => + session.writeTransaction(tx => + tx.run( + 'MATCH (emp:Person {name: $person_name}) ' + + 'MERGE (com:Company {name: $company_name}) ' + + 'MERGE (emp)-[:WORKS_FOR]->(com)', + { person_name: name, company_name: companyName } + ) + ) + ) + } + + return writeTxsPromise.then(() => nameRecords.length) + }) + + addEmployeesPromise.then(employeesCreated => { + session.close() + console.log('Created ' + employeesCreated + ' employees') + }) + // end::result-retain[] + }) + }) testResultPromise.then(loggedMsg => { - driver.close(); - expect(loggedMsg).toEqual('Created 2 employees'); - done(); - }); - }); + driver.close() + expect(loggedMsg).toEqual('Created 2 employees') + done() + }) + }) it('service unavailable example', done => { - const uri = 'bolt://localhost:7688'; // wrong port - const password = 'wrongPassword'; + const uri = 'bolt://localhost:7688' // wrong port + const password = 'wrongPassword' // tag::service-unavailable[] - const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {maxTransactionRetryTime: 3000}); - const session = driver.session(); + const driver = neo4j.driver(uri, neo4j.auth.basic(user, password), { + maxTransactionRetryTime: 3000 + }) + const session = driver.session() - const writeTxPromise = session.writeTransaction(tx => tx.run('CREATE (a:Item)')); + const writeTxPromise = session.writeTransaction(tx => + tx.run('CREATE (a:Item)') + ) writeTxPromise.catch(error => { if (error.code === neo4j.error.SERVICE_UNAVAILABLE) { - console.log('Unable to create node: ' + error.code); + console.log('Unable to create node: ' + error.code) } - }); + }) // end::service-unavailable[] testResultPromise.then(loggedMsg => { - driver.close(); - expect(loggedMsg).toBe('Unable to create node: ' + neo4j.error.SERVICE_UNAVAILABLE); - done(); - }); - }); + driver.close() + expect(loggedMsg).toBe( + 'Unable to create node: ' + neo4j.error.SERVICE_UNAVAILABLE + ) + done() + }) + }) it('session example', done => { - const driver = driverGlobal; - const personName = 'Alice'; + const driver = driverGlobal + const personName = 'Alice' // tag::session[] - const session = driver.session(); + const session = driver.session() - session.run('CREATE (a:Person {name: $name})', {'name': personName}).then(() => { - session.close(() => { - console.log('Person created, session closed'); - }); - }); + session + .run('CREATE (a:Person {name: $name})', { name: personName }) + .then(() => { + session.close(() => { + console.log('Person created, session closed') + }) + }) // end::session[] testResultPromise.then(loggedMsg => { - expect(loggedMsg).toBe('Person created, session closed'); - done(); - }); - }); + expect(loggedMsg).toBe('Person created, session closed') + done() + }) + }) it('transaction function example', done => { - const driver = driverGlobal; - const personName = 'Alice'; + const driver = driverGlobal + const personName = 'Alice' // tag::transaction-function[] - const session = driver.session(); - const writeTxPromise = session.writeTransaction(tx => tx.run('CREATE (a:Person {name: $name})', {'name': personName})); + const session = driver.session() + const writeTxPromise = session.writeTransaction(tx => + tx.run('CREATE (a:Person {name: $name})', { name: personName }) + ) writeTxPromise.then(result => { - session.close(); + session.close() if (result) { - console.log('Person created'); + console.log('Person created') } - }); + }) // end::transaction-function[] testResultPromise.then(loggedMsg => { - expect(loggedMsg).toBe('Person created'); - done(); - }); - }); + expect(loggedMsg).toBe('Person created') + done() + }) + }) it('pass bookmarks example', done => { - const driver = driverGlobal; + const driver = driverGlobal // tag::pass-bookmarks[] // Create a company node - function addCompany(tx, name) { - return tx.run('CREATE (a:Company {name: $name})', {'name': name}); + function addCompany (tx, name) { + return tx.run('CREATE (a:Company {name: $name})', { name: name }) } // Create a person node - function addPerson(tx, name) { - return tx.run('CREATE (a:Person {name: $name})', {'name': name}); + function addPerson (tx, name) { + return tx.run('CREATE (a:Person {name: $name})', { name: name }) } // Create an employment relationship to a pre-existing company node. // This relies on the person first having been created. - function addEmployee(tx, personName, companyName) { - return tx.run('MATCH (person:Person {name: $personName}) ' + - 'MATCH (company:Company {name: $companyName}) ' + - 'CREATE (person)-[:WORKS_FOR]->(company)', {'personName': personName, 'companyName': companyName}); + function addEmployee (tx, personName, companyName) { + return tx.run( + 'MATCH (person:Person {name: $personName}) ' + + 'MATCH (company:Company {name: $companyName}) ' + + 'CREATE (person)-[:WORKS_FOR]->(company)', + { personName: personName, companyName: companyName } + ) } // Create a friendship between two people. - function makeFriends(tx, name1, name2) { - return tx.run('MATCH (a:Person {name: $name1}) ' + - 'MATCH (b:Person {name: $name2}) ' + - 'MERGE (a)-[:KNOWS]->(b)', {'name1': name1, 'name2': name2}); + function makeFriends (tx, name1, name2) { + return tx.run( + 'MATCH (a:Person {name: $name1}) ' + + 'MATCH (b:Person {name: $name2}) ' + + 'MERGE (a)-[:KNOWS]->(b)', + { name1: name1, name2: name2 } + ) } // To collect friend relationships - const friends = []; + const friends = [] // Match and display all friendships. - function findFriendships(tx) { - const result = tx.run('MATCH (a)-[:KNOWS]->(b) RETURN a.name, b.name'); + function findFriendships (tx) { + const result = tx.run('MATCH (a)-[:KNOWS]->(b) RETURN a.name, b.name') result.subscribe({ onNext: record => { - const name1 = record.get(0); - const name2 = record.get(1); + const name1 = record.get(0) + const name2 = record.get(1) - friends.push({'name1': name1, 'name2': name2}); + friends.push({ name1: name1, name2: name2 }) } - }); + }) } // To collect the session bookmarks - const savedBookmarks = []; + const savedBookmarks = [] // Create the first person and employment relationship. - const session1 = driver.session(neo4j.WRITE); - const first = session1.writeTransaction(tx => addCompany(tx, 'Wayne Enterprises')).then( - () => session1.writeTransaction(tx => addPerson(tx, 'Alice'))).then( - () => session1.writeTransaction(tx => addEmployee(tx, 'Alice', 'Wayne Enterprises'))).then( - () => { - savedBookmarks.push(session1.lastBookmark()); + const session1 = driver.session(neo4j.WRITE) + const first = session1 + .writeTransaction(tx => addCompany(tx, 'Wayne Enterprises')) + .then(() => session1.writeTransaction(tx => addPerson(tx, 'Alice'))) + .then(() => + session1.writeTransaction(tx => + addEmployee(tx, 'Alice', 'Wayne Enterprises') + ) + ) + .then(() => { + savedBookmarks.push(session1.lastBookmark()) - return session1.close(); - }); + return session1.close() + }) // Create the second person and employment relationship. - const session2 = driver.session(neo4j.WRITE); - const second = session2.writeTransaction(tx => addCompany(tx, 'LexCorp')).then( - () => session2.writeTransaction(tx => addPerson(tx, 'Bob'))).then( - () => session2.writeTransaction(tx => addEmployee(tx, 'Bob', 'LexCorp'))).then( - () => { - savedBookmarks.push(session2.lastBookmark()); - - return session2.close(); - }); + const session2 = driver.session(neo4j.WRITE) + const second = session2 + .writeTransaction(tx => addCompany(tx, 'LexCorp')) + .then(() => session2.writeTransaction(tx => addPerson(tx, 'Bob'))) + .then(() => + session2.writeTransaction(tx => addEmployee(tx, 'Bob', 'LexCorp')) + ) + .then(() => { + savedBookmarks.push(session2.lastBookmark()) + + return session2.close() + }) // Create a friendship between the two people created above. const last = Promise.all([first, second]).then(ignore => { - const session3 = driver.session(neo4j.WRITE, savedBookmarks); + const session3 = driver.session(neo4j.WRITE, savedBookmarks) - return session3.writeTransaction(tx => makeFriends(tx, 'Alice', 'Bob')).then( - () => session3.readTransaction(findFriendships).then( - () => session3.close() + return session3 + .writeTransaction(tx => makeFriends(tx, 'Alice', 'Bob')) + .then(() => + session3.readTransaction(findFriendships).then(() => session3.close()) ) - ); - }); + }) // end::pass-bookmarks[] last.then(() => { - expect(friends.length).toBe(1); - expect(friends[0].name1).toBe('Alice'); - expect(friends[0].name2).toBe('Bob'); - - done(); - }); - }); + expect(friends.length).toBe(1) + expect(friends[0].name1).toBe('Alice') + expect(friends[0].name2).toBe('Bob') -}); + done() + }) + }) +}) -function removeLineBreaks(string) { - return string.replace(/(\r\n|\n|\r)/gm, ' '); +function removeLineBreaks (string) { + return string.replace(/(\r\n|\n|\r)/gm, ' ') } diff --git a/test/v1/integer.test.js b/test/v1/integer.test.js index a7d34e321..191307eb4 100644 --- a/test/v1/integer.test.js +++ b/test/v1/integer.test.js @@ -17,57 +17,81 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import Integer from '../../src/v1/integer'; +import neo4j from '../../src/v1' +import Integer from '../../src/v1/integer' -const int = neo4j.int; -const integer = neo4j.integer; +const int = neo4j.int +const integer = neo4j.integer describe('Integer', () => { - it('exposes inSafeRange function', () => { - expect(integer.inSafeRange(int('9007199254740991'))).toBeTruthy(); - expect(integer.inSafeRange(int('9007199254740992'))).toBeFalsy(); - expect(integer.inSafeRange(int('-9007199254740991'))).toBeTruthy(); - expect(integer.inSafeRange(int('-9007199254740992'))).toBeFalsy(); - }); + expect(integer.inSafeRange(int('9007199254740991'))).toBeTruthy() + expect(integer.inSafeRange(int('9007199254740992'))).toBeFalsy() + expect(integer.inSafeRange(int('-9007199254740991'))).toBeTruthy() + expect(integer.inSafeRange(int('-9007199254740992'))).toBeFalsy() + }) it('exposes toNumber function', () => { - expect(integer.toNumber(int('9007199254740991'))).toEqual(9007199254740991); - expect(integer.toNumber(int('-9007199254740991'))).toEqual(-9007199254740991); - }); + expect(integer.toNumber(int('9007199254740991'))).toEqual(9007199254740991) + expect(integer.toNumber(int('-9007199254740991'))).toEqual( + -9007199254740991 + ) + }) it('exposes toString function', () => { - expect(integer.toString(int('9007199254740991'))).toEqual('9007199254740991'); - expect(integer.toString(int('9007199254740992'))).toEqual('9007199254740992'); - expect(integer.toString(int('-9007199254740991'))).toEqual('-9007199254740991'); - expect(integer.toString(int('-9007199254740992'))).toEqual('-9007199254740992'); - }); + expect(integer.toString(int('9007199254740991'))).toEqual( + '9007199254740991' + ) + expect(integer.toString(int('9007199254740992'))).toEqual( + '9007199254740992' + ) + expect(integer.toString(int('-9007199254740991'))).toEqual( + '-9007199254740991' + ) + expect(integer.toString(int('-9007199254740992'))).toEqual( + '-9007199254740992' + ) + }) it('converts to number when safe', () => { - expect(int('42').toNumberOrInfinity()).toEqual(42); - expect(int('4242').toNumberOrInfinity()).toEqual(4242); - expect(int('-999').toNumberOrInfinity()).toEqual(-999); - expect(int('1000000000').toNumberOrInfinity()).toEqual(1000000000); - expect(Integer.MIN_SAFE_VALUE.toNumberOrInfinity()).toEqual(Integer.MIN_SAFE_VALUE.toNumber()); - expect(Integer.MAX_SAFE_VALUE.toNumberOrInfinity()).toEqual(Integer.MAX_SAFE_VALUE.toNumber()); - }); + expect(int('42').toNumberOrInfinity()).toEqual(42) + expect(int('4242').toNumberOrInfinity()).toEqual(4242) + expect(int('-999').toNumberOrInfinity()).toEqual(-999) + expect(int('1000000000').toNumberOrInfinity()).toEqual(1000000000) + expect(Integer.MIN_SAFE_VALUE.toNumberOrInfinity()).toEqual( + Integer.MIN_SAFE_VALUE.toNumber() + ) + expect(Integer.MAX_SAFE_VALUE.toNumberOrInfinity()).toEqual( + Integer.MAX_SAFE_VALUE.toNumber() + ) + }) it('converts to negative infinity when too small', () => { - expect(Integer.MIN_SAFE_VALUE.subtract(1).toNumberOrInfinity()).toEqual(Number.NEGATIVE_INFINITY); - expect(Integer.MIN_SAFE_VALUE.subtract(42).toNumberOrInfinity()).toEqual(Number.NEGATIVE_INFINITY); - expect(Integer.MIN_SAFE_VALUE.subtract(100).toNumberOrInfinity()).toEqual(Number.NEGATIVE_INFINITY); - }); + expect(Integer.MIN_SAFE_VALUE.subtract(1).toNumberOrInfinity()).toEqual( + Number.NEGATIVE_INFINITY + ) + expect(Integer.MIN_SAFE_VALUE.subtract(42).toNumberOrInfinity()).toEqual( + Number.NEGATIVE_INFINITY + ) + expect(Integer.MIN_SAFE_VALUE.subtract(100).toNumberOrInfinity()).toEqual( + Number.NEGATIVE_INFINITY + ) + }) it('converts to positive infinity when too large', () => { - expect(Integer.MAX_SAFE_VALUE.add(1).toNumberOrInfinity()).toEqual(Number.POSITIVE_INFINITY); - expect(Integer.MAX_SAFE_VALUE.add(24).toNumberOrInfinity()).toEqual(Number.POSITIVE_INFINITY); - expect(Integer.MAX_SAFE_VALUE.add(999).toNumberOrInfinity()).toEqual(Number.POSITIVE_INFINITY); - }); + expect(Integer.MAX_SAFE_VALUE.add(1).toNumberOrInfinity()).toEqual( + Number.POSITIVE_INFINITY + ) + expect(Integer.MAX_SAFE_VALUE.add(24).toNumberOrInfinity()).toEqual( + Number.POSITIVE_INFINITY + ) + expect(Integer.MAX_SAFE_VALUE.add(999).toNumberOrInfinity()).toEqual( + Number.POSITIVE_INFINITY + ) + }) it('type is exported', () => { - expect(neo4j.types.Integer).toBeDefined(); - expect(neo4j.int(1) instanceof neo4j.types.Integer).toBeTruthy(); - }); - -}); + expect(neo4j.types.Integer).toBeDefined() + expect(neo4j.int(1) instanceof neo4j.types.Integer).toBeTruthy() + }) +}) diff --git a/test/v1/record.test.js b/test/v1/record.test.js index 0eeac55df..32b1216c4 100644 --- a/test/v1/record.test.js +++ b/test/v1/record.test.js @@ -17,92 +17,100 @@ * limitations under the License. */ -import Record from '../../src/v1/record'; -import {Neo4jError} from '../../src/v1/error'; +import Record from '../../src/v1/record' +import { Neo4jError } from '../../src/v1/error' describe('Record', () => { - it('should allow getting fields by name', () => { // Given - const record = new Record(['name'], ['Bob']); + const record = new Record(['name'], ['Bob']) // When & Then - expect(record.get("name")).toEqual("Bob"); - }); + expect(record.get('name')).toEqual('Bob') + }) it('should allow checking if fields exist', () => { // Given - const record = new Record(['name'], ['Bob']); + const record = new Record(['name'], ['Bob']) // When & Then - expect(record.has("name")).toEqual(true); - expect(record.has("invalid key")).toEqual(false); - expect(record.has(0)).toEqual(true); - expect(record.has(1)).toEqual(false); - }); + expect(record.has('name')).toEqual(true) + expect(record.has('invalid key')).toEqual(false) + expect(record.has(0)).toEqual(true) + expect(record.has(1)).toEqual(false) + }) it('should transform Record into Object', () => { // Given - const record = new Record(['name', 'age', 'nested'], ['Bob', 20.5, {test: true}]); + const record = new Record( + ['name', 'age', 'nested'], + ['Bob', 20.5, { test: true }] + ) // When - const obj = record.toObject(); + const obj = record.toObject() // Then - expect(obj.name).toEqual("Bob"); - expect(obj.age).toEqual(20.5); - expect(obj.nested.test).toEqual(true); - }); + expect(obj.name).toEqual('Bob') + expect(obj.age).toEqual(20.5) + expect(obj.nested.test).toEqual(true) + }) it('should give helpful error on no such key', () => { // Given - const record = new Record(['name'], ['Bob']); + const record = new Record(['name'], ['Bob']) // When & Then expect(() => { - record.get('age'); - }).toThrow(new Neo4jError( - "This record has no field with key 'age', available key are: [name].")); - }); + record.get('age') + }).toThrow( + new Neo4jError( + "This record has no field with key 'age', available key are: [name]." + ) + ) + }) it('should allow getting fields by index', () => { // Given - const record = new Record(['name'], ['Bob']); + const record = new Record(['name'], ['Bob']) // When & Then - expect(record.get(0)).toEqual("Bob"); - }); + expect(record.get(0)).toEqual('Bob') + }) it('should give helpful error on no such index', () => { // Given - const record = new Record(['name'], ['Bob']); + const record = new Record(['name'], ['Bob']) // When & Then expect(() => { - record.get(1); - }).toThrow(new Neo4jError( - "This record has no field with index '1'. Remember that indexes start at `0`, " + - "and make sure your statement returns records in the shape you meant it to.")); - }); + record.get(1) + }).toThrow( + new Neo4jError( + "This record has no field with index '1'. Remember that indexes start at `0`, " + + 'and make sure your statement returns records in the shape you meant it to.' + ) + ) + }) it('should have length', () => { // When & Then - expect( new Record( [], []).length ).toBe(0); - expect( new Record( ["name"], ["Bob"]).length ).toBe(1); - expect( new Record( ["name", "age"], ["Bob", 45]).length ).toBe(2); - }); + expect(new Record([], []).length).toBe(0) + expect(new Record(['name'], ['Bob']).length).toBe(1) + expect(new Record(['name', 'age'], ['Bob', 45]).length).toBe(2) + }) it('should allow forEach through the record', () => { // Given - const record = new Record(['name', 'age'], ['Bob', 45]); - const result = []; + const record = new Record(['name', 'age'], ['Bob', 45]) + const result = [] // When record.forEach((value, key, record) => { - result.push( [value, key, record] ); - }); + result.push([value, key, record]) + }) // Then - expect(result).toEqual([["Bob", "name", record], [45, "age", record]]); - }); -}); + expect(result).toEqual([['Bob', 'name', record], [45, 'age', record]]) + }) +}) diff --git a/test/v1/result.test.js b/test/v1/result.test.js index c8e71dc57..d2f4044c1 100644 --- a/test/v1/result.test.js +++ b/test/v1/result.test.js @@ -17,121 +17,122 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import utils from '../internal/test-utils'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import utils from '../internal/test-utils' describe('result stream', () => { - - let driver, session; + let driver, session beforeEach(done => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - session = driver.session(); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + session = driver.session() - session.run("MATCH (n) DETACH DELETE n").then(done); - }); + session.run('MATCH (n) DETACH DELETE n').then(done) + }) afterEach(() => { - driver.close(); - }); + driver.close() + }) it('should allow chaining `then`, returning a new thing in each', done => { // When & Then - session.run( "RETURN 1") + session + .run('RETURN 1') .then(() => 'first') .then(arg => { - expect(arg).toBe( "first" ); - return "second"; + expect(arg).toBe('first') + return 'second' }) .then(arg => { - expect(arg).toBe( "second" ); + expect(arg).toBe('second') }) - .then(done); - }); + .then(done) + }) it('should allow catching exception thrown in `then`', done => { // When & Then - session.run( "RETURN 1") + session + .run('RETURN 1') .then(() => { - throw new Error("Away with you!"); + throw new Error('Away with you!') }) .catch(err => { - expect(err.message).toBe( "Away with you!" ); + expect(err.message).toBe('Away with you!') done() - }); - }); + }) + }) it('should handle missing onCompleted', done => { session.run('RETURN 1').subscribe({ onNext: record => { - expect(record.get(0).toInt()).toEqual(1); - done(); + expect(record.get(0).toInt()).toEqual(1) + done() }, onError: error => { - console.log(error); + console.log(error) } - }); - }); + }) + }) it('should have a stack trace that contains code outside the driver calls [node]', done => { if (utils.isClient()) { - done(); - return; + done() + return } // Given - const fn_a = cb => fn_b(cb); - const fn_b = cb => fn_c(cb); - const fn_c = cb => session.run('RETURN 1/0 AS x').catch(cb); + const fnA = cb => fnB(cb) + const fnB = cb => fnC(cb) + const fnC = cb => session.run('RETURN 1/0 AS x').catch(cb) // When - fn_a(err => { - const stack = err.stack; + fnA(err => { + const stack = err.stack // Then - const contains_fn_a = /fn_a \(.*?\/result.test.js:\d+:\d+\)/.test(stack); - const contains_fn_b = /fn_b \(.*?\/result.test.js:\d+:\d+\)/.test(stack); - const contains_fn_c = /fn_c \(.*?\/result.test.js:\d+:\d+\)/.test(stack); + const containsFnA = /fnA \(.*?\/result.test.js:\d+:\d+\)/.test(stack) + const containsFnB = /fnB \(.*?\/result.test.js:\d+:\d+\)/.test(stack) + const containsFnC = /fnC \(.*?\/result.test.js:\d+:\d+\)/.test(stack) - expect(contains_fn_a).toBeTruthy(); - expect(contains_fn_b).toBeTruthy(); - expect(contains_fn_c).toBeTruthy(); + expect(containsFnA).toBeTruthy() + expect(containsFnB).toBeTruthy() + expect(containsFnC).toBeTruthy() - done(); - }); - }); + done() + }) + }) it('should have a stack trace that contains code outside the driver calls [browser]', done => { if (utils.isServer()) { - done(); - return; + done() + return } if (!new Error('').stack) { - done(); - return; + done() + return } // Given - const fn_a = cb => fn_b(cb); - const fn_b = cb => fn_c(cb); - const fn_c = cb => session.run('RETURN 1/0 AS x').catch(cb); + const fnA = cb => fnB(cb) + const fnB = cb => fnC(cb) + const fnC = cb => session.run('RETURN 1/0 AS x').catch(cb) // When - fn_a(err => { - const stack = err.stack; + fnA(err => { + const stack = err.stack // Then - const contains_fn_a = /fn_a/.test(stack); - const contains_fn_b = /fn_b/.test(stack); - const contains_fn_c = /fn_c/.test(stack); - - expect(contains_fn_a).toBeTruthy(); - expect(contains_fn_b).toBeTruthy(); - expect(contains_fn_c).toBeTruthy(); - - done(); - }); - }); -}); + const containsFnA = /fnA/.test(stack) + const containsFnB = /fnB/.test(stack) + const containsFnC = /fnC/.test(stack) + + expect(containsFnA).toBeTruthy() + expect(containsFnB).toBeTruthy() + expect(containsFnC).toBeTruthy() + + done() + }) + }) +}) diff --git a/test/v1/routing-driver.test.js b/test/v1/routing-driver.test.js index 6aaa4ae55..6358fd495 100644 --- a/test/v1/routing-driver.test.js +++ b/test/v1/routing-driver.test.js @@ -17,41 +17,51 @@ * limitations under the License. */ -import RoundRobinLoadBalancingStrategy from '../../src/v1/internal/round-robin-load-balancing-strategy'; -import LeastConnectedLoadBalancingStrategy from '../../src/v1/internal/least-connected-load-balancing-strategy'; -import RoutingDriver from '../../src/v1/routing-driver'; -import Pool from '../../src/v1/internal/pool'; -import neo4j from '../../src/v1'; +import RoundRobinLoadBalancingStrategy from '../../src/v1/internal/round-robin-load-balancing-strategy' +import LeastConnectedLoadBalancingStrategy from '../../src/v1/internal/least-connected-load-balancing-strategy' +import RoutingDriver from '../../src/v1/routing-driver' +import Pool from '../../src/v1/internal/pool' +import neo4j from '../../src/v1' describe('RoutingDriver', () => { - it('should create least connected when nothing configured', () => { - const strategy = createStrategy({}); - expect(strategy instanceof LeastConnectedLoadBalancingStrategy).toBeTruthy(); - }); + const strategy = createStrategy({}) + expect(strategy instanceof LeastConnectedLoadBalancingStrategy).toBeTruthy() + }) it('should create least connected when it is configured', () => { - const strategy = createStrategy({loadBalancingStrategy: 'least_connected'}); - expect(strategy instanceof LeastConnectedLoadBalancingStrategy).toBeTruthy(); - }); + const strategy = createStrategy({ + loadBalancingStrategy: 'least_connected' + }) + expect(strategy instanceof LeastConnectedLoadBalancingStrategy).toBeTruthy() + }) it('should create round robin when it is configured', () => { - const strategy = createStrategy({loadBalancingStrategy: 'round_robin'}); - expect(strategy instanceof RoundRobinLoadBalancingStrategy).toBeTruthy(); - }); + const strategy = createStrategy({ loadBalancingStrategy: 'round_robin' }) + expect(strategy instanceof RoundRobinLoadBalancingStrategy).toBeTruthy() + }) it('should fail when unknown strategy is configured', () => { - expect(() => createStrategy({loadBalancingStrategy: 'wrong'})).toThrow(); - }); + expect(() => createStrategy({ loadBalancingStrategy: 'wrong' })).toThrow() + }) it('should fail when configured resolver is of illegal type', () => { - expect(() => neo4j.driver('bolt+routing://localhost', {}, {resolver: 'string instead of a function'})).toThrowError(TypeError); - expect(() => neo4j.driver('bolt+routing://localhost', {}, {resolver: []})).toThrowError(TypeError); - expect(() => neo4j.driver('bolt+routing://localhost', {}, {resolver: {}})).toThrowError(TypeError); - }); - -}); + expect(() => + neo4j.driver( + 'bolt+routing://localhost', + {}, + { resolver: 'string instead of a function' } + ) + ).toThrowError(TypeError) + expect(() => + neo4j.driver('bolt+routing://localhost', {}, { resolver: [] }) + ).toThrowError(TypeError) + expect(() => + neo4j.driver('bolt+routing://localhost', {}, { resolver: {} }) + ).toThrowError(TypeError) + }) +}) -function createStrategy(config) { - return RoutingDriver._createLoadBalancingStrategy(config, new Pool()); +function createStrategy (config) { + return RoutingDriver._createLoadBalancingStrategy(config, new Pool()) } diff --git a/test/v1/session.test.js b/test/v1/session.test.js index 0706a5936..3d370b032 100644 --- a/test/v1/session.test.js +++ b/test/v1/session.test.js @@ -17,1211 +17,1309 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import {statementType} from '../../src/v1/result-summary'; -import Session from '../../src/v1/session'; -import {READ} from '../../src/v1/driver'; -import {SingleConnectionProvider} from '../../src/v1/internal/connection-providers'; -import FakeConnection from '../internal/fake-connection'; -import sharedNeo4j from '../internal/shared-neo4j'; -import _ from 'lodash'; -import {ServerVersion, VERSION_3_1_0} from '../../src/v1/internal/server-version'; -import {isString} from '../../src/v1/internal/util'; -import testUtils from '../internal/test-utils'; -import {newError, PROTOCOL_ERROR, SESSION_EXPIRED} from '../../src/v1/error'; -import ServerAddress from '../../src/v1/internal/server-address'; +import neo4j from '../../src/v1' +import { statementType } from '../../src/v1/result-summary' +import Session from '../../src/v1/session' +import { READ } from '../../src/v1/driver' +import { SingleConnectionProvider } from '../../src/v1/internal/connection-providers' +import FakeConnection from '../internal/fake-connection' +import sharedNeo4j from '../internal/shared-neo4j' +import _ from 'lodash' +import { ServerVersion } from '../../src/v1/internal/server-version' +import { isString } from '../../src/v1/internal/util' +import testUtils from '../internal/test-utils' +import { newError, PROTOCOL_ERROR, SESSION_EXPIRED } from '../../src/v1/error' +import ServerAddress from '../../src/v1/internal/server-address' describe('session', () => { - - let driver; - let session; - let serverVersion; - let originalTimeout; + let driver + let session + // eslint-disable-next-line no-unused-vars + let serverVersion + let originalTimeout beforeEach(done => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - session = driver.session(); - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000; + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + session = driver.session() + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000 session.run('MATCH (n) DETACH DELETE n').then(result => { - serverVersion = ServerVersion.fromString(result.summary.server.version); - done(); - }); - }); + serverVersion = ServerVersion.fromString(result.summary.server.version) + done() + }) + }) afterEach(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - driver.close(); - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + driver.close() + }) it('close should invoke callback ', done => { - const connection = new FakeConnection(); - const session = newSessionWithConnection(connection); + const connection = new FakeConnection() + const session = newSessionWithConnection(connection) - session.close(done); - }); + session.close(done) + }) it('close should invoke callback even when already closed ', done => { - const connection = new FakeConnection(); - const session = newSessionWithConnection(connection); + const connection = new FakeConnection() + const session = newSessionWithConnection(connection) session.close(() => { session.close(() => { session.close(() => { - done(); - }); - }); - }); - }); + done() + }) + }) + }) + }) it('close should be idempotent ', done => { - const connection = new FakeConnection(); - const session = newSessionWithConnection(connection); + const connection = new FakeConnection() + const session = newSessionWithConnection(connection) session.close(() => { - expect(connection.isReleasedOnce()).toBeTruthy(); + expect(connection.isReleasedOnce()).toBeTruthy() session.close(() => { - expect(connection.isReleasedOnce()).toBeTruthy(); + expect(connection.isReleasedOnce()).toBeTruthy() session.close(() => { - expect(connection.isReleasedOnce()).toBeTruthy(); - done(); - }); - }); - }); - }); + expect(connection.isReleasedOnce()).toBeTruthy() + done() + }) + }) + }) + }) it('should close transaction executor', done => { - const session = newSessionWithConnection(new FakeConnection()); + const session = newSessionWithConnection(new FakeConnection()) - let closeCalledTimes = 0; - const transactionExecutor = session._transactionExecutor; - const originalClose = transactionExecutor.close; + let closeCalledTimes = 0 + const transactionExecutor = session._transactionExecutor + const originalClose = transactionExecutor.close transactionExecutor.close = () => { - closeCalledTimes++; - originalClose.call(transactionExecutor); - }; + closeCalledTimes++ + originalClose.call(transactionExecutor) + } session.close(() => { - expect(closeCalledTimes).toEqual(1); - done(); - }); - }); + expect(closeCalledTimes).toEqual(1) + done() + }) + }) it('should be possible to close driver after closing session with failed tx ', done => { - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const session = driver.session(); - const tx = session.beginTransaction(); + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const session = driver.session() + const tx = session.beginTransaction() tx.run('INVALID QUERY').catch(() => { tx.rollback().then(() => { session.close(() => { - driver.close(); - done(); - }); - }); - }); - }); + driver.close() + done() + }) + }) + }) + }) it('should expose basic run/subscribe ', done => { // Given // When & Then - const records = []; - session.run("RETURN 1.0 AS a").subscribe({ + const records = [] + session.run('RETURN 1.0 AS a').subscribe({ onNext: record => { - records.push(record); + records.push(record) }, onCompleted: () => { - expect(records.length).toBe(1); - expect(records[0].get('a')).toBe(1); - done(); + expect(records.length).toBe(1) + expect(records[0].get('a')).toBe(1) + done() } - }); - }); + }) + }) it('should keep context in subscribe methods ', done => { // Given - function MyObserver() { - this.local = 'hello'; - const privateLocal = 'hello'; + function MyObserver () { + this.local = 'hello' + const privateLocal = 'hello' this.onNext = function () { - expect(privateLocal).toBe('hello'); - expect(this.local).toBe('hello'); - }; + expect(privateLocal).toBe('hello') + expect(this.local).toBe('hello') + } this.onCompleted = function () { - expect(privateLocal).toBe('hello'); - expect(this.local).toBe('hello'); - done(); - }; + expect(privateLocal).toBe('hello') + expect(this.local).toBe('hello') + done() + } } // When & Then - session.run('RETURN 1.0 AS a').subscribe(new MyObserver()); - }); + session.run('RETURN 1.0 AS a').subscribe(new MyObserver()) + }) it('should call observers onError on error ', done => { - // When & Then session.run('RETURN 1 AS').subscribe({ onError: error => { - expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError'); - done(); + expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError') + done() } - }); - }); + }) + }) it('should accept a statement object ', done => { // Given - const statement = {text: 'RETURN 1 = {param} AS a', parameters: {param: 1}}; + const statement = { + text: 'RETURN 1 = {param} AS a', + parameters: { param: 1 } + } // When & Then - const records = []; + const records = [] session.run(statement).subscribe({ onNext: record => { - records.push(record); + records.push(record) }, onCompleted: () => { - expect(records.length).toBe(1); - expect(records[0].get('a')).toBe(true); - done(); + expect(records.length).toBe(1) + expect(records[0].get('a')).toBe(true) + done() } - }); - }); + }) + }) it('should expose run/then/then/then ', done => { // When & Then - session.run("RETURN 1.0 AS a") - .then( - result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('a')).toBe(1); - return result - } - ).then( - result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('a')).toBe(1); - } - ).then(done); - }); + session + .run('RETURN 1.0 AS a') + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('a')).toBe(1) + return result + }) + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('a')).toBe(1) + }) + .then(done) + }) it('should expose basic run/catch ', done => { // When & Then - session.run('RETURN 1 AS').catch( - error => { - expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError'); - done(); - } - ) - }); + session.run('RETURN 1 AS').catch(error => { + expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError') + done() + }) + }) it('should expose summarize method for basic metadata ', done => { // Given - const statement = 'CREATE (n:Label {prop:{prop}}) RETURN n'; - const params = {prop: 'string'}; + const statement = 'CREATE (n:Label {prop:{prop}}) RETURN n' + const params = { prop: 'string' } // When & Then - session.run(statement, params) - .then(result => { - const sum = result.summary; - expect(sum.statement.text).toBe(statement); - expect(sum.statement.parameters).toBe(params); - expect(sum.counters.containsUpdates()).toBe(true); - expect(sum.counters.nodesCreated()).toBe(1); - expect(sum.statementType).toBe(statementType.READ_WRITE); - done(); - }); - }); + session.run(statement, params).then(result => { + const sum = result.summary + expect(sum.statement.text).toBe(statement) + expect(sum.statement.parameters).toBe(params) + expect(sum.counters.containsUpdates()).toBe(true) + expect(sum.counters.nodesCreated()).toBe(1) + expect(sum.statementType).toBe(statementType.READ_WRITE) + done() + }) + }) it('should expose server info on successful query', done => { // Given - const statement = 'RETURN 1'; + const statement = 'RETURN 1' // When & Then - session.run(statement) - .then(result => { - const sum = result.summary; - expect(sum.server).toBeDefined(); - expect(sum.server.address).toEqual('localhost:7687'); - expect(sum.server.version).toBeDefined(); - done(); - }); - }); + session.run(statement).then(result => { + const sum = result.summary + expect(sum.server).toBeDefined() + expect(sum.server.address).toEqual('localhost:7687') + expect(sum.server.version).toBeDefined() + done() + }) + }) it('should expose execution time information', done => { // Given - const statement = 'UNWIND range(1,10000) AS n RETURN n AS number'; + const statement = 'UNWIND range(1,10000) AS n RETURN n AS number' // When & Then - session.run(statement) - .then(result => { - const sum = result.summary; - expect(sum.resultAvailableAfter.toInt()).not.toBeLessThan(0); - expect(sum.resultConsumedAfter.toInt()).not.toBeLessThan(0); - done(); - }); - }); + session.run(statement).then(result => { + const sum = result.summary + expect(sum.resultAvailableAfter.toInt()).not.toBeLessThan(0) + expect(sum.resultConsumedAfter.toInt()).not.toBeLessThan(0) + done() + }) + }) it('should expose empty parameter map on call with no parameters', done => { // Given - const statement = 'CREATE (n:Label {prop:\'string\'}) RETURN n'; + const statement = "CREATE (n:Label {prop:'string'}) RETURN n" // When & Then - session.run(statement) - .then(result => { - const sum = result.summary; - expect(sum.statement.parameters).toEqual({}); - done(); - }); - }); + session.run(statement).then(result => { + const sum = result.summary + expect(sum.statement.parameters).toEqual({}) + done() + }) + }) it('should expose plan ', done => { // Given - const statement = 'EXPLAIN CREATE (n:Label {prop:{prop}}) RETURN n'; - const params = {prop: 'string'}; + const statement = 'EXPLAIN CREATE (n:Label {prop:{prop}}) RETURN n' + const params = { prop: 'string' } // When & Then - session - .run(statement, params) - .then(result => { - const sum = result.summary; - expect(sum.hasPlan()).toBe(true); - expect(sum.hasProfile()).toBe(false); - expect(sum.plan.operatorType).toBeDefined(); - expect(isString(sum.plan.arguments.runtime)).toBeTruthy(); - expect(sum.plan.identifiers[0]).toBe('n'); - expect(sum.plan.children[0].operatorType).toBeDefined(); - done(); - }); - }); + session.run(statement, params).then(result => { + const sum = result.summary + expect(sum.hasPlan()).toBe(true) + expect(sum.hasProfile()).toBe(false) + expect(sum.plan.operatorType).toBeDefined() + expect(isString(sum.plan.arguments.runtime)).toBeTruthy() + expect(sum.plan.identifiers[0]).toBe('n') + expect(sum.plan.children[0].operatorType).toBeDefined() + done() + }) + }) it('should expose profile ', done => { // Given - const statement = 'PROFILE MATCH (n:Label {prop:{prop}}) RETURN n'; - const params = {prop: 'string'}; + const statement = 'PROFILE MATCH (n:Label {prop:{prop}}) RETURN n' + const params = { prop: 'string' } // When & Then - session - .run(statement, params) - .then(result => { - const sum = result.summary; - expect(sum.hasPlan()).toBe(true); //When there's a profile, there's a plan - expect(sum.hasProfile()).toBe(true); - expect(sum.profile.operatorType).toBeDefined(); - expect(isString(sum.profile.arguments.runtime)).toBeTruthy(); - expect(sum.profile.identifiers[0]).toBe('n'); - expect(sum.profile.children[0].operatorType).toBeDefined(); - expect(sum.profile.rows).toBe(0); - //expect(sum.profile.dbHits).toBeGreaterThan(0); - done(); - }); - }); + session.run(statement, params).then(result => { + const sum = result.summary + expect(sum.hasPlan()).toBe(true) // When there's a profile, there's a plan + expect(sum.hasProfile()).toBe(true) + expect(sum.profile.operatorType).toBeDefined() + expect(isString(sum.profile.arguments.runtime)).toBeTruthy() + expect(sum.profile.identifiers[0]).toBe('n') + expect(sum.profile.children[0].operatorType).toBeDefined() + expect(sum.profile.rows).toBe(0) + // expect(sum.profile.dbHits).toBeGreaterThan(0); + done() + }) + }) it('should expose cypher notifications ', done => { // Given - const statement = 'EXPLAIN MATCH (n), (m) RETURN n, m'; + const statement = 'EXPLAIN MATCH (n), (m) RETURN n, m' // When & Then - session - .run(statement) - .then(result => { - const sum = result.summary; - expect(sum.notifications.length).toBeGreaterThan(0); - expect(sum.notifications[0].code).toBe("Neo.ClientNotification.Statement.CartesianProductWarning"); - expect(sum.notifications[0].title).toBe("This query builds a cartesian product between disconnected patterns."); - expect(sum.notifications[0].position.column).toBeGreaterThan(0); - done(); - }); - }); + session.run(statement).then(result => { + const sum = result.summary + expect(sum.notifications.length).toBeGreaterThan(0) + expect(sum.notifications[0].code).toBe( + 'Neo.ClientNotification.Statement.CartesianProductWarning' + ) + expect(sum.notifications[0].title).toBe( + 'This query builds a cartesian product between disconnected patterns.' + ) + expect(sum.notifications[0].position.column).toBeGreaterThan(0) + done() + }) + }) it('should fail when using the session when having an open transaction', done => { - // When - session.beginTransaction(); + session.beginTransaction() - //Then - session.run("RETURN 42") - .catch(error => { - expect(error.message).toBe("Statements cannot be run directly on a " - + "session with an open transaction; either run from within the " - + "transaction or use a different session."); - done(); - }) - }); + // Then + session.run('RETURN 42').catch(error => { + expect(error.message).toBe( + 'Statements cannot be run directly on a ' + + 'session with an open transaction; either run from within the ' + + 'transaction or use a different session.' + ) + done() + }) + }) it('should fail when opening multiple transactions', () => { - // When - session.beginTransaction(); + session.beginTransaction() // Then - expect(()=>session.beginTransaction()).toThrowError( - /You cannot begin a transaction on a session with an open transaction/); - }); + expect(() => session.beginTransaction()).toThrowError( + /You cannot begin a transaction on a session with an open transaction/ + ) + }) it('should return lots of data', done => { - session.run("UNWIND range(1,10000) AS x CREATE (:ATTRACTION {prop: 'prop'})") + session + .run("UNWIND range(1,10000) AS x CREATE (:ATTRACTION {prop: 'prop'})") .then(() => { - session.run("MATCH (n) RETURN n") - .subscribe( - { - onNext: record => { - const node = record.get('n'); - expect(node.labels[0]).toEqual("ATTRACTION"); - expect(node.properties.prop).toEqual("prop"); - }, - onCompleted: () => { - session.close(); - done() - }, - onError: error => { - console.log(error); - } - } - ) - - }); - }); + session.run('MATCH (n) RETURN n').subscribe({ + onNext: record => { + const node = record.get('n') + expect(node.labels[0]).toEqual('ATTRACTION') + expect(node.properties.prop).toEqual('prop') + }, + onCompleted: () => { + session.close() + done() + }, + onError: error => { + console.log(error) + } + }) + }) + }) it('should be able to close a long running query ', done => { - //given a long running query - session.run('unwind range(1,1000000) as x create (n {prop:x}) delete n').catch(error => { - // long running query should fail - expect(error).toBeDefined(); - - // and it should be possible to start another session and run a query - const anotherSession = driver.session(); - anotherSession.run('RETURN 1.0 as a').then(result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('a')).toBe(1); - done(); - }).catch(error => { - console.log('Query failed after a long running query was terminated', error); - }); - }); + // given a long running query + session + .run('unwind range(1,1000000) as x create (n {prop:x}) delete n') + .catch(error => { + // long running query should fail + expect(error).toBeDefined() + + // and it should be possible to start another session and run a query + const anotherSession = driver.session() + anotherSession + .run('RETURN 1.0 as a') + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('a')).toBe(1) + done() + }) + .catch(error => { + console.log( + 'Query failed after a long running query was terminated', + error + ) + }) + }) // wait some time than close the session with a long running query setTimeout(() => { - session.close(); - }, 1000); - }); + session.close() + }, 1000) + }) it('should fail nicely on unpackable values ', done => { // Given const unpackable = () => { - throw Error(); - }; + throw Error() + } - const statement = 'RETURN {param}'; - const params = {param: unpackable}; + const statement = 'RETURN {param}' + const params = { param: unpackable } // When & Then - session - .run(statement, params) - .catch(ignore => { - done(); - }) - }); + session.run(statement, params).catch(ignore => { + done() + }) + }) it('should fail nicely for illegal statement', () => { - expect(() => session.run()).toThrowError(TypeError); - expect(() => session.run(null)).toThrowError(TypeError); - expect(() => session.run({})).toThrowError(TypeError); - expect(() => session.run(42)).toThrowError(TypeError); - expect(() => session.run([])).toThrowError(TypeError); - expect(() => session.run('')).toThrowError(TypeError); - expect(() => session.run(['CREATE ()'])).toThrowError(TypeError); - - expect(() => session.run({statement: 'CREATE ()'})).toThrowError(TypeError); - expect(() => session.run({cypher: 'CREATE ()'})).toThrowError(TypeError); - }); + expect(() => session.run()).toThrowError(TypeError) + expect(() => session.run(null)).toThrowError(TypeError) + expect(() => session.run({})).toThrowError(TypeError) + expect(() => session.run(42)).toThrowError(TypeError) + expect(() => session.run([])).toThrowError(TypeError) + expect(() => session.run('')).toThrowError(TypeError) + expect(() => session.run(['CREATE ()'])).toThrowError(TypeError) + + expect(() => session.run({ statement: 'CREATE ()' })).toThrowError( + TypeError + ) + expect(() => session.run({ cypher: 'CREATE ()' })).toThrowError(TypeError) + }) it('should fail nicely for illegal bookmark', () => { - expect(() => session.beginTransaction(42)).toThrowError(TypeError); - expect(() => session.beginTransaction(42)).toThrowError(TypeError); - expect(() => session.beginTransaction([42.0, 42.0])).toThrowError(TypeError); - expect(() => session.beginTransaction(() => ['bookmark:1', 'bookmark:2', 'bookmark:3'])).toThrowError(TypeError); - }); + expect(() => session.beginTransaction(42)).toThrowError(TypeError) + expect(() => session.beginTransaction(42)).toThrowError(TypeError) + expect(() => session.beginTransaction([42.0, 42.0])).toThrowError(TypeError) + expect(() => + session.beginTransaction(() => ['bookmark:1', 'bookmark:2', 'bookmark:3']) + ).toThrowError(TypeError) + }) it('should allow creation of a ' + neo4j.session.READ + ' session', done => { - const readSession = driver.session(neo4j.session.READ); + const readSession = driver.session(neo4j.session.READ) readSession.run('RETURN 1').then(() => { - readSession.close(); - done(); - }); - }); + readSession.close() + done() + }) + }) it('should allow creation of a ' + neo4j.session.WRITE + ' session', done => { - const writeSession = driver.session(neo4j.session.WRITE); + const writeSession = driver.session(neo4j.session.WRITE) writeSession.run('CREATE ()').then(() => { - writeSession.close(); - done(); - }); - }); + writeSession.close() + done() + }) + }) it('should fail for illegal session mode', () => { - expect(() => driver.session('ILLEGAL_MODE')).toThrow(); - }); + expect(() => driver.session('ILLEGAL_MODE')).toThrow() + }) it('should release connection to the pool after run', done => { withQueryInTmpSession(driver, () => { - const idleConnectionsBefore = idleConnectionCount(driver); + const idleConnectionsBefore = idleConnectionCount(driver) session.run('RETURN 1').then(() => { - const idleConnectionsAfter = idleConnectionCount(driver); - expect(idleConnectionsBefore).toEqual(idleConnectionsAfter); - done(); - }); - }); - }); + const idleConnectionsAfter = idleConnectionCount(driver) + expect(idleConnectionsBefore).toEqual(idleConnectionsAfter) + done() + }) + }) + }) it('should release connection to the pool after run failure', done => { withQueryInTmpSession(driver, () => { - const idleConnectionsBefore = idleConnectionCount(driver); + const idleConnectionsBefore = idleConnectionCount(driver) session.run('RETURN 10 / 0').catch(() => { - const idleConnectionsAfter = idleConnectionCount(driver); - expect(idleConnectionsBefore).toEqual(idleConnectionsAfter); - done(); - }); - }); - }); + const idleConnectionsAfter = idleConnectionCount(driver) + expect(idleConnectionsBefore).toEqual(idleConnectionsAfter) + done() + }) + }) + }) it('should release connection to the pool when result is consumed', done => { withQueryInTmpSession(driver, () => { - const idleConnectionsBefore = idleConnectionCount(driver); + const idleConnectionsBefore = idleConnectionCount(driver) session.run('UNWIND range(0, 10) AS x RETURN x + 1').subscribe({ onNext: () => { // one less idle connection, one connection is used for the current query - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1) }, onError: error => { - console.log(error); + console.log(error) }, onCompleted: () => { - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore); - done(); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore) + done() } - }); - }); - }); + }) + }) + }) it('should release connection to the pool when result fails', done => { withQueryInTmpSession(driver, () => { - const idleConnectionsBefore = idleConnectionCount(driver); + const idleConnectionsBefore = idleConnectionCount(driver) session.run('UNWIND range(10, 0, -1) AS x RETURN 10 / x').subscribe({ onNext: () => { // one less idle connection, one connection is used for the current query - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1) }, onError: ignoredError => { - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore); - done(); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore) + done() }, - onCompleted: () => { - } - }); - }); - }); + onCompleted: () => {} + }) + }) + }) it('should release connection to the pool when transaction commits', done => { withQueryInTmpSession(driver, () => { - const idleConnectionsBefore = idleConnectionCount(driver); + const idleConnectionsBefore = idleConnectionCount(driver) - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('UNWIND range(0, 10) AS x RETURN x + 1').subscribe({ onNext: () => { // one less idle connection, one connection is used for the current transaction - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1) }, onError: error => { - console.log(error); + console.log(error) }, onCompleted: () => { // one less idle connection, one connection is used for the current transaction - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1) tx.commit().then(() => { - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore); - done(); - }); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore) + done() + }) } - }); - }); - }); + }) + }) + }) it('should release connection to the pool when transaction rolls back', done => { withQueryInTmpSession(driver, () => { - const idleConnectionsBefore = idleConnectionCount(driver); + const idleConnectionsBefore = idleConnectionCount(driver) - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('UNWIND range(0, 10) AS x RETURN x + 1').subscribe({ onNext: () => { // one less idle connection, one connection is used for the current transaction - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1) }, onError: error => { - console.log(error); + console.log(error) }, onCompleted: () => { // one less idle connection, one connection is used for the current transaction - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore - 1) tx.rollback().then(() => { - expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore); - done(); - }); + expect(idleConnectionCount(driver)).toBe(idleConnectionsBefore) + done() + }) } - }); - }); - }); + }) + }) + }) it('should update last bookmark after every read tx commit', done => { - // new session without initial bookmark - session = driver.session(); - expect(session.lastBookmark()).toBeNull(); + session = driver.session() + expect(session.lastBookmark()).toBeNull() - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('RETURN 42 as answer').then(result => { - const records = result.records; - expect(records.length).toEqual(1); - expect(records[0].get('answer').toNumber()).toEqual(42); + const records = result.records + expect(records.length).toEqual(1) + expect(records[0].get('answer').toNumber()).toEqual(42) tx.commit().then(() => { - verifyBookmark(session.lastBookmark()); - done(); - }); - }); - }); + verifyBookmark(session.lastBookmark()) + done() + }) + }) + }) it('should update last bookmark after every write tx commit', done => { + const bookmarkBefore = session.lastBookmark() - const bookmarkBefore = session.lastBookmark(); - - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('CREATE ()').then(() => { tx.commit().then(() => { - const bookmarkAfter = session.lastBookmark(); - expect(bookmarkAfter).toBeDefined(); - expect(bookmarkAfter).not.toBeNull(); - expect(bookmarkAfter).not.toEqual(bookmarkBefore); + const bookmarkAfter = session.lastBookmark() + expect(bookmarkAfter).toBeDefined() + expect(bookmarkAfter).not.toBeNull() + expect(bookmarkAfter).not.toEqual(bookmarkBefore) - done(); - }); - }); - }); + done() + }) + }) + }) it('should not lose last bookmark after run', done => { - - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('CREATE ()').then(() => { tx.commit().then(() => { - const bookmarkBefore = session.lastBookmark(); - verifyBookmark(bookmarkBefore); + const bookmarkBefore = session.lastBookmark() + verifyBookmark(bookmarkBefore) session.run('CREATE ()').then(() => { - verifyBookmark(session.lastBookmark()); - done(); - }); - }); - }); - }); + verifyBookmark(session.lastBookmark()) + done() + }) + }) + }) + }) it('should commit read transaction', done => { // new session without initial bookmark - session = driver.session(); - expect(session.lastBookmark()).toBeNull(); + session = driver.session() + expect(session.lastBookmark()).toBeNull() - const resultPromise = session.readTransaction(tx => tx.run('RETURN 42 AS answer')); + const resultPromise = session.readTransaction(tx => + tx.run('RETURN 42 AS answer') + ) resultPromise.then(result => { - expect(result.records.length).toEqual(1); - expect(result.records[0].get('answer').toNumber()).toEqual(42); - verifyBookmark(session.lastBookmark()); - done(); - }); - }); + expect(result.records.length).toEqual(1) + expect(result.records[0].get('answer').toNumber()).toEqual(42) + verifyBookmark(session.lastBookmark()) + done() + }) + }) it('should commit write transaction', done => { - const bookmarkBefore = session.lastBookmark(); - const resultPromise = session.writeTransaction(tx => tx.run('CREATE (n:Node {id: 42}) RETURN n.id AS answer')); + const bookmarkBefore = session.lastBookmark() + const resultPromise = session.writeTransaction(tx => + tx.run('CREATE (n:Node {id: 42}) RETURN n.id AS answer') + ) resultPromise.then(result => { - expect(result.records.length).toEqual(1); - expect(result.records[0].get('answer').toNumber()).toEqual(42); - expect(result.summary.counters.nodesCreated()).toEqual(1); + expect(result.records.length).toEqual(1) + expect(result.records[0].get('answer').toNumber()).toEqual(42) + expect(result.summary.counters.nodesCreated()).toEqual(1) - const bookmarkAfter = session.lastBookmark(); - verifyBookmark(bookmarkAfter); - expect(bookmarkAfter).not.toEqual(bookmarkBefore); + const bookmarkAfter = session.lastBookmark() + verifyBookmark(bookmarkAfter) + expect(bookmarkAfter).not.toEqual(bookmarkBefore) countNodes('Node', 'id', 42).then(count => { - expect(count).toEqual(1); - done(); - }); - }); - }); + expect(count).toEqual(1) + done() + }) + }) + }) it('should not commit already committed read transaction', done => { const resultPromise = session.readTransaction(tx => { return new Promise((resolve, reject) => { - tx.run('RETURN 42 AS answer').then(result => { - tx.commit().then(() => { - resolve({result: result, bookmark: session.lastBookmark()}); - }).catch(error => reject(error)); - }).catch(error => reject(error)); - }); - }); + tx.run('RETURN 42 AS answer') + .then(result => { + tx.commit() + .then(() => { + resolve({ result: result, bookmark: session.lastBookmark() }) + }) + .catch(error => reject(error)) + }) + .catch(error => reject(error)) + }) + }) resultPromise.then(outcome => { - const bookmark = outcome.bookmark; - const result = outcome.result; + const bookmark = outcome.bookmark + const result = outcome.result - verifyBookmark(bookmark); - expect(session.lastBookmark()).toEqual(bookmark); // expect bookmark to not change + verifyBookmark(bookmark) + expect(session.lastBookmark()).toEqual(bookmark) // expect bookmark to not change - expect(result.records.length).toEqual(1); - expect(result.records[0].get('answer').toNumber()).toEqual(42); + expect(result.records.length).toEqual(1) + expect(result.records[0].get('answer').toNumber()).toEqual(42) - done(); - }); - }); + done() + }) + }) it('should not commit already committed write transaction', done => { const resultPromise = session.readTransaction(tx => { return new Promise((resolve, reject) => { - tx.run('CREATE (n:Node {id: 42}) RETURN n.id AS answer').then(result => { - tx.commit().then(() => { - resolve({result: result, bookmark: session.lastBookmark()}); - }).catch(error => reject(error)); - }).catch(error => reject(error)); - }); - }); + tx.run('CREATE (n:Node {id: 42}) RETURN n.id AS answer') + .then(result => { + tx.commit() + .then(() => { + resolve({ result: result, bookmark: session.lastBookmark() }) + }) + .catch(error => reject(error)) + }) + .catch(error => reject(error)) + }) + }) resultPromise.then(outcome => { - const bookmark = outcome.bookmark; - const result = outcome.result; + const bookmark = outcome.bookmark + const result = outcome.result - verifyBookmark(bookmark); - expect(session.lastBookmark()).toEqual(bookmark); // expect bookmark to not change + verifyBookmark(bookmark) + expect(session.lastBookmark()).toEqual(bookmark) // expect bookmark to not change - expect(result.records.length).toEqual(1); - expect(result.records[0].get('answer').toNumber()).toEqual(42); - expect(result.summary.counters.nodesCreated()).toEqual(1); + expect(result.records.length).toEqual(1) + expect(result.records[0].get('answer').toNumber()).toEqual(42) + expect(result.summary.counters.nodesCreated()).toEqual(1) countNodes('Node', 'id', 42).then(count => { - expect(count).toEqual(1); - done(); - }); - }); - }); + expect(count).toEqual(1) + done() + }) + }) + }) it('should not commit rolled back read transaction', done => { - - const bookmarkBefore = session.lastBookmark(); + const bookmarkBefore = session.lastBookmark() const resultPromise = session.readTransaction(tx => { return new Promise((resolve, reject) => { - tx.run('RETURN 42 AS answer').then(result => { - tx.rollback().then(() => { - resolve(result); - }).catch(error => reject(error)); - }).catch(error => reject(error)); - }); - }); + tx.run('RETURN 42 AS answer') + .then(result => { + tx.rollback() + .then(() => { + resolve(result) + }) + .catch(error => reject(error)) + }) + .catch(error => reject(error)) + }) + }) resultPromise.then(result => { - expect(result.records.length).toEqual(1); - expect(result.records[0].get('answer').toNumber()).toEqual(42); - expect(session.lastBookmark()).toBe(bookmarkBefore); // expect bookmark to not change + expect(result.records.length).toEqual(1) + expect(result.records[0].get('answer').toNumber()).toEqual(42) + expect(session.lastBookmark()).toBe(bookmarkBefore) // expect bookmark to not change - done(); - }); - }); + done() + }) + }) it('should not commit rolled back write transaction', done => { - - const bookmarkBefore = session.lastBookmark(); + const bookmarkBefore = session.lastBookmark() const resultPromise = session.readTransaction(tx => { return new Promise((resolve, reject) => { - tx.run('CREATE (n:Node {id: 42}) RETURN n.id AS answer').then(result => { - tx.rollback().then(() => { - resolve(result); - }).catch(error => reject(error)); - }).catch(error => reject(error)); - }); - }); + tx.run('CREATE (n:Node {id: 42}) RETURN n.id AS answer') + .then(result => { + tx.rollback() + .then(() => { + resolve(result) + }) + .catch(error => reject(error)) + }) + .catch(error => reject(error)) + }) + }) resultPromise.then(result => { - expect(result.records.length).toEqual(1); - expect(result.records[0].get('answer').toNumber()).toEqual(42); - expect(result.summary.counters.nodesCreated()).toEqual(1); - expect(session.lastBookmark()).toBe(bookmarkBefore); // expect bookmark to not change + expect(result.records.length).toEqual(1) + expect(result.records[0].get('answer').toNumber()).toEqual(42) + expect(result.summary.counters.nodesCreated()).toEqual(1) + expect(session.lastBookmark()).toBe(bookmarkBefore) // expect bookmark to not change countNodes('Node', 'id', 42).then(count => { - expect(count).toEqual(0); - done(); - }); - }); - }); + expect(count).toEqual(0) + done() + }) + }) + }) it('should interrupt query waiting on a lock when closed', done => { - session.run('CREATE ()').then(() => { session.close(() => { - const session1 = driver.session(); - const session2 = driver.session(); - const tx1 = session1.beginTransaction(); + const session1 = driver.session() + const session2 = driver.session() + const tx1 = session1.beginTransaction() tx1.run('MATCH (n) SET n.id = 1 RETURN 42 AS answer').then(result => { // node is now locked by tx1 - expect(result.records.length).toEqual(1); - expect(result.records[0].get(0).toNumber()).toEqual(42); + expect(result.records.length).toEqual(1) + expect(result.records[0].get(0).toNumber()).toEqual(42) // this query should get stuck waiting for the lock - session2.run('MATCH (n) SET n.id = 2 RETURN 42 AS answer').catch(error => { - expectTransactionTerminatedError(error); - tx1.commit().then(() => { - readAllNodeIds().then(ids => { - expect(ids).toEqual([1]); - done(); - }); - }); - }); + session2 + .run('MATCH (n) SET n.id = 2 RETURN 42 AS answer') + .catch(error => { + expectTransactionTerminatedError(error) + tx1.commit().then(() => { + readAllNodeIds().then(ids => { + expect(ids).toEqual([1]) + done() + }) + }) + }) setTimeout(() => { // close session after a while - session2.close(); - }, 1000); - }); - }); - }); - }); + session2.close() + }, 1000) + }) + }) + }) + }) it('should interrupt transaction waiting on a lock when closed', done => { - session.run('CREATE ()').then(() => { session.close(() => { - const session1 = driver.session(); - const session2 = driver.session(); - const tx1 = session1.beginTransaction(); - const tx2 = session2.beginTransaction(); + const session1 = driver.session() + const session2 = driver.session() + const tx1 = session1.beginTransaction() + const tx2 = session2.beginTransaction() tx1.run('MATCH (n) SET n.id = 1 RETURN 42 AS answer').then(result => { // node is now locked by tx1 - expect(result.records.length).toEqual(1); - expect(result.records[0].get(0).toNumber()).toEqual(42); + expect(result.records.length).toEqual(1) + expect(result.records[0].get(0).toNumber()).toEqual(42) // this query should get stuck waiting for the lock tx2.run('MATCH (n) SET n.id = 2 RETURN 42 AS answer').catch(error => { - expectTransactionTerminatedError(error); + expectTransactionTerminatedError(error) tx1.commit().then(() => { readAllNodeIds().then(ids => { - expect(ids).toEqual([1]); - done(); - }); - }); - }); + expect(ids).toEqual([1]) + done() + }) + }) + }) setTimeout(() => { // close session after a while - session2.close(); - }, 1000); - }); - }); - }); - }); + session2.close() + }, 1000) + }) + }) + }) + }) it('should interrupt transaction function waiting on a lock when closed', done => { - session.run('CREATE ()').then(() => { session.close(() => { - const session1 = driver.session(); - const session2 = driver.session(); - const tx1 = session1.beginTransaction(); + const session1 = driver.session() + const session2 = driver.session() + const tx1 = session1.beginTransaction() tx1.run('MATCH (n) SET n.id = 1 RETURN 42 AS answer').then(result => { // node is now locked by tx1 - expect(result.records.length).toEqual(1); - expect(result.records[0].get(0).toNumber()).toEqual(42); + expect(result.records.length).toEqual(1) + expect(result.records[0].get(0).toNumber()).toEqual(42) session2.writeTransaction(tx2 => { // this query should get stuck waiting for the lock - return tx2.run('MATCH (n) SET n.id = 2 RETURN 42 AS answer').catch(error => { - expectTransactionTerminatedError(error); - tx1.commit().then(() => { - readAllNodeIds().then(ids => { - expect(ids).toEqual([1]); - done(); - }); - }); - }); - }); + return tx2 + .run('MATCH (n) SET n.id = 2 RETURN 42 AS answer') + .catch(error => { + expectTransactionTerminatedError(error) + tx1.commit().then(() => { + readAllNodeIds().then(ids => { + expect(ids).toEqual([1]) + done() + }) + }) + }) + }) setTimeout(() => { // close session after a while - session2.close(); - }, 1000); - }); - }); - }); - }); + session2.close() + }, 1000) + }) + }) + }) + }) it('should be able to do nested queries', done => { - session.run( - 'CREATE (knight:Person:Knight {name: {name1}, castle: {castle}})' + - 'CREATE (king:Person {name: {name2}, title: {title}})', - {name1: 'Lancelot', castle: 'Camelot', name2: 'Arthur', title: 'King'}) + session + .run( + 'CREATE (knight:Person:Knight {name: {name1}, castle: {castle}})' + + 'CREATE (king:Person {name: {name2}, title: {title}})', + { name1: 'Lancelot', castle: 'Camelot', name2: 'Arthur', title: 'King' } + ) .then(() => { - session.run( - 'MATCH (knight:Person:Knight) WHERE knight.castle = {castle} RETURN id(knight) AS knight_id', - {castle: 'Camelot'}).subscribe( - { + session + .run( + 'MATCH (knight:Person:Knight) WHERE knight.castle = {castle} RETURN id(knight) AS knight_id', + { castle: 'Camelot' } + ) + .subscribe({ onNext: record => { - session - .run('MATCH (knight) WHERE id(knight) = {id} MATCH (king:Person) WHERE king.name = {king} CREATE (knight)-[:DEFENDS]->(king)', - {id: record.get('knight_id'), king: 'Arthur'}); + session.run( + 'MATCH (knight) WHERE id(knight) = {id} MATCH (king:Person) WHERE king.name = {king} CREATE (knight)-[:DEFENDS]->(king)', + { id: record.get('knight_id'), king: 'Arthur' } + ) }, onCompleted: () => { session .run('MATCH (:Knight)-[:DEFENDS]->() RETURN count(*)') .then(result => { - session.close(); - const count = result.records[0].get(0).toInt(); - expect(count).toEqual(1); - done(); - }); + session.close() + const count = result.records[0].get(0).toInt() + expect(count).toEqual(1) + done() + }) }, onError: error => { - console.log(error); + console.log(error) } - }); - }); - }); + }) + }) + }) it('should send multiple bookmarks', async () => { - const nodeCount = 17; - const bookmarks = []; + const nodeCount = 17 + const bookmarks = [] for (let i = 0; i < nodeCount; i++) { - const bookmark = await runQueryAndGetBookmark(driver); - bookmarks.push(bookmark); + const bookmark = await runQueryAndGetBookmark(driver) + bookmarks.push(bookmark) } - expect(_.uniq(bookmarks).length).toEqual(nodeCount); - bookmarks.forEach(bookmark => expect(_.isString(bookmark)).toBeTruthy()); + expect(_.uniq(bookmarks).length).toEqual(nodeCount) + bookmarks.forEach(bookmark => expect(_.isString(bookmark)).toBeTruthy()) - const session = driver.session(READ, bookmarks); + const session = driver.session(READ, bookmarks) try { - const result = await session.run('MATCH (n) RETURN count(n)'); - const count = result.records[0].get(0).toInt(); - expect(count).toEqual(nodeCount); + const result = await session.run('MATCH (n) RETURN count(n)') + const count = result.records[0].get(0).toInt() + expect(count).toEqual(nodeCount) } finally { - session.close(); + session.close() } - }); + }) it('should acquire connection for transaction', done => { - expect(numberOfAcquiredConnectionsFromPool()).toEqual(0); - - session.beginTransaction().run('RETURN 1.0').then(result => { - expect(result.records[0].get(0)).toEqual(1); - expect(numberOfAcquiredConnectionsFromPool()).toEqual(1); - - driver.session().beginTransaction().run('RETURN 2.0').then(result => { - expect(result.records[0].get(0)).toEqual(2); - expect(numberOfAcquiredConnectionsFromPool()).toEqual(2); + expect(numberOfAcquiredConnectionsFromPool()).toEqual(0) - driver.session().beginTransaction().run('RETURN 3.0').then(result => { - expect(result.records[0].get(0)).toEqual(3); - expect(numberOfAcquiredConnectionsFromPool()).toEqual(3); - - driver.session().beginTransaction().run('RETURN 4.0').then(result => { - expect(result.records[0].get(0)).toEqual(4); - expect(numberOfAcquiredConnectionsFromPool()).toEqual(4); - - done(); - }); - }); - }); - }); - }); + session + .beginTransaction() + .run('RETURN 1.0') + .then(result => { + expect(result.records[0].get(0)).toEqual(1) + expect(numberOfAcquiredConnectionsFromPool()).toEqual(1) + + driver + .session() + .beginTransaction() + .run('RETURN 2.0') + .then(result => { + expect(result.records[0].get(0)).toEqual(2) + expect(numberOfAcquiredConnectionsFromPool()).toEqual(2) + + driver + .session() + .beginTransaction() + .run('RETURN 3.0') + .then(result => { + expect(result.records[0].get(0)).toEqual(3) + expect(numberOfAcquiredConnectionsFromPool()).toEqual(3) + + driver + .session() + .beginTransaction() + .run('RETURN 4.0') + .then(result => { + expect(result.records[0].get(0)).toEqual(4) + expect(numberOfAcquiredConnectionsFromPool()).toEqual(4) + + done() + }) + }) + }) + }) + }) it('should acquire connection for query execution', done => { session.run('RETURN 42 AS answer').subscribe({ onNext: record => { - expect(record.get('answer').toInt()).toEqual(42); - expect(numberOfAcquiredConnectionsFromPool()).toEqual(1); + expect(record.get('answer').toInt()).toEqual(42) + expect(numberOfAcquiredConnectionsFromPool()).toEqual(1) }, onCompleted: () => { session.close(() => { - done(); - }); + done() + }) }, onError: error => { - console.log(error); + console.log(error) } - }); - }); + }) + }) it('should acquire separate connections for transaction and query execution in different sessions', done => { - const otherSession = driver.session(); - expect(otherSession.beginTransaction()).toBeDefined(); + const otherSession = driver.session() + expect(otherSession.beginTransaction()).toBeDefined() session.run('RETURN 42 AS answer').subscribe({ onNext: record => { - expect(record.get('answer').toInt()).toEqual(42); - expect(numberOfAcquiredConnectionsFromPool()).toEqual(2); + expect(record.get('answer').toInt()).toEqual(42) + expect(numberOfAcquiredConnectionsFromPool()).toEqual(2) }, onCompleted: () => { otherSession.close(() => { session.close(() => { - done(); - }); - }); + done() + }) + }) }, onError: error => { - console.log(error); + console.log(error) } - }); - }); + }) + }) it('should respect connection timeout', done => { - testConnectionTimeout(false, done); - }); + testConnectionTimeout(false, done) + }) it('should respect encrypted connection timeout', done => { - testConnectionTimeout(true, done); - }); + testConnectionTimeout(true, done) + }) it('should convert iterable to array', done => { - const iterable = {}; - iterable[Symbol.iterator] = function* () { - yield '111'; - yield '222'; - yield '333'; - }; - - session.run('RETURN $array', {array: iterable}).then(result => { - const records = result.records; - expect(records.length).toEqual(1); - const received = records[0].get(0); - expect(received).toEqual(['111', '222', '333']); - done(); - }).catch(error => { - done.fail(error); - }); - }); + const iterable = {} + iterable[Symbol.iterator] = function * () { + yield '111' + yield '222' + yield '333' + } + + session + .run('RETURN $array', { array: iterable }) + .then(result => { + const records = result.records + expect(records.length).toEqual(1) + const received = records[0].get(0) + expect(received).toEqual(['111', '222', '333']) + done() + }) + .catch(error => { + done.fail(error) + }) + }) it('should fail to convert illegal iterable to array', done => { - const iterable = {}; - iterable[Symbol.iterator] = function () { - }; - - session.run('RETURN $array', {array: iterable}).then(result => { - done.fail('Failre expected but query returned ' + JSON.stringify(result.records[0].get(0))); - }).catch(error => { - expect(error.message.indexOf('Cannot pack given iterable')).not.toBeLessThan(0); - done(); - }); - }); + const iterable = {} + iterable[Symbol.iterator] = function () {} + + session + .run('RETURN $array', { array: iterable }) + .then(result => { + done.fail( + 'Failre expected but query returned ' + + JSON.stringify(result.records[0].get(0)) + ) + }) + .catch(error => { + expect( + error.message.indexOf('Cannot pack given iterable') + ).not.toBeLessThan(0) + done() + }) + }) it('should fail for invalid query parameters', () => { - expect(() => session.run('RETURN $value', '42')).toThrowError(TypeError); - expect(() => session.run('RETURN $value', 42)).toThrowError(TypeError); - expect(() => session.run('RETURN $value', () => 42)).toThrowError(TypeError); - }); + expect(() => session.run('RETURN $value', '42')).toThrowError(TypeError) + expect(() => session.run('RETURN $value', 42)).toThrowError(TypeError) + expect(() => session.run('RETURN $value', () => 42)).toThrowError(TypeError) + }) it('should fail to pass node as a query parameter', done => { - testUnsupportedQueryParameter(new neo4j.types.Node(neo4j.int(1), ['Person'], {name: 'Bob'}), done); - }); + testUnsupportedQueryParameter( + new neo4j.types.Node(neo4j.int(1), ['Person'], { name: 'Bob' }), + done + ) + }) it('should fail to pass relationship as a query parameter', done => { - testUnsupportedQueryParameter(new neo4j.types.Relationship(neo4j.int(1), neo4j.int(2), neo4j.int(3), 'KNOWS', {since: 42}), done); - }); + testUnsupportedQueryParameter( + new neo4j.types.Relationship( + neo4j.int(1), + neo4j.int(2), + neo4j.int(3), + 'KNOWS', + { since: 42 } + ), + done + ) + }) it('should fail to pass path as a query parameter', done => { - const node1 = new neo4j.types.Node(neo4j.int(1), ['Person'], {name: 'Alice'}); - const node2 = new neo4j.types.Node(neo4j.int(2), ['Person'], {name: 'Bob'}); - testUnsupportedQueryParameter(new neo4j.types.Path(node1, node2, []), done); - }); + const node1 = new neo4j.types.Node(neo4j.int(1), ['Person'], { + name: 'Alice' + }) + const node2 = new neo4j.types.Node(neo4j.int(2), ['Person'], { + name: 'Bob' + }) + testUnsupportedQueryParameter(new neo4j.types.Path(node1, node2, []), done) + }) it('should retry transaction until success when function throws', done => { testTransactionRetryUntilSuccess(() => { - throw newError('Error that can be retried', SESSION_EXPIRED); - }, done); - }); + throw newError('Error that can be retried', SESSION_EXPIRED) + }, done) + }) it('should retry transaction until success when function returns rejected promise', done => { - testTransactionRetryUntilSuccess(() => Promise.reject(newError('Error that can be retried', SESSION_EXPIRED)), done); - }); + testTransactionRetryUntilSuccess( + () => + Promise.reject(newError('Error that can be retried', SESSION_EXPIRED)), + done + ) + }) it('should not retry transaction when function throws fatal error', done => { testTransactionRetryOnFatalError(() => { - throw newError('Error that is fatal', PROTOCOL_ERROR); - }, done); - }); + throw newError('Error that is fatal', PROTOCOL_ERROR) + }, done) + }) it('should not retry transaction when function returns promise rejected with fatal error', done => { - testTransactionRetryOnFatalError(() => Promise.reject(newError('Error that is fatal', 'ReallyFatalErrorCode')), done); - }); + testTransactionRetryOnFatalError( + () => + Promise.reject(newError('Error that is fatal', 'ReallyFatalErrorCode')), + done + ) + }) - function testTransactionRetryUntilSuccess(failureResponseFunction, done) { - const session = driver.session(); + function testTransactionRetryUntilSuccess (failureResponseFunction, done) { + const session = driver.session() - const failures = 3; - const usedTransactions = []; + const failures = 3 + const usedTransactions = [] const resultPromise = session.writeTransaction(tx => { - usedTransactions.push(tx); + usedTransactions.push(tx) if (usedTransactions.length < failures) { - return failureResponseFunction(); + return failureResponseFunction() } else { - return tx.run('RETURN "424242"'); + return tx.run('RETURN "424242"') } - }); + }) - resultPromise.then(result => { - expect(result.records[0].get(0)).toEqual('424242'); - expect(usedTransactions.length).toEqual(3); - usedTransactions.forEach(tx => expect(tx.isOpen()).toBeFalsy()); - session.close(); - done(); - }).catch(error => { - done.fail(error); - }); + resultPromise + .then(result => { + expect(result.records[0].get(0)).toEqual('424242') + expect(usedTransactions.length).toEqual(3) + usedTransactions.forEach(tx => expect(tx.isOpen()).toBeFalsy()) + session.close() + done() + }) + .catch(error => { + done.fail(error) + }) } - function testTransactionRetryOnFatalError(failureResponseFunction, done) { - const session = driver.session(); + function testTransactionRetryOnFatalError (failureResponseFunction, done) { + const session = driver.session() - const usedTransactions = []; + const usedTransactions = [] const resultPromise = session.writeTransaction(tx => { - usedTransactions.push(tx); - return failureResponseFunction(); - }); + usedTransactions.push(tx) + return failureResponseFunction() + }) - resultPromise.then(result => { - session.close(); - done.fail('Retries should not succeed: ' + JSON.stringify(result)); - }).catch(error => { - session.close(); - expect(error).toBeDefined(); - expect(error).not.toBeNull(); - expect(usedTransactions.length).toEqual(1); - expect(usedTransactions[0].isOpen()).toBeFalsy(); - done(); - }); + resultPromise + .then(result => { + session.close() + done.fail('Retries should not succeed: ' + JSON.stringify(result)) + }) + .catch(error => { + session.close() + expect(error).toBeDefined() + expect(error).not.toBeNull() + expect(usedTransactions.length).toEqual(1) + expect(usedTransactions[0].isOpen()).toBeFalsy() + done() + }) } - function countNodes(label, propertyKey, propertyValue) { + function countNodes (label, propertyKey, propertyValue) { return new Promise((resolve, reject) => { - session.run(`MATCH (n: ${label} {${propertyKey}: ${propertyValue}}) RETURN count(n) AS count`).then(result => { - resolve(result.records[0].get('count').toNumber()); - }).catch(error => reject(error)); - }); + session + .run( + `MATCH (n: ${label} {${propertyKey}: ${propertyValue}}) RETURN count(n) AS count` + ) + .then(result => { + resolve(result.records[0].get('count').toNumber()) + }) + .catch(error => reject(error)) + }) } - function withQueryInTmpSession(driver, callback) { - const tmpSession = driver.session(); + function withQueryInTmpSession (driver, callback) { + const tmpSession = driver.session() return tmpSession.run('RETURN 1').then(() => { - tmpSession.close(callback); - }); + tmpSession.close(callback) + }) } - function newSessionWithConnection(connection) { - const connectionProvider = new SingleConnectionProvider(Promise.resolve(connection)); - const session = new Session(READ, connectionProvider); - session.beginTransaction(); // force session to acquire new connection - return session; + function newSessionWithConnection (connection) { + const connectionProvider = new SingleConnectionProvider( + Promise.resolve(connection) + ) + const session = new Session(READ, connectionProvider) + session.beginTransaction() // force session to acquire new connection + return session } - function idleConnectionCount(driver) { - const connectionProvider = driver._connectionProvider; - const address = connectionProvider._address.asKey(); - const connectionPool = connectionProvider._connectionPool; - const idleConnections = connectionPool._pools[address]; - return idleConnections.length; + function idleConnectionCount (driver) { + const connectionProvider = driver._connectionProvider + const address = connectionProvider._address.asKey() + const connectionPool = connectionProvider._connectionPool + const idleConnections = connectionPool._pools[address] + return idleConnections.length } - function verifyBookmark(bookmark) { - expect(bookmark).toBeDefined(); - expect(bookmark).not.toBeNull(); + function verifyBookmark (bookmark) { + expect(bookmark).toBeDefined() + expect(bookmark).not.toBeNull() } - function expectTransactionTerminatedError(error) { - const message = error.message.toLowerCase(); - expect(message.indexOf('transaction')).not.toBeLessThan(0); - expect(message.indexOf('terminated')).not.toBeLessThan(0); + function expectTransactionTerminatedError (error) { + const message = error.message.toLowerCase() + expect(message.indexOf('transaction')).not.toBeLessThan(0) + expect(message.indexOf('terminated')).not.toBeLessThan(0) } - function readAllNodeIds() { + function readAllNodeIds () { return new Promise((resolve, reject) => { - const session = driver.session(); - session.run('MATCH (n) RETURN n.id').then(result => { - const ids = result.records.map(record => record.get(0).toNumber()); - session.close(); - resolve(ids); - }).catch(error => { - reject(error); - }); - }); + const session = driver.session() + session + .run('MATCH (n) RETURN n.id') + .then(result => { + const ids = result.records.map(record => record.get(0).toNumber()) + session.close() + resolve(ids) + }) + .catch(error => { + reject(error) + }) + }) } - function runQueryAndGetBookmark(driver) { - const session = driver.session(); - const tx = session.beginTransaction(); + function runQueryAndGetBookmark (driver) { + const session = driver.session() + const tx = session.beginTransaction() return new Promise((resolve, reject) => { - tx.run('CREATE ()').then(() => { - tx.commit().then(() => { - const bookmark = session.lastBookmark(); - session.close(() => { - resolve(bookmark); - }); - }).catch(error => reject(error)); - }).catch(error => reject(error)); - }); + tx.run('CREATE ()') + .then(() => { + tx.commit() + .then(() => { + const bookmark = session.lastBookmark() + session.close(() => { + resolve(bookmark) + }) + }) + .catch(error => reject(error)) + }) + .catch(error => reject(error)) + }) } - function numberOfAcquiredConnectionsFromPool() { - const pool = driver._pool; - return pool.activeResourceCount(ServerAddress.fromUrl('localhost:7687')); + function numberOfAcquiredConnectionsFromPool () { + const pool = driver._pool + return pool.activeResourceCount(ServerAddress.fromUrl('localhost:7687')) } - function testConnectionTimeout(encrypted, done) { + function testConnectionTimeout (encrypted, done) { if (testUtils.isClient() && encrypted) { // skip encrypted test in browser because it runs all tests in a HTTP page - done(); - return; + done() + return } - const boltUri = 'bolt://10.0.0.0'; // use non-routable IP address which never responds - const config = {encrypted: encrypted, connectionTimeout: 1000}; - - const localDriver = neo4j.driver(boltUri, sharedNeo4j.authToken, config); - const session = localDriver.session(); - session.run('RETURN 1').then(() => { - localDriver.close(); - done.fail('Query did not fail'); - }).catch(error => { - localDriver.close(); - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - - // in some environments non-routable address results in immediate 'connection refused' error and connect - // timeout is not fired; skip message assertion for such cases, it is important for connect attempt to not hang - if (error.message.indexOf('Failed to establish connection') === 0) { - expect(error.message).toEqual('Failed to establish connection in 1000ms'); - } + const boltUri = 'bolt://10.0.0.0' // use non-routable IP address which never responds + const config = { encrypted: encrypted, connectionTimeout: 1000 } - done(); - }); - } + const localDriver = neo4j.driver(boltUri, sharedNeo4j.authToken, config) + const session = localDriver.session() + session + .run('RETURN 1') + .then(() => { + localDriver.close() + done.fail('Query did not fail') + }) + .catch(error => { + localDriver.close() + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) + + // in some environments non-routable address results in immediate 'connection refused' error and connect + // timeout is not fired; skip message assertion for such cases, it is important for connect attempt to not hang + if (error.message.indexOf('Failed to establish connection') === 0) { + expect(error.message).toEqual( + 'Failed to establish connection in 1000ms' + ) + } - function testUnsupportedQueryParameter(value, done) { - session.run('RETURN $value', {value: value}).then(() => { - done.fail(`Should not be possible to send ${value.constructor.name} ${value} as a query parameter`); - }).catch(error => { - expect(error.name).toEqual('Neo4jError'); - expect(error.code).toEqual(neo4j.error.PROTOCOL_ERROR); - done(); - }); + done() + }) } -}); + function testUnsupportedQueryParameter (value, done) { + session + .run('RETURN $value', { value: value }) + .then(() => { + done.fail( + `Should not be possible to send ${ + value.constructor.name + } ${value} as a query parameter` + ) + }) + .catch(error => { + expect(error.name).toEqual('Neo4jError') + expect(error.code).toEqual(neo4j.error.PROTOCOL_ERROR) + done() + }) + } +}) diff --git a/test/v1/spatial-types.test.js b/test/v1/spatial-types.test.js index 6939cc457..872923645 100644 --- a/test/v1/spatial-types.test.js +++ b/test/v1/spatial-types.test.js @@ -17,137 +17,165 @@ * limitations under the License. */ -import neo4j, {int} from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import {ServerVersion, VERSION_3_4_0} from '../../src/v1/internal/server-version'; -import {isPoint, Point} from '../../src/v1/spatial-types'; -import _ from 'lodash'; +import neo4j, { int } from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import { + ServerVersion, + VERSION_3_4_0 +} from '../../src/v1/internal/server-version' +import { isPoint, Point } from '../../src/v1/spatial-types' +import _ from 'lodash' -const WGS_84_2D_CRS_CODE = neo4j.int(4326); -const CARTESIAN_2D_CRS_CODE = neo4j.int(7203); +const WGS_84_2D_CRS_CODE = neo4j.int(4326) +const CARTESIAN_2D_CRS_CODE = neo4j.int(7203) -const WGS_84_3D_CRS_CODE = neo4j.int(4979); -const CARTESIAN_3D_CRS_CODE = neo4j.int(9157); +const WGS_84_3D_CRS_CODE = neo4j.int(4979) +const CARTESIAN_3D_CRS_CODE = neo4j.int(9157) describe('spatial-types', () => { - - let driver; - let driverWithNativeNumbers; - let session; - let serverVersion; + let driver + let driverWithNativeNumbers + let session + let serverVersion beforeAll(done => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - driverWithNativeNumbers = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {disableLosslessIntegers: true}); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + driverWithNativeNumbers = neo4j.driver( + 'bolt://localhost', + sharedNeo4j.authToken, + { disableLosslessIntegers: true } + ) ServerVersion.fromDriver(driver).then(version => { - serverVersion = version; - done(); - }); - }); + serverVersion = version + done() + }) + }) afterAll(() => { if (driver) { - driver.close(); - driver = null; + driver.close() + driver = null } if (driverWithNativeNumbers) { - driverWithNativeNumbers.close(); - driverWithNativeNumbers = null; + driverWithNativeNumbers.close() + driverWithNativeNumbers = null } - }); + }) beforeEach(done => { - session = driver.session(); - session.run('MATCH (n) DETACH DELETE n').then(() => { - done(); - }).catch(error => { - done.fail(error); - }); - }); + session = driver.session() + session + .run('MATCH (n) DETACH DELETE n') + .then(() => { + done() + }) + .catch(error => { + done.fail(error) + }) + }) afterEach(() => { if (session) { - session.close(); - session = null; + session.close() + session = null } - }); + }) it('should expose frozen immutable points', () => { - const point = new Point(CARTESIAN_2D_CRS_CODE, 1.2, 3.4); + const point = new Point(CARTESIAN_2D_CRS_CODE, 1.2, 3.4) - expect(Object.isFrozen(point)).toBeTruthy(); + expect(Object.isFrozen(point)).toBeTruthy() - expect(point.srid).toEqual(CARTESIAN_2D_CRS_CODE); - expect(point.x).toEqual(1.2); - expect(point.y).toEqual(3.4); - expect(point.z).toBeUndefined(); + expect(point.srid).toEqual(CARTESIAN_2D_CRS_CODE) + expect(point.x).toEqual(1.2) + expect(point.y).toEqual(3.4) + expect(point.z).toBeUndefined() try { - point.x = 5.6; - } catch (e) { - } + point.x = 5.6 + } catch (e) {} try { - point.y = 7.8; - } catch (e) { - } + point.y = 7.8 + } catch (e) {} try { - point.z = 9.0; - } catch (e) { - } + point.z = 9.0 + } catch (e) {} - expect(point.x).toEqual(1.2); - expect(point.y).toEqual(3.4); - expect(point.z).toBeUndefined(); - }); + expect(point.x).toEqual(1.2) + expect(point.y).toEqual(3.4) + expect(point.z).toBeUndefined() + }) it('should receive 2D points', done => { - testReceivingOfPoints(done, 'RETURN point({x: 169.99, y: 12.1718})', point => { - expect(isPoint(point)).toBeTruthy(); - expect(point.srid).toEqual(CARTESIAN_2D_CRS_CODE); - expect(point.x).toEqual(169.99); - expect(point.y).toEqual(12.1718); - expect(point.z).toBeUndefined(); - }); - }); + testReceivingOfPoints( + done, + 'RETURN point({x: 169.99, y: 12.1718})', + point => { + expect(isPoint(point)).toBeTruthy() + expect(point.srid).toEqual(CARTESIAN_2D_CRS_CODE) + expect(point.x).toEqual(169.99) + expect(point.y).toEqual(12.1718) + expect(point.z).toBeUndefined() + } + ) + }) it('should receive 2D points with crs', done => { - testReceivingOfPoints(done, `RETURN point({x: 2.3, y: 4.5, crs: 'WGS-84'})`, point => { - expect(isPoint(point)).toBeTruthy(); - expect(point.srid).toEqual(WGS_84_2D_CRS_CODE); - expect(point.x).toEqual(2.3); - expect(point.y).toEqual(4.5); - expect(point.z).toBeUndefined(); - }); - }); + testReceivingOfPoints( + done, + `RETURN point({x: 2.3, y: 4.5, crs: 'WGS-84'})`, + point => { + expect(isPoint(point)).toBeTruthy() + expect(point.srid).toEqual(WGS_84_2D_CRS_CODE) + expect(point.x).toEqual(2.3) + expect(point.y).toEqual(4.5) + expect(point.z).toBeUndefined() + } + ) + }) it('should receive 3D points', done => { - testReceivingOfPoints(done, 'RETURN point({x: -19.9, y: 45.99, z: 8.88})', point => { - expect(isPoint(point)).toBeTruthy(); - expect(point.srid).toEqual(CARTESIAN_3D_CRS_CODE); - expect(point.x).toEqual(-19.9); - expect(point.y).toEqual(45.99); - expect(point.z).toEqual(8.88); - }); - }); + testReceivingOfPoints( + done, + 'RETURN point({x: -19.9, y: 45.99, z: 8.88})', + point => { + expect(isPoint(point)).toBeTruthy() + expect(point.srid).toEqual(CARTESIAN_3D_CRS_CODE) + expect(point.x).toEqual(-19.9) + expect(point.y).toEqual(45.99) + expect(point.z).toEqual(8.88) + } + ) + }) it('should receive 3D points with crs', done => { - testReceivingOfPoints(done, `RETURN point({x: 34.76, y: 11.9, z: -99.01, crs: 'WGS-84-3D'})`, point => { - expect(isPoint(point)).toBeTruthy(); - expect(point.srid).toEqual(WGS_84_3D_CRS_CODE); - expect(point.x).toEqual(34.76); - expect(point.y).toEqual(11.9); - expect(point.z).toEqual(-99.01); - }); - }); + testReceivingOfPoints( + done, + `RETURN point({x: 34.76, y: 11.9, z: -99.01, crs: 'WGS-84-3D'})`, + point => { + expect(isPoint(point)).toBeTruthy() + expect(point.srid).toEqual(WGS_84_3D_CRS_CODE) + expect(point.x).toEqual(34.76) + expect(point.y).toEqual(11.9) + expect(point.z).toEqual(-99.01) + } + ) + }) it('should send and receive 2D point', done => { - testSendingAndReceivingOfPoints(done, new Point(CARTESIAN_2D_CRS_CODE, 19.101, -88.21)); - }); + testSendingAndReceivingOfPoints( + done, + new Point(CARTESIAN_2D_CRS_CODE, 19.101, -88.21) + ) + }) it('should send and receive 3D point', done => { - testSendingAndReceivingOfPoints(done, new Point(WGS_84_3D_CRS_CODE, 1.22, 9.8, -6.65)); - }); + testSendingAndReceivingOfPoints( + done, + new Point(WGS_84_3D_CRS_CODE, 1.22, 9.8, -6.65) + ) + }) it('should send and receive array of 2D points', done => { const arrayOfPoints = [ @@ -157,10 +185,10 @@ describe('spatial-types', () => { new Point(WGS_84_2D_CRS_CODE, 93.75, 123.213), new Point(WGS_84_2D_CRS_CODE, 111.13, -90.1), new Point(WGS_84_2D_CRS_CODE, 43.99, -1) - ]; + ] - testSendingAndReceivingOfPoints(done, arrayOfPoints); - }); + testSendingAndReceivingOfPoints(done, arrayOfPoints) + }) it('should send and receive array of 3D points', done => { const arrayOfPoints = [ @@ -169,116 +197,137 @@ describe('spatial-types', () => { new Point(CARTESIAN_3D_CRS_CODE, 0.845, -0.74, 3.48), new Point(CARTESIAN_3D_CRS_CODE, 123.33, 93.3, 96.96), new Point(CARTESIAN_3D_CRS_CODE, -54.9, 13.7893, -90.9) - ]; + ] - testSendingAndReceivingOfPoints(done, arrayOfPoints); - }); + testSendingAndReceivingOfPoints(done, arrayOfPoints) + }) it('should receive point with number srid when disableLosslessIntegers=true', done => { - session = driverWithNativeNumbers.session(); - - testReceivingOfPoints(done, 'RETURN point({x: 42.231, y: 176.938123})', point => { - expect(isPoint(point)).toBeTruthy(); - expect(_.isNumber(point.srid)).toBeTruthy(); - expect(point.srid).toEqual(CARTESIAN_2D_CRS_CODE.toNumber()); - }); - }); + session = driverWithNativeNumbers.session() + + testReceivingOfPoints( + done, + 'RETURN point({x: 42.231, y: 176.938123})', + point => { + expect(isPoint(point)).toBeTruthy() + expect(_.isNumber(point.srid)).toBeTruthy() + expect(point.srid).toEqual(CARTESIAN_2D_CRS_CODE.toNumber()) + } + ) + }) it('should send and receive point with number srid when disableLosslessIntegers=true', done => { - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - testSendingAndReceivingOfPoints(done, new Point(CARTESIAN_3D_CRS_CODE.toNumber(), 12.87, 13.89, 14.901)); - }); + testSendingAndReceivingOfPoints( + done, + new Point(CARTESIAN_3D_CRS_CODE.toNumber(), 12.87, 13.89, 14.901) + ) + }) it('should convert points to string', () => { - const point1 = new Point(CARTESIAN_3D_CRS_CODE, 19.24, 100.29, 20.22222); - expect(point1.toString()).toEqual('Point{srid=9157, x=19.24, y=100.29, z=20.22222}'); - - const point2 = new Point(WGS_84_2D_CRS_CODE, 1.00005, 2.00006); - expect(point2.toString()).toEqual('Point{srid=4326, x=1.00005, y=2.00006}'); - - const point3 = new Point(WGS_84_3D_CRS_CODE, 1.111, 2.222, 0.0); - expect(point3.toString()).toEqual('Point{srid=4979, x=1.111, y=2.222, z=0.0}'); - - const point4 = new Point(CARTESIAN_2D_CRS_CODE, 78.15, 92.2, null); - expect(point4.toString()).toEqual('Point{srid=7203, x=78.15, y=92.2}'); - - const point5 = new Point(WGS_84_2D_CRS_CODE, 123.9, 64.5, undefined); - expect(point5.toString()).toEqual('Point{srid=4326, x=123.9, y=64.5}'); - - const point6 = new Point(CARTESIAN_2D_CRS_CODE, 23.9378123, 67.3891, Number.NaN); - expect(point6.toString()).toEqual('Point{srid=7203, x=23.9378123, y=67.3891}'); - }); + const point1 = new Point(CARTESIAN_3D_CRS_CODE, 19.24, 100.29, 20.22222) + expect(point1.toString()).toEqual( + 'Point{srid=9157, x=19.24, y=100.29, z=20.22222}' + ) + + const point2 = new Point(WGS_84_2D_CRS_CODE, 1.00005, 2.00006) + expect(point2.toString()).toEqual('Point{srid=4326, x=1.00005, y=2.00006}') + + const point3 = new Point(WGS_84_3D_CRS_CODE, 1.111, 2.222, 0.0) + expect(point3.toString()).toEqual( + 'Point{srid=4979, x=1.111, y=2.222, z=0.0}' + ) + + const point4 = new Point(CARTESIAN_2D_CRS_CODE, 78.15, 92.2, null) + expect(point4.toString()).toEqual('Point{srid=7203, x=78.15, y=92.2}') + + const point5 = new Point(WGS_84_2D_CRS_CODE, 123.9, 64.5, undefined) + expect(point5.toString()).toEqual('Point{srid=4326, x=123.9, y=64.5}') + + const point6 = new Point( + CARTESIAN_2D_CRS_CODE, + 23.9378123, + 67.3891, + Number.NaN + ) + expect(point6.toString()).toEqual( + 'Point{srid=7203, x=23.9378123, y=67.3891}' + ) + }) it('should validate types of constructor arguments for Point', () => { - expect(() => new Point('1', 2, 3)).toThrowError(TypeError); - expect(() => new Point(1, '2', 3)).toThrowError(TypeError); - expect(() => new Point(1, 2, '3')).toThrowError(TypeError); - expect(() => new Point(1, 2, '3')).toThrowError(TypeError); + expect(() => new Point('1', 2, 3)).toThrowError(TypeError) + expect(() => new Point(1, '2', 3)).toThrowError(TypeError) + expect(() => new Point(1, 2, '3')).toThrowError(TypeError) + expect(() => new Point(1, 2, '3')).toThrowError(TypeError) - expect(() => new Point('1', 2, 3, null)).toThrowError(TypeError); - expect(() => new Point(1, '2', 3, null)).toThrowError(TypeError); - expect(() => new Point(1, 2, '3', null)).toThrowError(TypeError); - expect(() => new Point(1, 2, '3', null)).toThrowError(TypeError); + expect(() => new Point('1', 2, 3, null)).toThrowError(TypeError) + expect(() => new Point(1, '2', 3, null)).toThrowError(TypeError) + expect(() => new Point(1, 2, '3', null)).toThrowError(TypeError) + expect(() => new Point(1, 2, '3', null)).toThrowError(TypeError) - expect(() => new Point('1', 2, 3, 4)).toThrowError(TypeError); - expect(() => new Point(1, '2', 3, 4)).toThrowError(TypeError); - expect(() => new Point(1, 2, '3', 4)).toThrowError(TypeError); - expect(() => new Point(1, 2, '3', 4)).toThrowError(TypeError); + expect(() => new Point('1', 2, 3, 4)).toThrowError(TypeError) + expect(() => new Point(1, '2', 3, 4)).toThrowError(TypeError) + expect(() => new Point(1, 2, '3', 4)).toThrowError(TypeError) + expect(() => new Point(1, 2, '3', 4)).toThrowError(TypeError) - expect(() => new Point(1, int(2), 3, 4)).toThrowError(TypeError); - expect(() => new Point(1, 2, int(3), 4)).toThrowError(TypeError); - expect(() => new Point(1, 2, 3, int(4))).toThrowError(TypeError); + expect(() => new Point(1, int(2), 3, 4)).toThrowError(TypeError) + expect(() => new Point(1, 2, int(3), 4)).toThrowError(TypeError) + expect(() => new Point(1, 2, 3, int(4))).toThrowError(TypeError) - expect(new Point(1, 2, 3, 4)).toBeDefined(); + expect(new Point(1, 2, 3, 4)).toBeDefined() - expect(new Point(int(1), 2, 3, undefined)).toBeDefined(); - expect(new Point(1, 2, 3, undefined)).toBeDefined(); + expect(new Point(int(1), 2, 3, undefined)).toBeDefined() + expect(new Point(1, 2, 3, undefined)).toBeDefined() - expect(new Point(1, 2, 3, null)).toBeDefined(); - expect(new Point(int(1), 2, 3, null)).toBeDefined(); - }); + expect(new Point(1, 2, 3, null)).toBeDefined() + expect(new Point(int(1), 2, 3, null)).toBeDefined() + }) - function testReceivingOfPoints(done, query, pointChecker) { + function testReceivingOfPoints (done, query, pointChecker) { if (neo4jDoesNotSupportPoints(done)) { - return; + return } session.run(query).then(result => { - const records = result.records; - expect(records.length).toEqual(1); + const records = result.records + expect(records.length).toEqual(1) - const point = records[0].get(0); - pointChecker(point); + const point = records[0].get(0) + pointChecker(point) - session.close(); - done(); - }); + session.close() + done() + }) } - function testSendingAndReceivingOfPoints(done, originalValue) { + function testSendingAndReceivingOfPoints (done, originalValue) { if (neo4jDoesNotSupportPoints(done)) { - return; + return } - session.run('CREATE (n: Node {value: $value}) RETURN n.value', {value: originalValue}).then(result => { - const records = result.records; - expect(records.length).toEqual(1); + session + .run('CREATE (n: Node {value: $value}) RETURN n.value', { + value: originalValue + }) + .then(result => { + const records = result.records + expect(records.length).toEqual(1) - const receivedPoint = records[0].get(0); - expect(receivedPoint).toEqual(originalValue); + const receivedPoint = records[0].get(0) + expect(receivedPoint).toEqual(originalValue) - session.close(); - done(); - }); + session.close() + done() + }) } - function neo4jDoesNotSupportPoints(done) { + function neo4jDoesNotSupportPoints (done) { if (serverVersion.compareTo(VERSION_3_4_0) < 0) { - done(); - return true; + done() + return true } - return false; + return false } - -}); +}) diff --git a/test/v1/stress.test.js b/test/v1/stress.test.js index eaaf34e51..a21aa0a1d 100644 --- a/test/v1/stress.test.js +++ b/test/v1/stress.test.js @@ -17,15 +17,17 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import {READ, WRITE} from '../../src/v1/driver'; -import parallelLimit from 'async/parallelLimit'; -import _ from 'lodash'; -import {ServerVersion, VERSION_3_2_0} from '../../src/v1/internal/server-version'; -import sharedNeo4j from '../internal/shared-neo4j'; +import neo4j from '../../src/v1' +import { READ, WRITE } from '../../src/v1/driver' +import parallelLimit from 'async/parallelLimit' +import _ from 'lodash' +import { + ServerVersion, + VERSION_3_2_0 +} from '../../src/v1/internal/server-version' +import sharedNeo4j from '../internal/shared-neo4j' describe('stress tests', () => { - const TEST_MODES = { fast: { commandsCount: 5000, @@ -37,74 +39,80 @@ describe('stress tests', () => { parallelism: 16, maxRunTimeMs: 60 * 60000 // 60 minutes } - }; + } - const READ_QUERY = 'MATCH (n) RETURN n LIMIT 1'; - const WRITE_QUERY = 'CREATE (person:Person:Employee {name: {name}, salary: {salary}}) RETURN person'; + const READ_QUERY = 'MATCH (n) RETURN n LIMIT 1' + const WRITE_QUERY = + 'CREATE (person:Person:Employee {name: {name}, salary: {salary}}) RETURN person' - const TEST_MODE = modeFromEnvOrDefault('STRESS_TEST_MODE'); - const DATABASE_URI = fromEnvOrDefault('STRESS_TEST_DATABASE_URI', 'bolt://localhost'); - const LOGGING_ENABLED = fromEnvOrDefault('STRESS_TEST_LOGGING_ENABLED', false); + const TEST_MODE = modeFromEnvOrDefault('STRESS_TEST_MODE') + const DATABASE_URI = fromEnvOrDefault( + 'STRESS_TEST_DATABASE_URI', + 'bolt://localhost' + ) + const LOGGING_ENABLED = fromEnvOrDefault('STRESS_TEST_LOGGING_ENABLED', false) - let originalTimeout; - let driver; + let originalTimeout + let driver beforeEach(done => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = TEST_MODE.maxRunTimeMs; + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = TEST_MODE.maxRunTimeMs - const config = {logging: neo4j.logging.console(LOGGING_ENABLED ? 'debug' : 'info')}; - driver = neo4j.driver(DATABASE_URI, sharedNeo4j.authToken, config); + const config = { + logging: neo4j.logging.console(LOGGING_ENABLED ? 'debug' : 'info') + } + driver = neo4j.driver(DATABASE_URI, sharedNeo4j.authToken, config) - cleanupDb(driver).then(() => done()); - }); + cleanupDb(driver).then(() => done()) + }) afterEach(done => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout cleanupDb(driver).then(() => { - driver.close(); - done(); - }); - }); + driver.close() + done() + }) + }) it('basic', done => { - const context = new Context(driver, LOGGING_ENABLED); - const commands = createCommands(context); + const context = new Context(driver, LOGGING_ENABLED) + const commands = createCommands(context) - console.time('Basic-stress-test'); + console.time('Basic-stress-test') parallelLimit(commands, TEST_MODE.parallelism, error => { - console.timeEnd('Basic-stress-test'); + console.timeEnd('Basic-stress-test') - console.log('Read statistics: ', context.readServersWithQueryCount); - console.log('Write statistics: ', context.writeServersWithQueryCount); + console.log('Read statistics: ', context.readServersWithQueryCount) + console.log('Write statistics: ', context.writeServersWithQueryCount) if (error) { - done.fail(error); + done.fail(error) } verifyServers(context) .then(() => verifyNodeCount(context)) .then(() => done()) - .catch(error => done.fail(error)); - }); - }); + .catch(error => done.fail(error)) + }) + }) - function createCommands(context) { - const uniqueCommands = createUniqueCommands(context); + function createCommands (context) { + const uniqueCommands = createUniqueCommands(context) - const commands = []; + const commands = [] for (let i = 0; i < TEST_MODE.commandsCount; i++) { - const randomCommand = _.sample(uniqueCommands); - commands.push(randomCommand); + const randomCommand = _.sample(uniqueCommands) + commands.push(randomCommand) } - console.log(`Generated ${TEST_MODE.commandsCount} commands`); + console.log(`Generated ${TEST_MODE.commandsCount} commands`) - return commands; + return commands } - function createUniqueCommands(context) { + function createUniqueCommands (context) { return [ readQueryCommand(context), readQueryWithBookmarkCommand(context), @@ -118,388 +126,507 @@ describe('stress tests', () => { writeQueryInTxFunctionCommand(context), writeQueryInTxWithBookmarkCommand(context), writeQueryInTxFunctionWithBookmarkCommand(context) - ]; + ] } - function readQueryCommand(context) { - return queryCommand(context, READ_QUERY, () => noParams(), READ, false); + function readQueryCommand (context) { + return queryCommand(context, READ_QUERY, () => noParams(), READ, false) } - function readQueryWithBookmarkCommand(context) { - return queryCommand(context, READ_QUERY, () => noParams(), READ, true); + function readQueryWithBookmarkCommand (context) { + return queryCommand(context, READ_QUERY, () => noParams(), READ, true) } - function readQueryInTxCommand(context) { - return queryInTxCommand(context, READ_QUERY, () => noParams(), READ, false); + function readQueryInTxCommand (context) { + return queryInTxCommand(context, READ_QUERY, () => noParams(), READ, false) } - function readQueryInTxFunctionCommand(context) { - return queryInTxFunctionCommand(context, READ_QUERY, () => noParams(), READ, false); + function readQueryInTxFunctionCommand (context) { + return queryInTxFunctionCommand( + context, + READ_QUERY, + () => noParams(), + READ, + false + ) } - function readQueryInTxWithBookmarkCommand(context) { - return queryInTxCommand(context, READ_QUERY, () => noParams(), READ, true); + function readQueryInTxWithBookmarkCommand (context) { + return queryInTxCommand(context, READ_QUERY, () => noParams(), READ, true) } - function readQueryInTxFunctionWithBookmarkCommand(context) { - return queryInTxFunctionCommand(context, READ_QUERY, () => noParams(), READ, true); + function readQueryInTxFunctionWithBookmarkCommand (context) { + return queryInTxFunctionCommand( + context, + READ_QUERY, + () => noParams(), + READ, + true + ) } - function writeQueryCommand(context) { - return queryCommand(context, WRITE_QUERY, () => randomParams(), WRITE, false); + function writeQueryCommand (context) { + return queryCommand( + context, + WRITE_QUERY, + () => randomParams(), + WRITE, + false + ) } - function writeQueryWithBookmarkCommand(context) { - return queryCommand(context, WRITE_QUERY, () => randomParams(), WRITE, true); + function writeQueryWithBookmarkCommand (context) { + return queryCommand(context, WRITE_QUERY, () => randomParams(), WRITE, true) } - function writeQueryInTxCommand(context) { - return queryInTxCommand(context, WRITE_QUERY, () => randomParams(), WRITE, false); + function writeQueryInTxCommand (context) { + return queryInTxCommand( + context, + WRITE_QUERY, + () => randomParams(), + WRITE, + false + ) } - function writeQueryInTxFunctionCommand(context) { - return queryInTxFunctionCommand(context, WRITE_QUERY, () => randomParams(), WRITE, false); + function writeQueryInTxFunctionCommand (context) { + return queryInTxFunctionCommand( + context, + WRITE_QUERY, + () => randomParams(), + WRITE, + false + ) } - function writeQueryInTxWithBookmarkCommand(context) { - return queryInTxCommand(context, WRITE_QUERY, () => randomParams(), WRITE, true); + function writeQueryInTxWithBookmarkCommand (context) { + return queryInTxCommand( + context, + WRITE_QUERY, + () => randomParams(), + WRITE, + true + ) } - function writeQueryInTxFunctionWithBookmarkCommand(context) { - return queryInTxFunctionCommand(context, WRITE_QUERY, () => randomParams(), WRITE, true); + function writeQueryInTxFunctionWithBookmarkCommand (context) { + return queryInTxFunctionCommand( + context, + WRITE_QUERY, + () => randomParams(), + WRITE, + true + ) } - function queryCommand(context, query, paramsSupplier, accessMode, useBookmark) { + function queryCommand ( + context, + query, + paramsSupplier, + accessMode, + useBookmark + ) { return callback => { - const commandId = context.nextCommandId(); - const session = newSession(context, accessMode, useBookmark); - const params = paramsSupplier(); + const commandId = context.nextCommandId() + const session = newSession(context, accessMode, useBookmark) + const params = paramsSupplier() - context.log(commandId, `About to run ${accessMode} query`); + context.log(commandId, `About to run ${accessMode} query`) - session.run(query, params).then(result => { - context.queryCompleted(result, accessMode); - context.log(commandId, `Query completed successfully`); + session + .run(query, params) + .then(result => { + context.queryCompleted(result, accessMode) + context.log(commandId, `Query completed successfully`) - session.close(() => { - const possibleError = verifyQueryResult(result); - callback(possibleError); - }); - }).catch(error => { - context.log(commandId, `Query failed with error ${JSON.stringify(error)}`); - callback(error); - }); - }; + session.close(() => { + const possibleError = verifyQueryResult(result) + callback(possibleError) + }) + }) + .catch(error => { + context.log( + commandId, + `Query failed with error ${JSON.stringify(error)}` + ) + callback(error) + }) + } } - function queryInTxFunctionCommand(context, query, paramsSupplier, accessMode, useBookmark) { + function queryInTxFunctionCommand ( + context, + query, + paramsSupplier, + accessMode, + useBookmark + ) { return callback => { - const commandId = context.nextCommandId(); - const params = paramsSupplier(); - const session = newSession(context, accessMode, useBookmark); + const commandId = context.nextCommandId() + const params = paramsSupplier() + const session = newSession(context, accessMode, useBookmark) - context.log(commandId, `About to run ${accessMode} query in TX function`); + context.log(commandId, `About to run ${accessMode} query in TX function`) - let resultPromise; + let resultPromise if (accessMode === READ) { - resultPromise = session.readTransaction(tx => tx.run(query, params)); + resultPromise = session.readTransaction(tx => tx.run(query, params)) } else { - resultPromise = session.writeTransaction(tx => tx.run(query, params)); + resultPromise = session.writeTransaction(tx => tx.run(query, params)) } - resultPromise.then(result => { - context.queryCompleted(result, accessMode, session.lastBookmark()); - context.log(commandId, `Transaction function executed successfully`); + resultPromise + .then(result => { + context.queryCompleted(result, accessMode, session.lastBookmark()) + context.log(commandId, `Transaction function executed successfully`) - session.close(() => { - const possibleError = verifyQueryResult(result); - callback(possibleError); - }); - }).catch(error => { - context.log(commandId, `Transaction function failed with error ${JSON.stringify(error)}`); - callback(error); - }); - }; + session.close(() => { + const possibleError = verifyQueryResult(result) + callback(possibleError) + }) + }) + .catch(error => { + context.log( + commandId, + `Transaction function failed with error ${JSON.stringify(error)}` + ) + callback(error) + }) + } } - function queryInTxCommand(context, query, paramsSupplier, accessMode, useBookmark) { + function queryInTxCommand ( + context, + query, + paramsSupplier, + accessMode, + useBookmark + ) { return callback => { - const commandId = context.nextCommandId(); - const session = newSession(context, accessMode, useBookmark); - const tx = session.beginTransaction(); - const params = paramsSupplier(); - - context.log(commandId, `About to run ${accessMode} query in TX`); - - tx.run(query, params).then(result => { - let commandError = verifyQueryResult(result); - - tx.commit().catch(commitError => { - context.log(commandId, `Transaction commit failed with error ${JSON.stringify(error)}`); - if (!commandError) { - commandError = commitError; - } - }).then(() => { - context.queryCompleted(result, accessMode, session.lastBookmark()); - context.log(commandId, `Transaction committed successfully`); - - session.close(() => { - callback(commandError); - }); - }); - - }).catch(error => { - context.log(commandId, `Query failed with error ${JSON.stringify(error)}`); - callback(error); - }); - }; + const commandId = context.nextCommandId() + const session = newSession(context, accessMode, useBookmark) + const tx = session.beginTransaction() + const params = paramsSupplier() + + context.log(commandId, `About to run ${accessMode} query in TX`) + + tx.run(query, params) + .then(result => { + let commandError = verifyQueryResult(result) + + tx.commit() + .catch(commitError => { + context.log( + commandId, + `Transaction commit failed with error ${JSON.stringify( + commitError + )}` + ) + if (!commandError) { + commandError = commitError + } + }) + .then(() => { + context.queryCompleted(result, accessMode, session.lastBookmark()) + context.log(commandId, `Transaction committed successfully`) + + session.close(() => { + callback(commandError) + }) + }) + }) + .catch(error => { + context.log( + commandId, + `Query failed with error ${JSON.stringify(error)}` + ) + callback(error) + }) + } } - function verifyQueryResult(result) { + function verifyQueryResult (result) { if (!result) { - return new Error(`Received undefined result`); + return new Error(`Received undefined result`) } else if (result.records.length === 0) { // it is ok to receive no nodes back for read queries at the beginning of the test - return null; + return null } else if (result.records.length === 1) { - const record = result.records[0]; - return verifyRecord(record); + const record = result.records[0] + return verifyRecord(record) } else { - return new Error(`Unexpected amount of records received: ${JSON.stringify(result)}`); + return new Error( + `Unexpected amount of records received: ${JSON.stringify(result)}` + ) } } - function verifyRecord(record) { - const node = record.get(0); + function verifyRecord (record) { + const node = record.get(0) if (!arraysEqual(['Person', 'Employee'], node.labels)) { - return new Error(`Unexpected labels in node: ${JSON.stringify(node)}`); + return new Error(`Unexpected labels in node: ${JSON.stringify(node)}`) } - const propertyKeys = _.keys(node.properties); - if (!_.isEmpty(propertyKeys) && !arraysEqual(['name', 'salary'], propertyKeys)) { - return new Error(`Unexpected property keys in node: ${JSON.stringify(node)}`); + const propertyKeys = _.keys(node.properties) + if ( + !_.isEmpty(propertyKeys) && + !arraysEqual(['name', 'salary'], propertyKeys) + ) { + return new Error( + `Unexpected property keys in node: ${JSON.stringify(node)}` + ) } - return null; + return null } - function verifyNodeCount(context) { - const expectedNodeCount = context.createdNodesCount; + function verifyNodeCount (context) { + const expectedNodeCount = context.createdNodesCount - const session = context.driver.session(); + const session = context.driver.session() return session.run('MATCH (n) RETURN count(n)').then(result => { - const record = result.records[0]; - const count = record.get(0).toNumber(); + const record = result.records[0] + const count = record.get(0).toNumber() if (count !== expectedNodeCount) { - throw new Error(`Unexpected node count: ${count}, expected: ${expectedNodeCount}`); + throw new Error( + `Unexpected node count: ${count}, expected: ${expectedNodeCount}` + ) } - }); + }) } - function verifyServers(context) { - const routing = DATABASE_URI.indexOf('bolt+routing') === 0 || DATABASE_URI.indexOf('neo4j') === 0 + function verifyServers (context) { + const routing = + DATABASE_URI.indexOf('bolt+routing') === 0 || + DATABASE_URI.indexOf('neo4j') === 0 if (routing) { - return verifyCausalClusterMembers(context); + return verifyCausalClusterMembers(context) } - return verifySingleInstance(context); + return verifySingleInstance(context) } - function verifySingleInstance(context) { + function verifySingleInstance (context) { return new Promise(resolve => { - const readServerAddresses = context.readServerAddresses(); - const writeServerAddresses = context.writeServerAddresses(); + const readServerAddresses = context.readServerAddresses() + const writeServerAddresses = context.writeServerAddresses() - expect(readServerAddresses.length).toEqual(1); - expect(writeServerAddresses.length).toEqual(1); - expect(readServerAddresses).toEqual(writeServerAddresses); + expect(readServerAddresses.length).toEqual(1) + expect(writeServerAddresses.length).toEqual(1) + expect(readServerAddresses).toEqual(writeServerAddresses) - const address = readServerAddresses[0]; - expect(context.readServersWithQueryCount[address]).toBeGreaterThan(1); - expect(context.writeServersWithQueryCount[address]).toBeGreaterThan(1); + const address = readServerAddresses[0] + expect(context.readServersWithQueryCount[address]).toBeGreaterThan(1) + expect(context.writeServersWithQueryCount[address]).toBeGreaterThan(1) - resolve(); - }); + resolve() + }) } - function verifyCausalClusterMembers(context) { + function verifyCausalClusterMembers (context) { return fetchClusterAddresses(context).then(clusterAddresses => { // before 3.2.0 only read replicas serve reads - const readsOnFollowersEnabled = context.serverVersion.compareTo(VERSION_3_2_0) >= 0; + const readsOnFollowersEnabled = + context.serverVersion.compareTo(VERSION_3_2_0) >= 0 if (readsOnFollowersEnabled) { // expect all followers to serve more than zero read queries - assertAllAddressesServedReadQueries(clusterAddresses.followers, context.readServersWithQueryCount); + assertAllAddressesServedReadQueries( + clusterAddresses.followers, + context.readServersWithQueryCount + ) } // expect all read replicas to serve more than zero read queries - assertAllAddressesServedReadQueries(clusterAddresses.readReplicas, context.readServersWithQueryCount); + assertAllAddressesServedReadQueries( + clusterAddresses.readReplicas, + context.readServersWithQueryCount + ) if (readsOnFollowersEnabled) { // expect all followers to serve same order of magnitude read queries - assertAllAddressesServedSimilarAmountOfReadQueries(clusterAddresses.followers, context.readServersWithQueryCount); + assertAllAddressesServedSimilarAmountOfReadQueries( + clusterAddresses.followers, + context.readServersWithQueryCount + ) } // expect all read replicas to serve same order of magnitude read queries - assertAllAddressesServedSimilarAmountOfReadQueries(clusterAddresses.readReplicas, - context.readServersWithQueryCount); - }); + assertAllAddressesServedSimilarAmountOfReadQueries( + clusterAddresses.readReplicas, + context.readServersWithQueryCount + ) + }) } - function fetchClusterAddresses(context) { - const session = context.driver.session(); + function fetchClusterAddresses (context) { + const session = context.driver.session() return session.run('CALL dbms.cluster.overview()').then(result => { - session.close(); - const records = result.records; + session.close() + const records = result.records - const followers = addressesWithRole(records, 'FOLLOWER'); - const readReplicas = addressesWithRole(records, 'READ_REPLICA'); + const followers = addressesWithRole(records, 'FOLLOWER') + const readReplicas = addressesWithRole(records, 'READ_REPLICA') - return new ClusterAddresses(followers, readReplicas); - }); + return new ClusterAddresses(followers, readReplicas) + }) } - function addressesWithRole(records, role) { - return _.uniq(records.filter(record => record.get('role') === role) - .map(record => record.get('addresses')[0].replace('bolt://', ''))); + function addressesWithRole (records, role) { + return _.uniq( + records + .filter(record => record.get('role') === role) + .map(record => record.get('addresses')[0].replace('bolt://', '')) + ) } - function assertAllAddressesServedReadQueries(addresses, readQueriesByServer) { + function assertAllAddressesServedReadQueries (addresses, readQueriesByServer) { addresses.forEach(address => { - const queries = readQueriesByServer[address]; - expect(queries).toBeGreaterThan(0); - }); + const queries = readQueriesByServer[address] + expect(queries).toBeGreaterThan(0) + }) } - function assertAllAddressesServedSimilarAmountOfReadQueries(addresses, readQueriesByServer) { - const expectedOrderOfMagnitude = orderOfMagnitude(readQueriesByServer[addresses[0]]); + function assertAllAddressesServedSimilarAmountOfReadQueries ( + addresses, + readQueriesByServer + ) { + const expectedOrderOfMagnitude = orderOfMagnitude( + readQueriesByServer[addresses[0]] + ) addresses.forEach(address => { - const queries = readQueriesByServer[address]; - const currentOrderOfMagnitude = orderOfMagnitude(queries); + const queries = readQueriesByServer[address] + const currentOrderOfMagnitude = orderOfMagnitude(queries) - expect(currentOrderOfMagnitude).not.toBeLessThan(expectedOrderOfMagnitude - 1); - expect(currentOrderOfMagnitude).not.toBeGreaterThan(expectedOrderOfMagnitude + 1); - }); + expect(currentOrderOfMagnitude).not.toBeLessThan( + expectedOrderOfMagnitude - 1 + ) + expect(currentOrderOfMagnitude).not.toBeGreaterThan( + expectedOrderOfMagnitude + 1 + ) + }) } - function orderOfMagnitude(number) { - let result = 1; + function orderOfMagnitude (number) { + let result = 1 while (number >= 10) { - number /= 10; - result++; + number /= 10 + result++ } - return result; + return result } - function randomParams() { + function randomParams () { return { name: `Person-${Date.now()}`, salary: Date.now() - }; + } } - function noParams() { - return {}; + function noParams () { + return {} } - function newSession(context, accessMode, useBookmark) { + function newSession (context, accessMode, useBookmark) { if (useBookmark) { - return context.driver.session(accessMode, context.bookmark); + return context.driver.session(accessMode, context.bookmark) } - return context.driver.session(accessMode); + return context.driver.session(accessMode) } - function modeFromEnvOrDefault(envVariableName) { - const modeName = fromEnvOrDefault(envVariableName, 'fast'); - const mode = TEST_MODES[modeName]; + function modeFromEnvOrDefault (envVariableName) { + const modeName = fromEnvOrDefault(envVariableName, 'fast') + const mode = TEST_MODES[modeName] if (!mode) { - throw new Error(`Unknown test mode: ${modeName}`); + throw new Error(`Unknown test mode: ${modeName}`) } - console.log(`Selected '${modeName}' mode for the stress test`); - return mode; + console.log(`Selected '${modeName}' mode for the stress test`) + return mode } - function fromEnvOrDefault(envVariableName, defaultValue) { + function fromEnvOrDefault (envVariableName, defaultValue) { if (process && process.env && process.env[envVariableName]) { - return process.env[envVariableName]; + return process.env[envVariableName] } - return defaultValue; + return defaultValue } - function cleanupDb(driver) { - const session = driver.session(); - return session.run('MATCH (n) DETACH DELETE n').then(() => { - session.close(); - }).catch(error => { - console.log('Error clearing the database: ', error); - }); + function cleanupDb (driver) { + const session = driver.session() + return session + .run('MATCH (n) DETACH DELETE n') + .then(() => { + session.close() + }) + .catch(error => { + console.log('Error clearing the database: ', error) + }) } - function arraysEqual(array1, array2) { - return _.difference(array1, array2).length === 0; + function arraysEqual (array1, array2) { + return _.difference(array1, array2).length === 0 } class Context { - - constructor(driver, loggingEnabled) { - this.driver = driver; - this.bookmark = null; - this.createdNodesCount = 0; - this._commandIdCouter = 0; - this._loggingEnabled = loggingEnabled; - this.readServersWithQueryCount = {}; - this.writeServersWithQueryCount = {}; - this.serverVersion = null; + constructor (driver, loggingEnabled) { + this.driver = driver + this.bookmark = null + this.createdNodesCount = 0 + this._commandIdCouter = 0 + this._loggingEnabled = loggingEnabled + this.readServersWithQueryCount = {} + this.writeServersWithQueryCount = {} + this.serverVersion = null } - queryCompleted(result, accessMode, bookmark) { - const serverInfo = result.summary.server; + queryCompleted (result, accessMode, bookmark) { + const serverInfo = result.summary.server if (!this.serverVersion) { - this.serverVersion = ServerVersion.fromString(serverInfo.version); + this.serverVersion = ServerVersion.fromString(serverInfo.version) } - const serverAddress = serverInfo.address; + const serverAddress = serverInfo.address if (accessMode === WRITE) { - this.createdNodesCount++; - this.writeServersWithQueryCount[serverAddress] = (this.writeServersWithQueryCount[serverAddress] || 0) + 1; + this.createdNodesCount++ + this.writeServersWithQueryCount[serverAddress] = + (this.writeServersWithQueryCount[serverAddress] || 0) + 1 } else { - this.readServersWithQueryCount[serverAddress] = (this.readServersWithQueryCount[serverAddress] || 0) + 1; + this.readServersWithQueryCount[serverAddress] = + (this.readServersWithQueryCount[serverAddress] || 0) + 1 } if (bookmark) { - this.bookmark = bookmark; + this.bookmark = bookmark } } - nextCommandId() { - return this._commandIdCouter++; + nextCommandId () { + return this._commandIdCouter++ } - readServerAddresses() { - return Object.keys(this.readServersWithQueryCount); + readServerAddresses () { + return Object.keys(this.readServersWithQueryCount) } - writeServerAddresses() { - return Object.keys(this.writeServersWithQueryCount); + writeServerAddresses () { + return Object.keys(this.writeServersWithQueryCount) } - log(commandId, message) { + log (commandId, message) { if (this._loggingEnabled) { - console.log(`Command [${commandId}]: ${message}`); + console.log(`Command [${commandId}]: ${message}`) } } } class ClusterAddresses { - - constructor(followers, readReplicas) { - this.followers = followers; - this.readReplicas = readReplicas; + constructor (followers, readReplicas) { + this.followers = followers + this.readReplicas = readReplicas } } - -}); +}) diff --git a/test/v1/summary.test.js b/test/v1/summary.test.js index 34132ca65..bbdd1cf8a 100644 --- a/test/v1/summary.test.js +++ b/test/v1/summary.test.js @@ -17,122 +17,118 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' describe('result summary', () => { - - let driver, session; + let driver, session beforeEach(done => { - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - session = driver.session(); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + session = driver.session() - session.run("MATCH (n) DETACH DELETE n").then(done); - }); + session.run('MATCH (n) DETACH DELETE n').then(done) + }) afterEach(() => { - driver.close(); - }); + driver.close() + }) it('should get result summary', done => { // When & Then session.run("CREATE (p:Person { Name: 'Test'})").then(result => { - let summary = result.summary; - - expect(summary.statement.text).toBe("CREATE (p:Person { Name: 'Test'})"); - expect(summary.statement.parameters).toEqual({}); - - expect(summary.statementType).toBe("w"); - expect(summary.plan).toBe(false); - expect(summary.profile).toBe(false); - expect(summary.notifications).toEqual([]); - expect(summary.resultConsumedAfter).toBeDefined(); - expect(summary.resultAvailableAfter).toBeDefined(); - - let counters = summary.counters; - expect(counters.nodesCreated()).toBe(1); - expect(counters.nodesDeleted()).toBe(0); - expect(counters.relationshipsCreated()).toBe(0); - expect(counters.relationshipsDeleted()).toBe(0); - expect(counters.propertiesSet()).toBe(1); - expect(counters.labelsAdded()).toBe(1); - expect(counters.labelsRemoved()).toBe(0); - expect(counters.indexesAdded()).toBe(0); - expect(counters.indexesRemoved()).toBe(0); - expect(counters.constraintsAdded()).toBe(0); - expect(counters.constraintsRemoved()).toBe(0); - done(); - }); - }); + let summary = result.summary + + expect(summary.statement.text).toBe("CREATE (p:Person { Name: 'Test'})") + expect(summary.statement.parameters).toEqual({}) + + expect(summary.statementType).toBe('w') + expect(summary.plan).toBe(false) + expect(summary.profile).toBe(false) + expect(summary.notifications).toEqual([]) + expect(summary.resultConsumedAfter).toBeDefined() + expect(summary.resultAvailableAfter).toBeDefined() + + let counters = summary.counters + expect(counters.nodesCreated()).toBe(1) + expect(counters.nodesDeleted()).toBe(0) + expect(counters.relationshipsCreated()).toBe(0) + expect(counters.relationshipsDeleted()).toBe(0) + expect(counters.propertiesSet()).toBe(1) + expect(counters.labelsAdded()).toBe(1) + expect(counters.labelsRemoved()).toBe(0) + expect(counters.indexesAdded()).toBe(0) + expect(counters.indexesRemoved()).toBe(0) + expect(counters.constraintsAdded()).toBe(0) + expect(counters.constraintsRemoved()).toBe(0) + done() + }) + }) it('should get plan from summary', done => { - session.run("EXPLAIN MATCH (n) RETURN 1").then(result => { - let summary = result.summary; - expect(summary.plan).toBeDefined(); - expect(summary.profile).toBe(false); - - let plan = summary.plan; - expect(plan.arguments).toBeDefined(); - expect(plan.children).toBeDefined(); - expect(plan.identifiers).toBeDefined(); - expect(plan.operatorType).toBeDefined(); - done(); - }); - }); + session.run('EXPLAIN MATCH (n) RETURN 1').then(result => { + let summary = result.summary + expect(summary.plan).toBeDefined() + expect(summary.profile).toBe(false) + + let plan = summary.plan + expect(plan.arguments).toBeDefined() + expect(plan.children).toBeDefined() + expect(plan.identifiers).toBeDefined() + expect(plan.operatorType).toBeDefined() + done() + }) + }) it('should get profile from summary', done => { - session.run("PROFILE RETURN 1").then(result => { - let summary = result.summary; - expect(summary.plan).toBeDefined(); - expect(summary.profile).toBeDefined(); + session.run('PROFILE RETURN 1').then(result => { + let summary = result.summary + expect(summary.plan).toBeDefined() + expect(summary.profile).toBeDefined() - let profile = summary.profile; - let plan = summary.plan; + let profile = summary.profile + let plan = summary.plan - verifyProfileAndPlanAreEqual(profile, plan); + verifyProfileAndPlanAreEqual(profile, plan) - expect(profile.dbHits).toBe(0); - expect(profile.rows).toBe(1); + expect(profile.dbHits).toBe(0) + expect(profile.rows).toBe(1) - done(); - }); - }); + done() + }) + }) it('should get notifications from summary', done => { - session.run("EXPLAIN MATCH (n), (m) RETURN n, m").then(result => { - let summary = result.summary; - expect(summary.notifications).toBeDefined(); - expect(summary.notifications.length).toBe(1); - let notification = summary.notifications[0]; - - expect(notification.code).toBeDefined(); - expect(notification.title).toBeDefined(); - expect(notification.description).toBeDefined(); - expect(notification.severity).toBeDefined(); - expect(notification.position).toBeDefined(); - - done(); - }); - }); - - function verifyProfileAndPlanAreEqual(profile, plan) { - expect(profile.arguments).toBe(plan.arguments); - expect(profile.identifiers).toBe(plan.identifiers); - expect(profile.operatorType).toBe(plan.operatorType); - - if (!profile.children || !plan.children ) - { - expect(profile.children).toBeUndefined(); - expect(plan.children).toBeUndefined(); - } - else - { - expect(profile.children).toBeDefined(); - expect(plan.children).toBeDefined(); + session.run('EXPLAIN MATCH (n), (m) RETURN n, m').then(result => { + let summary = result.summary + expect(summary.notifications).toBeDefined() + expect(summary.notifications.length).toBe(1) + let notification = summary.notifications[0] + + expect(notification.code).toBeDefined() + expect(notification.title).toBeDefined() + expect(notification.description).toBeDefined() + expect(notification.severity).toBeDefined() + expect(notification.position).toBeDefined() + + done() + }) + }) + + function verifyProfileAndPlanAreEqual (profile, plan) { + expect(profile.arguments).toBe(plan.arguments) + expect(profile.identifiers).toBe(plan.identifiers) + expect(profile.operatorType).toBe(plan.operatorType) + + if (!profile.children || !plan.children) { + expect(profile.children).toBeUndefined() + expect(plan.children).toBeUndefined() + } else { + expect(profile.children).toBeDefined() + expect(plan.children).toBeDefined() // recursively calling the same method to verify they are equal - verifyProfileAndPlanAreEqual(profile.children, plan.children); + verifyProfileAndPlanAreEqual(profile.children, plan.children) } } -}); +}) diff --git a/test/v1/temporal-types.test.js b/test/v1/temporal-types.test.js index 9e97fecbe..03f082aaa 100644 --- a/test/v1/temporal-types.test.js +++ b/test/v1/temporal-types.test.js @@ -17,1179 +17,1812 @@ * limitations under the License. */ -import neo4j from '../../src'; -import sharedNeo4j from '../internal/shared-neo4j'; -import {timeZoneOffsetInSeconds, totalNanoseconds} from '../../src/v1/internal/temporal-util'; -import {ServerVersion, VERSION_3_4_0} from '../../src/v1/internal/server-version'; -import timesSeries from 'async/timesSeries'; -import _ from 'lodash'; -import testUtils from '../internal/test-utils'; - -const RANDOM_VALUES_TO_TEST = 2000; -const MIN_TEMPORAL_ARRAY_LENGTH = 20; -const MAX_TEMPORAL_ARRAY_LENGTH = 1000; +import neo4j from '../../src' +import sharedNeo4j from '../internal/shared-neo4j' +import { + timeZoneOffsetInSeconds, + totalNanoseconds +} from '../../src/v1/internal/temporal-util' +import { + ServerVersion, + VERSION_3_4_0 +} from '../../src/v1/internal/server-version' +import timesSeries from 'async/timesSeries' +import _ from 'lodash' +import testUtils from '../internal/test-utils' + +const RANDOM_VALUES_TO_TEST = 2000 +const MIN_TEMPORAL_ARRAY_LENGTH = 20 +const MAX_TEMPORAL_ARRAY_LENGTH = 1000 /** * Duration in neo4j is limited to `Long.MAX_VALUE` when converted to seconds. * This bound should be used for all components of duration, except nanoseconds. * It's a fairly random large value that allows created duration to not overflow. * @type {number} */ -const MAX_DURATION_COMPONENT = 3000000000000; -const MAX_NANO_OF_SECOND = 999999999; -const MAX_YEAR = 999999999; -const MIN_YEAR = -MAX_YEAR; -const MAX_TIME_ZONE_OFFSET = 64800; -const MIN_TIME_ZONE_OFFSET = -MAX_TIME_ZONE_OFFSET; -const SECONDS_PER_MINUTE = 60; -const MIN_ZONE_ID = 'Etc/GMT+12'; -const MAX_ZONE_ID = 'Etc/GMT-14'; -const ZONE_IDS = ['Europe/Zaporozhye', 'Europe/London', 'UTC', 'Africa/Cairo']; +const MAX_DURATION_COMPONENT = 3000000000000 +const MAX_NANO_OF_SECOND = 999999999 +const MAX_YEAR = 999999999 +const MIN_YEAR = -MAX_YEAR +const MAX_TIME_ZONE_OFFSET = 64800 +const MIN_TIME_ZONE_OFFSET = -MAX_TIME_ZONE_OFFSET +const SECONDS_PER_MINUTE = 60 +const MIN_ZONE_ID = 'Etc/GMT+12' +const MAX_ZONE_ID = 'Etc/GMT-14' +const ZONE_IDS = ['Europe/Zaporozhye', 'Europe/London', 'UTC', 'Africa/Cairo'] describe('temporal-types', () => { - - let originalTimeout; - let driver; - let driverWithNativeNumbers; - let session; - let serverVersion; + let originalTimeout + let driver + let driverWithNativeNumbers + let session + let serverVersion beforeAll(done => { - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000 - driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - driverWithNativeNumbers = neo4j.driver('bolt://localhost', sharedNeo4j.authToken, {disableLosslessIntegers: true}); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + driverWithNativeNumbers = neo4j.driver( + 'bolt://localhost', + sharedNeo4j.authToken, + { disableLosslessIntegers: true } + ) ServerVersion.fromDriver(driver).then(version => { - serverVersion = version; - done(); - }); - }); + serverVersion = version + done() + }) + }) afterAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout if (driver) { - driver.close(); - driver = null; + driver.close() + driver = null } if (driverWithNativeNumbers) { - driverWithNativeNumbers.close(); - driverWithNativeNumbers = null; + driverWithNativeNumbers.close() + driverWithNativeNumbers = null } - }); + }) beforeEach(done => { - session = driver.session(); - session.run('MATCH (n) DETACH DELETE n').then(() => { - done(); - }).catch(error => { - done.fail(error); - }); - }); + session = driver.session() + session + .run('MATCH (n) DETACH DELETE n') + .then(() => { + done() + }) + .catch(error => { + done.fail(error) + }) + }) afterEach(() => { if (session) { - session.close(); - session = null; + session.close() + session = null } - }); + }) it('should receive Duration', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = duration(27, 17, 91, 999); - testReceiveTemporalValue('RETURN duration({years: 2, months: 3, days: 17, seconds: 91, nanoseconds: 999})', expectedValue, done); - }); + const expectedValue = duration(27, 17, 91, 999) + testReceiveTemporalValue( + 'RETURN duration({years: 2, months: 3, days: 17, seconds: 91, nanoseconds: 999})', + expectedValue, + done + ) + }) it('should send and receive random Duration', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomDuration(), done); - }); + testSendAndReceiveRandomTemporalValues(() => randomDuration(), done) + }) it('should send and receive Duration when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - testSendReceiveTemporalValue(new neo4j.types.Duration(4, 15, 931, 99953), done); - }); + testSendReceiveTemporalValue( + new neo4j.types.Duration(4, 15, 931, 99953), + done + ) + }) it('should send and receive array of Duration', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomDuration(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues(() => randomDuration(), done) + }) it('should receive LocalTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = localTime(22, 59, 10, 999999); - testReceiveTemporalValue('RETURN localtime({hour: 22, minute: 59, second: 10, nanosecond: 999999})', expectedValue, done); - }); + const expectedValue = localTime(22, 59, 10, 999999) + testReceiveTemporalValue( + 'RETURN localtime({hour: 22, minute: 59, second: 10, nanosecond: 999999})', + expectedValue, + done + ) + }) it('should send and receive max LocalTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const maxLocalTime = localTime(23, 59, 59, MAX_NANO_OF_SECOND); - testSendReceiveTemporalValue(maxLocalTime, done); - }); + const maxLocalTime = localTime(23, 59, 59, MAX_NANO_OF_SECOND) + testSendReceiveTemporalValue(maxLocalTime, done) + }) it('should send and receive min LocalTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const minLocalTime = localTime(0, 0, 0, 0); - testSendReceiveTemporalValue(minLocalTime, done); - }); + const minLocalTime = localTime(0, 0, 0, 0) + testSendReceiveTemporalValue(minLocalTime, done) + }) it('should send and receive LocalTime when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - testSendReceiveTemporalValue(new neo4j.types.LocalTime(12, 32, 56, 12345), done); - }); + testSendReceiveTemporalValue( + new neo4j.types.LocalTime(12, 32, 56, 12345), + done + ) + }) it('should send and receive random LocalTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomLocalTime(), done); - }); + testSendAndReceiveRandomTemporalValues(() => randomLocalTime(), done) + }) it('should send and receive array of LocalTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomLocalTime(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues(() => randomLocalTime(), done) + }) it('should receive Time', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = time(11, 42, 59, 9999, -30600); - testReceiveTemporalValue('RETURN time({hour: 11, minute: 42, second: 59, nanosecond: 9999, timezone:"-08:30"})', expectedValue, done); - }); + const expectedValue = time(11, 42, 59, 9999, -30600) + testReceiveTemporalValue( + 'RETURN time({hour: 11, minute: 42, second: 59, nanosecond: 9999, timezone:"-08:30"})', + expectedValue, + done + ) + }) it('should send and receive max Time', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const maxTime = time(23, 59, 59, MAX_NANO_OF_SECOND, MAX_TIME_ZONE_OFFSET); - testSendReceiveTemporalValue(maxTime, done); - }); + const maxTime = time(23, 59, 59, MAX_NANO_OF_SECOND, MAX_TIME_ZONE_OFFSET) + testSendReceiveTemporalValue(maxTime, done) + }) it('should send and receive min Time', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const minTime = time(0, 0, 0, 0, MIN_TIME_ZONE_OFFSET); - testSendReceiveTemporalValue(minTime, done); - }); + const minTime = time(0, 0, 0, 0, MIN_TIME_ZONE_OFFSET) + testSendReceiveTemporalValue(minTime, done) + }) it('should send and receive Time when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - testSendReceiveTemporalValue(new neo4j.types.Time(22, 19, 32, 18381, MAX_TIME_ZONE_OFFSET), done); - }); + testSendReceiveTemporalValue( + new neo4j.types.Time(22, 19, 32, 18381, MAX_TIME_ZONE_OFFSET), + done + ) + }) it('should send and receive random Time', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomTime(), done); - }); + testSendAndReceiveRandomTemporalValues(() => randomTime(), done) + }) it('should send and receive array of Time', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomTime(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues(() => randomTime(), done) + }) it('should receive Date', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = date(1995, 7, 28); - testReceiveTemporalValue('RETURN date({year: 1995, month: 7, day: 28})', expectedValue, done); - }); + const expectedValue = date(1995, 7, 28) + testReceiveTemporalValue( + 'RETURN date({year: 1995, month: 7, day: 28})', + expectedValue, + done + ) + }) it('should send and receive max Date', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const maxDate = date(MAX_YEAR, 12, 31); - testSendReceiveTemporalValue(maxDate, done); - }); + const maxDate = date(MAX_YEAR, 12, 31) + testSendReceiveTemporalValue(maxDate, done) + }) it('should send and receive min Date', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const minDate = date(MIN_YEAR, 1, 1); - testSendReceiveTemporalValue(minDate, done); - }); + const minDate = date(MIN_YEAR, 1, 1) + testSendReceiveTemporalValue(minDate, done) + }) it('should send and receive Date when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - testSendReceiveTemporalValue(new neo4j.types.Date(1923, 8, 14), done); - }); + testSendReceiveTemporalValue(new neo4j.types.Date(1923, 8, 14), done) + }) it('should send and receive random Date', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomDate(), done); - }); + testSendAndReceiveRandomTemporalValues(() => randomDate(), done) + }) it('should send and receive array of Date', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomDate(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues(() => randomDate(), done) + }) it('should receive LocalDateTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = localDateTime(1869, 9, 23, 18, 29, 59, 12349); - testReceiveTemporalValue('RETURN localdatetime({year: 1869, month: 9, day: 23, hour: 18, minute: 29, second: 59, nanosecond: 12349})', expectedValue, done); - }); + const expectedValue = localDateTime(1869, 9, 23, 18, 29, 59, 12349) + testReceiveTemporalValue( + 'RETURN localdatetime({year: 1869, month: 9, day: 23, hour: 18, minute: 29, second: 59, nanosecond: 12349})', + expectedValue, + done + ) + }) it('should send and receive max LocalDateTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const maxLocalDateTime = localDateTime(MAX_YEAR, 12, 31, 23, 59, 59, MAX_NANO_OF_SECOND); - testSendReceiveTemporalValue(maxLocalDateTime, done); - }); + const maxLocalDateTime = localDateTime( + MAX_YEAR, + 12, + 31, + 23, + 59, + 59, + MAX_NANO_OF_SECOND + ) + testSendReceiveTemporalValue(maxLocalDateTime, done) + }) it('should send and receive min LocalDateTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const minLocalDateTime = localDateTime(MIN_YEAR, 1, 1, 0, 0, 0, 0); - testSendReceiveTemporalValue(minLocalDateTime, done); - }); + const minLocalDateTime = localDateTime(MIN_YEAR, 1, 1, 0, 0, 0, 0) + testSendReceiveTemporalValue(minLocalDateTime, done) + }) it('should send and receive LocalDateTime when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - testSendReceiveTemporalValue(new neo4j.types.LocalDateTime(2045, 9, 1, 11, 25, 25, 911), done); - }); + testSendReceiveTemporalValue( + new neo4j.types.LocalDateTime(2045, 9, 1, 11, 25, 25, 911), + done + ) + }) it('should send and receive random LocalDateTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomLocalDateTime(), done); - }); + testSendAndReceiveRandomTemporalValues(() => randomLocalDateTime(), done) + }) it('should send and receive random LocalDateTime', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomLocalDateTime(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues( + () => randomLocalDateTime(), + done + ) + }) it('should receive DateTime with time zone offset', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = dateTimeWithZoneOffset(1992, 11, 24, 9, 55, 42, 999, 18000); - testReceiveTemporalValue('RETURN datetime({year: 1992, month: 11, day: 24, hour: 9, minute: 55, second: 42, nanosecond: 999, timezone: "+05:00"})', expectedValue, done); - }); + const expectedValue = dateTimeWithZoneOffset( + 1992, + 11, + 24, + 9, + 55, + 42, + 999, + 18000 + ) + testReceiveTemporalValue( + 'RETURN datetime({year: 1992, month: 11, day: 24, hour: 9, minute: 55, second: 42, nanosecond: 999, timezone: "+05:00"})', + expectedValue, + done + ) + }) it('should send and receive max DateTime with zone offset', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const maxDateTime = dateTimeWithZoneOffset(MAX_YEAR, 12, 31, 23, 59, 59, MAX_NANO_OF_SECOND, MAX_TIME_ZONE_OFFSET); - testSendReceiveTemporalValue(maxDateTime, done); - }); + const maxDateTime = dateTimeWithZoneOffset( + MAX_YEAR, + 12, + 31, + 23, + 59, + 59, + MAX_NANO_OF_SECOND, + MAX_TIME_ZONE_OFFSET + ) + testSendReceiveTemporalValue(maxDateTime, done) + }) it('should send and receive min DateTime with zone offset', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const minDateTime = dateTimeWithZoneOffset(MIN_YEAR, 1, 1, 0, 0, 0, 0, MAX_TIME_ZONE_OFFSET); - testSendReceiveTemporalValue(minDateTime, done); - }); + const minDateTime = dateTimeWithZoneOffset( + MIN_YEAR, + 1, + 1, + 0, + 0, + 0, + 0, + MAX_TIME_ZONE_OFFSET + ) + testSendReceiveTemporalValue(minDateTime, done) + }) it('should send and receive DateTime with zone offset when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); - - testSendReceiveTemporalValue(new neo4j.types.DateTime(2022, 2, 7, 17, 15, 59, 12399, MAX_TIME_ZONE_OFFSET, null), done); - }); + session = driverWithNativeNumbers.session() + + testSendReceiveTemporalValue( + new neo4j.types.DateTime( + 2022, + 2, + 7, + 17, + 15, + 59, + 12399, + MAX_TIME_ZONE_OFFSET, + null + ), + done + ) + }) it('should send and receive random DateTime with zone offset', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomDateTimeWithZoneOffset(), done); - }); + testSendAndReceiveRandomTemporalValues( + () => randomDateTimeWithZoneOffset(), + done + ) + }) it('should send and receive array of DateTime with zone offset', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomDateTimeWithZoneOffset(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues( + () => randomDateTimeWithZoneOffset(), + done + ) + }) it('should receive DateTime with zone id', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const expectedValue = dateTimeWithZoneId(1992, 11, 24, 9, 55, 42, 999, 'Europe/Stockholm'); - testReceiveTemporalValue('RETURN datetime({year: 1992, month: 11, day: 24, hour: 9, minute: 55, second: 42, nanosecond: 999, timezone: "Europe/Stockholm"})', expectedValue, done); - }); + const expectedValue = dateTimeWithZoneId( + 1992, + 11, + 24, + 9, + 55, + 42, + 999, + 'Europe/Stockholm' + ) + testReceiveTemporalValue( + 'RETURN datetime({year: 1992, month: 11, day: 24, hour: 9, minute: 55, second: 42, nanosecond: 999, timezone: "Europe/Stockholm"})', + expectedValue, + done + ) + }) it('should send and receive max DateTime with zone id', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const maxDateTime = dateTimeWithZoneId(MAX_YEAR, 12, 31, 23, 59, 59, MAX_NANO_OF_SECOND, MAX_ZONE_ID); - testSendReceiveTemporalValue(maxDateTime, done); - }); + const maxDateTime = dateTimeWithZoneId( + MAX_YEAR, + 12, + 31, + 23, + 59, + 59, + MAX_NANO_OF_SECOND, + MAX_ZONE_ID + ) + testSendReceiveTemporalValue(maxDateTime, done) + }) it('should send and receive min DateTime with zone id', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - const minDateTime = dateTimeWithZoneId(MIN_YEAR, 1, 1, 0, 0, 0, 0, MIN_ZONE_ID); - testSendReceiveTemporalValue(minDateTime, done); - }); + const minDateTime = dateTimeWithZoneId( + MIN_YEAR, + 1, + 1, + 0, + 0, + 0, + 0, + MIN_ZONE_ID + ) + testSendReceiveTemporalValue(minDateTime, done) + }) it('should send and receive DateTime with zone id when disableLosslessIntegers=true', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - session = driverWithNativeNumbers.session(); - - testSendReceiveTemporalValue(new neo4j.types.DateTime(2011, 11, 25, 23, 59, 59, 192378, null, 'Europe/Stockholm'), done); - }); + session = driverWithNativeNumbers.session() + + testSendReceiveTemporalValue( + new neo4j.types.DateTime( + 2011, + 11, + 25, + 23, + 59, + 59, + 192378, + null, + 'Europe/Stockholm' + ), + done + ) + }) it('should send and receive random DateTime with zone id', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveRandomTemporalValues(() => randomDateTimeWithZoneId(), done); - }); + testSendAndReceiveRandomTemporalValues( + () => randomDateTimeWithZoneId(), + done + ) + }) it('should send and receive array of DateTime with zone id', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testSendAndReceiveArrayOfRandomTemporalValues(() => randomDateTimeWithZoneId(), done); - }); + testSendAndReceiveArrayOfRandomTemporalValues( + () => randomDateTimeWithZoneId(), + done + ) + }) it('should convert Duration to ISO string', () => { - expect(duration(13, 62, 3, 999111999).toString()).toEqual('P13M62DT3.999111999S'); - expect(duration(0, 0, 0, 0).toString()).toEqual('P0M0DT0S'); - expect(duration(-1, -2, 10, 10).toString()).toEqual('P-1M-2DT10.000000010S'); - }); + expect(duration(13, 62, 3, 999111999).toString()).toEqual( + 'P13M62DT3.999111999S' + ) + expect(duration(0, 0, 0, 0).toString()).toEqual('P0M0DT0S') + expect(duration(-1, -2, 10, 10).toString()).toEqual('P-1M-2DT10.000000010S') + }) it('should convert LocalTime to ISO string', () => { - expect(localTime(12, 19, 39, 111222333).toString()).toEqual('12:19:39.111222333'); - expect(localTime(3, 59, 2, 17).toString()).toEqual('03:59:02.000000017'); - expect(localTime(0, 0, 0, 0).toString()).toEqual('00:00:00'); - }); + expect(localTime(12, 19, 39, 111222333).toString()).toEqual( + '12:19:39.111222333' + ) + expect(localTime(3, 59, 2, 17).toString()).toEqual('03:59:02.000000017') + expect(localTime(0, 0, 0, 0).toString()).toEqual('00:00:00') + }) it('should convert Time to ISO string', () => { - expect(time(11, 45, 22, 333222111, 9015).toString()).toEqual('11:45:22.333222111+02:30:15'); - expect(time(23, 2, 1, 10, 0).toString()).toEqual('23:02:01.000000010Z'); - expect(time(0, 12, 59, 0, -40500).toString()).toEqual('00:12:59-11:15'); - expect(time(21, 59, 0, 123, -25200).toString()).toEqual('21:59:00.000000123-07:00'); - }); + expect(time(11, 45, 22, 333222111, 9015).toString()).toEqual( + '11:45:22.333222111+02:30:15' + ) + expect(time(23, 2, 1, 10, 0).toString()).toEqual('23:02:01.000000010Z') + expect(time(0, 12, 59, 0, -40500).toString()).toEqual('00:12:59-11:15') + expect(time(21, 59, 0, 123, -25200).toString()).toEqual( + '21:59:00.000000123-07:00' + ) + }) it('should convert Date to ISO string', () => { - expect(date(2015, 10, 12).toString()).toEqual('2015-10-12'); - expect(date(881, 1, 1).toString()).toEqual('0881-01-01'); - expect(date(-999, 12, 24).toString()).toEqual('-0999-12-24'); - expect(date(-9, 1, 1).toString()).toEqual('-0009-01-01'); - }); + expect(date(2015, 10, 12).toString()).toEqual('2015-10-12') + expect(date(881, 1, 1).toString()).toEqual('0881-01-01') + expect(date(-999, 12, 24).toString()).toEqual('-0999-12-24') + expect(date(-9, 1, 1).toString()).toEqual('-0009-01-01') + }) it('should convert LocalDateTime to ISO string', () => { - expect(localDateTime(1992, 11, 8, 9, 42, 17, 22).toString()).toEqual('1992-11-08T09:42:17.000000022'); - expect(localDateTime(-10, 7, 15, 8, 15, 33, 500).toString()).toEqual('-0010-07-15T08:15:33.000000500'); - expect(localDateTime(0, 1, 1, 0, 0, 0, 1).toString()).toEqual('0000-01-01T00:00:00.000000001'); - }); + expect(localDateTime(1992, 11, 8, 9, 42, 17, 22).toString()).toEqual( + '1992-11-08T09:42:17.000000022' + ) + expect(localDateTime(-10, 7, 15, 8, 15, 33, 500).toString()).toEqual( + '-0010-07-15T08:15:33.000000500' + ) + expect(localDateTime(0, 1, 1, 0, 0, 0, 1).toString()).toEqual( + '0000-01-01T00:00:00.000000001' + ) + }) it('should convert DateTime with time zone offset to ISO string', () => { - expect(dateTimeWithZoneOffset(2025, 9, 17, 23, 22, 21, 999888, 37800).toString()).toEqual('2025-09-17T23:22:21.000999888+10:30'); - expect(dateTimeWithZoneOffset(1, 2, 3, 4, 5, 6, 7, -49376).toString()).toEqual('0001-02-03T04:05:06.000000007-13:42:56'); - expect(dateTimeWithZoneOffset(-3, 3, 9, 9, 33, 27, 999000, 15300).toString()).toEqual('-0003-03-09T09:33:27.000999000+04:15'); - }); + expect( + dateTimeWithZoneOffset(2025, 9, 17, 23, 22, 21, 999888, 37800).toString() + ).toEqual('2025-09-17T23:22:21.000999888+10:30') + expect( + dateTimeWithZoneOffset(1, 2, 3, 4, 5, 6, 7, -49376).toString() + ).toEqual('0001-02-03T04:05:06.000000007-13:42:56') + expect( + dateTimeWithZoneOffset(-3, 3, 9, 9, 33, 27, 999000, 15300).toString() + ).toEqual('-0003-03-09T09:33:27.000999000+04:15') + }) it('should convert DateTime with time zone id to ISO-like string', () => { - expect(dateTimeWithZoneId(1949, 10, 7, 6, 10, 15, 15000000, 'Europe/Zaporozhye').toString()).toEqual('1949-10-07T06:10:15.015000000[Europe/Zaporozhye]'); - expect(dateTimeWithZoneId(-30455, 5, 5, 12, 24, 10, 123, 'Asia/Yangon').toString()).toEqual('-30455-05-05T12:24:10.000000123[Asia/Yangon]'); - expect(dateTimeWithZoneId(248, 12, 30, 23, 59, 59, 3, 'CET').toString()).toEqual('0248-12-30T23:59:59.000000003[CET]'); - }); + expect( + dateTimeWithZoneId( + 1949, + 10, + 7, + 6, + 10, + 15, + 15000000, + 'Europe/Zaporozhye' + ).toString() + ).toEqual('1949-10-07T06:10:15.015000000[Europe/Zaporozhye]') + expect( + dateTimeWithZoneId( + -30455, + 5, + 5, + 12, + 24, + 10, + 123, + 'Asia/Yangon' + ).toString() + ).toEqual('-30455-05-05T12:24:10.000000123[Asia/Yangon]') + expect( + dateTimeWithZoneId(248, 12, 30, 23, 59, 59, 3, 'CET').toString() + ).toEqual('0248-12-30T23:59:59.000000003[CET]') + }) it('should expose local time components in time', () => { - const offsetTime = time(22, 12, 58, 999111222, 42); + const offsetTime = time(22, 12, 58, 999111222, 42) - expect(offsetTime.hour).toEqual(neo4j.int(22)); - expect(offsetTime.minute).toEqual(neo4j.int(12)); - expect(offsetTime.second).toEqual(neo4j.int(58)); - expect(offsetTime.nanosecond).toEqual(neo4j.int(999111222)); - }); + expect(offsetTime.hour).toEqual(neo4j.int(22)) + expect(offsetTime.minute).toEqual(neo4j.int(12)) + expect(offsetTime.second).toEqual(neo4j.int(58)) + expect(offsetTime.nanosecond).toEqual(neo4j.int(999111222)) + }) it('should expose local date and time components in local date-time', () => { - const dateTime = localDateTime(2025, 9, 18, 23, 22, 21, 2020); + const dateTime = localDateTime(2025, 9, 18, 23, 22, 21, 2020) - expect(dateTime.year).toEqual(neo4j.int(2025)); - expect(dateTime.month).toEqual(neo4j.int(9)); - expect(dateTime.day).toEqual(neo4j.int(18)); + expect(dateTime.year).toEqual(neo4j.int(2025)) + expect(dateTime.month).toEqual(neo4j.int(9)) + expect(dateTime.day).toEqual(neo4j.int(18)) - expect(dateTime.hour).toEqual(neo4j.int(23)); - expect(dateTime.minute).toEqual(neo4j.int(22)); - expect(dateTime.second).toEqual(neo4j.int(21)); - expect(dateTime.nanosecond).toEqual(neo4j.int(2020)); - }); + expect(dateTime.hour).toEqual(neo4j.int(23)) + expect(dateTime.minute).toEqual(neo4j.int(22)) + expect(dateTime.second).toEqual(neo4j.int(21)) + expect(dateTime.nanosecond).toEqual(neo4j.int(2020)) + }) it('should expose local date-time components in date-time with zone offset', () => { - const zonedDateTime = dateTimeWithZoneOffset(1799, 5, 19, 18, 37, 59, 875387, 3600); - - expect(zonedDateTime.year).toEqual(neo4j.int(1799)); - expect(zonedDateTime.month).toEqual(neo4j.int(5)); - expect(zonedDateTime.day).toEqual(neo4j.int(19)); - - expect(zonedDateTime.hour).toEqual(neo4j.int(18)); - expect(zonedDateTime.minute).toEqual(neo4j.int(37)); - expect(zonedDateTime.second).toEqual(neo4j.int(59)); - expect(zonedDateTime.nanosecond).toEqual(neo4j.int(875387)); - }); + const zonedDateTime = dateTimeWithZoneOffset( + 1799, + 5, + 19, + 18, + 37, + 59, + 875387, + 3600 + ) + + expect(zonedDateTime.year).toEqual(neo4j.int(1799)) + expect(zonedDateTime.month).toEqual(neo4j.int(5)) + expect(zonedDateTime.day).toEqual(neo4j.int(19)) + + expect(zonedDateTime.hour).toEqual(neo4j.int(18)) + expect(zonedDateTime.minute).toEqual(neo4j.int(37)) + expect(zonedDateTime.second).toEqual(neo4j.int(59)) + expect(zonedDateTime.nanosecond).toEqual(neo4j.int(875387)) + }) it('should expose local date-time components in date-time with zone ID', () => { - const zonedDateTime = dateTimeWithZoneId(2356, 7, 29, 23, 32, 11, 9346458, randomZoneId()); - - expect(zonedDateTime.year).toEqual(neo4j.int(2356)); - expect(zonedDateTime.month).toEqual(neo4j.int(7)); - expect(zonedDateTime.day).toEqual(neo4j.int(29)); - - expect(zonedDateTime.hour).toEqual(neo4j.int(23)); - expect(zonedDateTime.minute).toEqual(neo4j.int(32)); - expect(zonedDateTime.second).toEqual(neo4j.int(11)); - expect(zonedDateTime.nanosecond).toEqual(neo4j.int(9346458)); - }); + const zonedDateTime = dateTimeWithZoneId( + 2356, + 7, + 29, + 23, + 32, + 11, + 9346458, + randomZoneId() + ) + + expect(zonedDateTime.year).toEqual(neo4j.int(2356)) + expect(zonedDateTime.month).toEqual(neo4j.int(7)) + expect(zonedDateTime.day).toEqual(neo4j.int(29)) + + expect(zonedDateTime.hour).toEqual(neo4j.int(23)) + expect(zonedDateTime.minute).toEqual(neo4j.int(32)) + expect(zonedDateTime.second).toEqual(neo4j.int(11)) + expect(zonedDateTime.nanosecond).toEqual(neo4j.int(9346458)) + }) it('should format duration to string', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } - testDurationToString([ - {duration: duration(0, 0, 0, 0), expectedString: 'P0M0DT0S'}, - - {duration: duration(0, 0, 42, 0), expectedString: 'P0M0DT42S'}, - {duration: duration(0, 0, -42, 0), expectedString: 'P0M0DT-42S'}, - {duration: duration(0, 0, 1, 0), expectedString: 'P0M0DT1S'}, - {duration: duration(0, 0, -1, 0), expectedString: 'P0M0DT-1S'}, - - {duration: duration(0, 0, 0, 5), expectedString: 'P0M0DT0.000000005S'}, - {duration: duration(0, 0, 0, -5), expectedString: 'P0M0DT-0.000000005S'}, - {duration: duration(0, 0, 0, 999999999), expectedString: 'P0M0DT0.999999999S'}, - {duration: duration(0, 0, 0, -999999999), expectedString: 'P0M0DT-0.999999999S'}, - - {duration: duration(0, 0, 1, 5), expectedString: 'P0M0DT1.000000005S'}, - {duration: duration(0, 0, -1, -5), expectedString: 'P0M0DT-1.000000005S'}, - {duration: duration(0, 0, 1, -5), expectedString: 'P0M0DT0.999999995S'}, - {duration: duration(0, 0, -1, 5), expectedString: 'P0M0DT-0.999999995S'}, - {duration: duration(0, 0, 1, 999999999), expectedString: 'P0M0DT1.999999999S'}, - {duration: duration(0, 0, -1, -999999999), expectedString: 'P0M0DT-1.999999999S'}, - {duration: duration(0, 0, 1, -999999999), expectedString: 'P0M0DT0.000000001S'}, - {duration: duration(0, 0, -1, 999999999), expectedString: 'P0M0DT-0.000000001S'}, - - {duration: duration(0, 0, 28, 9), expectedString: 'P0M0DT28.000000009S'}, - {duration: duration(0, 0, -28, 9), expectedString: 'P0M0DT-27.999999991S'}, - {duration: duration(0, 0, 28, -9), expectedString: 'P0M0DT27.999999991S'}, - {duration: duration(0, 0, -28, -9), expectedString: 'P0M0DT-28.000000009S'}, - - {duration: duration(0, 0, -78036, -143000000), expectedString: 'P0M0DT-78036.143000000S'}, - - {duration: duration(0, 0, 0, 1000000000), expectedString: 'P0M0DT1S'}, - {duration: duration(0, 0, 0, -1000000000), expectedString: 'P0M0DT-1S'}, - {duration: duration(0, 0, 0, 1000000007), expectedString: 'P0M0DT1.000000007S'}, - {duration: duration(0, 0, 0, -1000000007), expectedString: 'P0M0DT-1.000000007S'}, - - {duration: duration(0, 0, 40, 2123456789), expectedString: 'P0M0DT42.123456789S'}, - {duration: duration(0, 0, -40, 2123456789), expectedString: 'P0M0DT-37.876543211S'}, - {duration: duration(0, 0, 40, -2123456789), expectedString: 'P0M0DT37.876543211S'}, - {duration: duration(0, 0, -40, -2123456789), expectedString: 'P0M0DT-42.123456789S'} - ], done); - }); + testDurationToString( + [ + { duration: duration(0, 0, 0, 0), expectedString: 'P0M0DT0S' }, + + { duration: duration(0, 0, 42, 0), expectedString: 'P0M0DT42S' }, + { duration: duration(0, 0, -42, 0), expectedString: 'P0M0DT-42S' }, + { duration: duration(0, 0, 1, 0), expectedString: 'P0M0DT1S' }, + { duration: duration(0, 0, -1, 0), expectedString: 'P0M0DT-1S' }, + + { + duration: duration(0, 0, 0, 5), + expectedString: 'P0M0DT0.000000005S' + }, + { + duration: duration(0, 0, 0, -5), + expectedString: 'P0M0DT-0.000000005S' + }, + { + duration: duration(0, 0, 0, 999999999), + expectedString: 'P0M0DT0.999999999S' + }, + { + duration: duration(0, 0, 0, -999999999), + expectedString: 'P0M0DT-0.999999999S' + }, + + { + duration: duration(0, 0, 1, 5), + expectedString: 'P0M0DT1.000000005S' + }, + { + duration: duration(0, 0, -1, -5), + expectedString: 'P0M0DT-1.000000005S' + }, + { + duration: duration(0, 0, 1, -5), + expectedString: 'P0M0DT0.999999995S' + }, + { + duration: duration(0, 0, -1, 5), + expectedString: 'P0M0DT-0.999999995S' + }, + { + duration: duration(0, 0, 1, 999999999), + expectedString: 'P0M0DT1.999999999S' + }, + { + duration: duration(0, 0, -1, -999999999), + expectedString: 'P0M0DT-1.999999999S' + }, + { + duration: duration(0, 0, 1, -999999999), + expectedString: 'P0M0DT0.000000001S' + }, + { + duration: duration(0, 0, -1, 999999999), + expectedString: 'P0M0DT-0.000000001S' + }, + + { + duration: duration(0, 0, 28, 9), + expectedString: 'P0M0DT28.000000009S' + }, + { + duration: duration(0, 0, -28, 9), + expectedString: 'P0M0DT-27.999999991S' + }, + { + duration: duration(0, 0, 28, -9), + expectedString: 'P0M0DT27.999999991S' + }, + { + duration: duration(0, 0, -28, -9), + expectedString: 'P0M0DT-28.000000009S' + }, + + { + duration: duration(0, 0, -78036, -143000000), + expectedString: 'P0M0DT-78036.143000000S' + }, + + { duration: duration(0, 0, 0, 1000000000), expectedString: 'P0M0DT1S' }, + { + duration: duration(0, 0, 0, -1000000000), + expectedString: 'P0M0DT-1S' + }, + { + duration: duration(0, 0, 0, 1000000007), + expectedString: 'P0M0DT1.000000007S' + }, + { + duration: duration(0, 0, 0, -1000000007), + expectedString: 'P0M0DT-1.000000007S' + }, + + { + duration: duration(0, 0, 40, 2123456789), + expectedString: 'P0M0DT42.123456789S' + }, + { + duration: duration(0, 0, -40, 2123456789), + expectedString: 'P0M0DT-37.876543211S' + }, + { + duration: duration(0, 0, 40, -2123456789), + expectedString: 'P0M0DT37.876543211S' + }, + { + duration: duration(0, 0, -40, -2123456789), + expectedString: 'P0M0DT-42.123456789S' + } + ], + done + ) + }) it('should normalize created duration', () => { - const duration1 = duration(0, 0, 1, 1000000000); - expect(duration1.seconds).toEqual(neo4j.int(2)); - expect(duration1.nanoseconds).toEqual(neo4j.int(0)); + const duration1 = duration(0, 0, 1, 1000000000) + expect(duration1.seconds).toEqual(neo4j.int(2)) + expect(duration1.nanoseconds).toEqual(neo4j.int(0)) - const duration2 = duration(0, 0, 42, 1000000001); - expect(duration2.seconds).toEqual(neo4j.int(43)); - expect(duration2.nanoseconds).toEqual(neo4j.int(1)); + const duration2 = duration(0, 0, 42, 1000000001) + expect(duration2.seconds).toEqual(neo4j.int(43)) + expect(duration2.nanoseconds).toEqual(neo4j.int(1)) - const duration3 = duration(0, 0, 42, 42999111222); - expect(duration3.seconds).toEqual(neo4j.int(84)); - expect(duration3.nanoseconds).toEqual(neo4j.int(999111222)); + const duration3 = duration(0, 0, 42, 42999111222) + expect(duration3.seconds).toEqual(neo4j.int(84)) + expect(duration3.nanoseconds).toEqual(neo4j.int(999111222)) - const duration4 = duration(0, 0, 1, -1000000000); - expect(duration4.seconds).toEqual(neo4j.int(0)); - expect(duration4.nanoseconds).toEqual(neo4j.int(0)); + const duration4 = duration(0, 0, 1, -1000000000) + expect(duration4.seconds).toEqual(neo4j.int(0)) + expect(duration4.nanoseconds).toEqual(neo4j.int(0)) - const duration5 = duration(0, 0, 1, -1000000001); - expect(duration5.seconds).toEqual(neo4j.int(-1)); - expect(duration5.nanoseconds).toEqual(neo4j.int(999999999)); + const duration5 = duration(0, 0, 1, -1000000001) + expect(duration5.seconds).toEqual(neo4j.int(-1)) + expect(duration5.nanoseconds).toEqual(neo4j.int(999999999)) - const duration6 = duration(0, 0, 40, -12123456999); - expect(duration6.seconds).toEqual(neo4j.int(27)); - expect(duration6.nanoseconds).toEqual(neo4j.int(876543001)); - }); + const duration6 = duration(0, 0, 40, -12123456999) + expect(duration6.seconds).toEqual(neo4j.int(27)) + expect(duration6.nanoseconds).toEqual(neo4j.int(876543001)) + }) it('should validate types of constructor arguments for Duration', () => { - expect(() => new neo4j.types.Duration('1', 2, 3, 4)).toThrowError(TypeError); - expect(() => new neo4j.types.Duration(1, '2', 3, 4)).toThrowError(TypeError); - expect(() => new neo4j.types.Duration(1, 2, [3], 4)).toThrowError(TypeError); - expect(() => new neo4j.types.Duration(1, 2, 3, {value: 4})).toThrowError(TypeError); - expect(() => new neo4j.types.Duration({months: 1, days: 2, seconds: 3, nanoseconds: 4})).toThrowError(TypeError); - }); + expect(() => new neo4j.types.Duration('1', 2, 3, 4)).toThrowError(TypeError) + expect(() => new neo4j.types.Duration(1, '2', 3, 4)).toThrowError(TypeError) + expect(() => new neo4j.types.Duration(1, 2, [3], 4)).toThrowError(TypeError) + expect(() => new neo4j.types.Duration(1, 2, 3, { value: 4 })).toThrowError( + TypeError + ) + expect( + () => + new neo4j.types.Duration({ + months: 1, + days: 2, + seconds: 3, + nanoseconds: 4 + }) + ).toThrowError(TypeError) + }) it('should validate types of constructor arguments for LocalTime', () => { - expect(() => new neo4j.types.LocalTime('1', 2, 3, 4)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalTime(1, '2', 3, 4)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalTime(1, 2, [3], 4)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalTime(1, 2, 3, {value: 4})).toThrowError(TypeError); - expect(() => new neo4j.types.LocalTime({hour: 1, minute: 2, seconds: 3, nanosecond: 4})).toThrowError(TypeError); - }); + expect(() => new neo4j.types.LocalTime('1', 2, 3, 4)).toThrowError( + TypeError + ) + expect(() => new neo4j.types.LocalTime(1, '2', 3, 4)).toThrowError( + TypeError + ) + expect(() => new neo4j.types.LocalTime(1, 2, [3], 4)).toThrowError( + TypeError + ) + expect(() => new neo4j.types.LocalTime(1, 2, 3, { value: 4 })).toThrowError( + TypeError + ) + expect( + () => + new neo4j.types.LocalTime({ + hour: 1, + minute: 2, + seconds: 3, + nanosecond: 4 + }) + ).toThrowError(TypeError) + }) it('should validate types of constructor arguments for Time', () => { - expect(() => new neo4j.types.Time('1', 2, 3, 4, 5)).toThrowError(TypeError); - expect(() => new neo4j.types.Time(1, '2', 3, 4, 5)).toThrowError(TypeError); - expect(() => new neo4j.types.Time(1, 2, [3], 4, 5)).toThrowError(TypeError); - expect(() => new neo4j.types.Time(1, 2, 3, {value: 4}, 5)).toThrowError(TypeError); - expect(() => new neo4j.types.Time(1, 2, 3, 4, () => 5)).toThrowError(TypeError); - expect(() => new neo4j.types.Time({hour: 1, minute: 2, seconds: 3, nanosecond: 4, timeZoneOffsetSeconds: 5})).toThrowError(TypeError); - }); + expect(() => new neo4j.types.Time('1', 2, 3, 4, 5)).toThrowError(TypeError) + expect(() => new neo4j.types.Time(1, '2', 3, 4, 5)).toThrowError(TypeError) + expect(() => new neo4j.types.Time(1, 2, [3], 4, 5)).toThrowError(TypeError) + expect(() => new neo4j.types.Time(1, 2, 3, { value: 4 }, 5)).toThrowError( + TypeError + ) + expect(() => new neo4j.types.Time(1, 2, 3, 4, () => 5)).toThrowError( + TypeError + ) + expect( + () => + new neo4j.types.Time({ + hour: 1, + minute: 2, + seconds: 3, + nanosecond: 4, + timeZoneOffsetSeconds: 5 + }) + ).toThrowError(TypeError) + }) it('should validate types of constructor arguments for Date', () => { - expect(() => new neo4j.types.Date('1', 2, 3)).toThrowError(TypeError); - expect(() => new neo4j.types.Date(1, [2], 3)).toThrowError(TypeError); - expect(() => new neo4j.types.Date(1, 2, () => 3)).toThrowError(TypeError); - expect(() => new neo4j.types.Date({year: 1, month: 2, day: 3})).toThrowError(TypeError); - }); + expect(() => new neo4j.types.Date('1', 2, 3)).toThrowError(TypeError) + expect(() => new neo4j.types.Date(1, [2], 3)).toThrowError(TypeError) + expect(() => new neo4j.types.Date(1, 2, () => 3)).toThrowError(TypeError) + expect( + () => new neo4j.types.Date({ year: 1, month: 2, day: 3 }) + ).toThrowError(TypeError) + }) it('should validate types of constructor arguments for LocalDateTime', () => { - expect(() => new neo4j.types.LocalDateTime('1', 2, 3, 4, 5, 6, 7)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime(1, '2', 3, 4, 5, 6, 7)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime(1, 2, [3], 4, 5, 6, 7)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime(1, 2, 3, [4], 5, 6, 7)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime(1, 2, 3, 4, () => 5, 6, 7)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime(1, 2, 3, 4, 5, () => 6, 7)).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime(1, 2, 3, 4, 5, 6, {value: 7})).toThrowError(TypeError); - expect(() => new neo4j.types.LocalDateTime({year: 1, month: 2, day: 3, hour: 4, minute: 5, second: 6, nanosecond: 7})).toThrowError(TypeError); - }); + expect( + () => new neo4j.types.LocalDateTime('1', 2, 3, 4, 5, 6, 7) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.LocalDateTime(1, '2', 3, 4, 5, 6, 7) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.LocalDateTime(1, 2, [3], 4, 5, 6, 7) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.LocalDateTime(1, 2, 3, [4], 5, 6, 7) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.LocalDateTime(1, 2, 3, 4, () => 5, 6, 7) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.LocalDateTime(1, 2, 3, 4, 5, () => 6, 7) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.LocalDateTime(1, 2, 3, 4, 5, 6, { value: 7 }) + ).toThrowError(TypeError) + expect( + () => + new neo4j.types.LocalDateTime({ + year: 1, + month: 2, + day: 3, + hour: 4, + minute: 5, + second: 6, + nanosecond: 7 + }) + ).toThrowError(TypeError) + }) it('should validate types of constructor arguments for DateTime', () => { - expect(() => new neo4j.types.DateTime('1', 2, 3, 4, 5, 6, 7, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, '2', 3, 4, 5, 6, 7, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, [3], 4, 5, 6, 7, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, 3, [4], 5, 6, 7, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, () => 5, 6, 7, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, () => 6, 7, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, {value: 7}, 8)).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, {value: 8})).toThrowError(TypeError); - - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, {timeZoneId: 'UK'})).toThrowError(TypeError); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, ['UK'])).toThrowError(TypeError); - - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7)).toThrow(); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, null)).toThrow(); - expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, 8, 'UK')).toThrow(); - }); + expect( + () => new neo4j.types.DateTime('1', 2, 3, 4, 5, 6, 7, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, '2', 3, 4, 5, 6, 7, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, [3], 4, 5, 6, 7, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, 3, [4], 5, 6, 7, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, () => 5, 6, 7, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, 5, () => 6, 7, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, { value: 7 }, 8) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, { value: 8 }) + ).toThrowError(TypeError) + + expect( + () => + new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, { + timeZoneId: 'UK' + }) + ).toThrowError(TypeError) + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, ['UK']) + ).toThrowError(TypeError) + + expect(() => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7)).toThrow() + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, null, null) + ).toThrow() + expect( + () => new neo4j.types.DateTime(1, 2, 3, 4, 5, 6, 7, 8, 'UK') + ).toThrow() + }) it('should convert standard Date to neo4j LocalTime', () => { - testStandardDateToLocalTimeConversion(new Date(2000, 1, 1, 0, 0, 0, 0)); - testStandardDateToLocalTimeConversion(new Date(1456, 7, 12, 12, 0, 0, 0)); - testStandardDateToLocalTimeConversion(new Date(2121, 11, 27, 21, 56, 0, 0)); - testStandardDateToLocalTimeConversion(new Date(1392, 2, 2, 3, 14, 59, 0)); - testStandardDateToLocalTimeConversion(new Date(1102, 6, 5, 17, 12, 32, 99)); - testStandardDateToLocalTimeConversion(new Date(2019, 2, 7, 0, 0, 0, 1)); - - testStandardDateToLocalTimeConversion(new Date(1351, 4, 7, 0, 0, 0, 0), neo4j.int(1)); - testStandardDateToLocalTimeConversion(new Date(3841, 1, 19, 0, 0, 0, 0), neo4j.int(99)); - testStandardDateToLocalTimeConversion(new Date(2222, 3, 29, 0, 0, 0, 0), neo4j.int(999999999)); - }); + testStandardDateToLocalTimeConversion(new Date(2000, 1, 1, 0, 0, 0, 0)) + testStandardDateToLocalTimeConversion(new Date(1456, 7, 12, 12, 0, 0, 0)) + testStandardDateToLocalTimeConversion(new Date(2121, 11, 27, 21, 56, 0, 0)) + testStandardDateToLocalTimeConversion(new Date(1392, 2, 2, 3, 14, 59, 0)) + testStandardDateToLocalTimeConversion(new Date(1102, 6, 5, 17, 12, 32, 99)) + testStandardDateToLocalTimeConversion(new Date(2019, 2, 7, 0, 0, 0, 1)) + + testStandardDateToLocalTimeConversion( + new Date(1351, 4, 7, 0, 0, 0, 0), + neo4j.int(1) + ) + testStandardDateToLocalTimeConversion( + new Date(3841, 1, 19, 0, 0, 0, 0), + neo4j.int(99) + ) + testStandardDateToLocalTimeConversion( + new Date(2222, 3, 29, 0, 0, 0, 0), + neo4j.int(999999999) + ) + }) it('should fail to convert invalid standard Date to neo4j LocalTime', () => { - const LocalTime = neo4j.types.LocalTime; - - expect(() => LocalTime.fromStandardDate()).toThrowError(TypeError); - expect(() => LocalTime.fromStandardDate('2007-04-05T12:30-02:00')).toThrowError(TypeError); - expect(() => LocalTime.fromStandardDate({})).toThrowError(TypeError); - - expect(() => LocalTime.fromStandardDate(new Date({}))).toThrowError(TypeError); - expect(() => LocalTime.fromStandardDate(new Date([]))).toThrowError(TypeError); - expect(() => LocalTime.fromStandardDate(new Date(NaN))).toThrowError(TypeError); - - expect(() => LocalTime.fromStandardDate(new Date(), '1')).toThrowError(TypeError); - expect(() => LocalTime.fromStandardDate(new Date(), {nanosecond: 1})).toThrowError(TypeError); - expect(() => LocalTime.fromStandardDate(new Date(), [1])).toThrowError(TypeError); - }); + const LocalTime = neo4j.types.LocalTime + + expect(() => LocalTime.fromStandardDate()).toThrowError(TypeError) + expect(() => + LocalTime.fromStandardDate('2007-04-05T12:30-02:00') + ).toThrowError(TypeError) + expect(() => LocalTime.fromStandardDate({})).toThrowError(TypeError) + + expect(() => LocalTime.fromStandardDate(new Date({}))).toThrowError( + TypeError + ) + expect(() => LocalTime.fromStandardDate(new Date([]))).toThrowError( + TypeError + ) + expect(() => LocalTime.fromStandardDate(new Date(NaN))).toThrowError( + TypeError + ) + + expect(() => LocalTime.fromStandardDate(new Date(), '1')).toThrowError( + TypeError + ) + expect(() => + LocalTime.fromStandardDate(new Date(), { nanosecond: 1 }) + ).toThrowError(TypeError) + expect(() => LocalTime.fromStandardDate(new Date(), [1])).toThrowError( + TypeError + ) + }) it('should convert standard Date to neo4j Time', () => { - testStandardDateToTimeConversion(new Date(2000, 1, 1, 0, 0, 0, 0)); - testStandardDateToTimeConversion(new Date(1456, 7, 12, 12, 0, 0, 0)); - testStandardDateToTimeConversion(new Date(2121, 11, 27, 21, 56, 0, 0)); - testStandardDateToTimeConversion(new Date(1392, 2, 2, 3, 14, 59, 0)); - testStandardDateToTimeConversion(new Date(1102, 6, 5, 17, 12, 32, 99)); - testStandardDateToTimeConversion(new Date(2019, 2, 7, 0, 0, 0, 1)); - - testStandardDateToTimeConversion(new Date(1351, 4, 7, 0, 0, 0, 0), neo4j.int(1)); - testStandardDateToTimeConversion(new Date(3841, 1, 19, 0, 0, 0, 0), neo4j.int(99)); - testStandardDateToTimeConversion(new Date(2222, 3, 29, 0, 0, 0, 0), neo4j.int(999999999)); - }); + testStandardDateToTimeConversion(new Date(2000, 1, 1, 0, 0, 0, 0)) + testStandardDateToTimeConversion(new Date(1456, 7, 12, 12, 0, 0, 0)) + testStandardDateToTimeConversion(new Date(2121, 11, 27, 21, 56, 0, 0)) + testStandardDateToTimeConversion(new Date(1392, 2, 2, 3, 14, 59, 0)) + testStandardDateToTimeConversion(new Date(1102, 6, 5, 17, 12, 32, 99)) + testStandardDateToTimeConversion(new Date(2019, 2, 7, 0, 0, 0, 1)) + + testStandardDateToTimeConversion( + new Date(1351, 4, 7, 0, 0, 0, 0), + neo4j.int(1) + ) + testStandardDateToTimeConversion( + new Date(3841, 1, 19, 0, 0, 0, 0), + neo4j.int(99) + ) + testStandardDateToTimeConversion( + new Date(2222, 3, 29, 0, 0, 0, 0), + neo4j.int(999999999) + ) + }) it('should fail to convert invalid standard Date to neo4j Time', () => { - const Time = neo4j.types.Time; + const Time = neo4j.types.Time - expect(() => Time.fromStandardDate()).toThrowError(TypeError); - expect(() => Time.fromStandardDate('2007-04-05T12:30-02:00')).toThrowError(TypeError); - expect(() => Time.fromStandardDate({})).toThrowError(TypeError); + expect(() => Time.fromStandardDate()).toThrowError(TypeError) + expect(() => Time.fromStandardDate('2007-04-05T12:30-02:00')).toThrowError( + TypeError + ) + expect(() => Time.fromStandardDate({})).toThrowError(TypeError) - expect(() => Time.fromStandardDate(new Date({}))).toThrowError(TypeError); - expect(() => Time.fromStandardDate(new Date([]))).toThrowError(TypeError); - expect(() => Time.fromStandardDate(new Date(NaN))).toThrowError(TypeError); + expect(() => Time.fromStandardDate(new Date({}))).toThrowError(TypeError) + expect(() => Time.fromStandardDate(new Date([]))).toThrowError(TypeError) + expect(() => Time.fromStandardDate(new Date(NaN))).toThrowError(TypeError) - expect(() => Time.fromStandardDate(new Date(), '1')).toThrowError(TypeError); - expect(() => Time.fromStandardDate(new Date(), {nanosecond: 1})).toThrowError(TypeError); - expect(() => Time.fromStandardDate(new Date(), [1])).toThrowError(TypeError); - }); + expect(() => Time.fromStandardDate(new Date(), '1')).toThrowError(TypeError) + expect(() => + Time.fromStandardDate(new Date(), { nanosecond: 1 }) + ).toThrowError(TypeError) + expect(() => Time.fromStandardDate(new Date(), [1])).toThrowError(TypeError) + }) it('should convert standard Date to neo4j Date', () => { - testStandardDateToNeo4jDateConversion(new Date(2000, 1, 1)); - testStandardDateToNeo4jDateConversion(new Date(1456, 7, 12)); - testStandardDateToNeo4jDateConversion(new Date(2121, 11, 27)); - testStandardDateToNeo4jDateConversion(new Date(1392, 2, 2)); - testStandardDateToNeo4jDateConversion(new Date(1102, 6, 5)); - testStandardDateToNeo4jDateConversion(new Date(2019, 2, 7)); + testStandardDateToNeo4jDateConversion(new Date(2000, 1, 1)) + testStandardDateToNeo4jDateConversion(new Date(1456, 7, 12)) + testStandardDateToNeo4jDateConversion(new Date(2121, 11, 27)) + testStandardDateToNeo4jDateConversion(new Date(1392, 2, 2)) + testStandardDateToNeo4jDateConversion(new Date(1102, 6, 5)) + testStandardDateToNeo4jDateConversion(new Date(2019, 2, 7)) - testStandardDateToNeo4jDateConversion(new Date(1351, 4, 7)); - testStandardDateToNeo4jDateConversion(new Date(3841, 1, 19)); - testStandardDateToNeo4jDateConversion(new Date(2222, 3, 29)); + testStandardDateToNeo4jDateConversion(new Date(1351, 4, 7)) + testStandardDateToNeo4jDateConversion(new Date(3841, 1, 19)) + testStandardDateToNeo4jDateConversion(new Date(2222, 3, 29)) - testStandardDateToNeo4jDateConversion(new Date(1567, 0, 29)); - }); + testStandardDateToNeo4jDateConversion(new Date(1567, 0, 29)) + }) it('should fail to convert invalid standard Date to neo4j Date', () => { - const Neo4jDate = neo4j.types.Date; - - expect(() => Neo4jDate.fromStandardDate()).toThrowError(TypeError); - expect(() => Neo4jDate.fromStandardDate('2007-04-05T12:30-02:00')).toThrowError(TypeError); - expect(() => Neo4jDate.fromStandardDate({})).toThrowError(TypeError); - - expect(() => Neo4jDate.fromStandardDate(new Date({}))).toThrowError(TypeError); - expect(() => Neo4jDate.fromStandardDate(new Date([]))).toThrowError(TypeError); - expect(() => Neo4jDate.fromStandardDate(new Date(NaN))).toThrowError(TypeError); - }); + const Neo4jDate = neo4j.types.Date + + expect(() => Neo4jDate.fromStandardDate()).toThrowError(TypeError) + expect(() => + Neo4jDate.fromStandardDate('2007-04-05T12:30-02:00') + ).toThrowError(TypeError) + expect(() => Neo4jDate.fromStandardDate({})).toThrowError(TypeError) + + expect(() => Neo4jDate.fromStandardDate(new Date({}))).toThrowError( + TypeError + ) + expect(() => Neo4jDate.fromStandardDate(new Date([]))).toThrowError( + TypeError + ) + expect(() => Neo4jDate.fromStandardDate(new Date(NaN))).toThrowError( + TypeError + ) + }) it('should convert standard Date to neo4j LocalDateTime', () => { - testStandardDateToLocalDateTimeConversion(new Date(2011, 9, 18)); - testStandardDateToLocalDateTimeConversion(new Date(1455, 0, 1)); - testStandardDateToLocalDateTimeConversion(new Date(0)); - testStandardDateToLocalDateTimeConversion(new Date(2056, 5, 22, 21, 59, 12, 999)); - - testStandardDateToLocalDateTimeConversion(new Date(0), 1); - testStandardDateToLocalDateTimeConversion(new Date(0), 999999999); - testStandardDateToLocalDateTimeConversion(new Date(1922, 1, 22, 23, 23, 45, 123), 456789); - - testStandardDateToLocalDateTimeConversion(new Date(1999, 1, 1, 10, 10, 10), neo4j.int(999)); - - testStandardDateToLocalDateTimeConversion(new Date(2192, 0, 17, 20, 30, 40)); - testStandardDateToLocalDateTimeConversion(new Date(2239, 0, 9, 1, 2, 3), 4); - }); + testStandardDateToLocalDateTimeConversion(new Date(2011, 9, 18)) + testStandardDateToLocalDateTimeConversion(new Date(1455, 0, 1)) + testStandardDateToLocalDateTimeConversion(new Date(0)) + testStandardDateToLocalDateTimeConversion( + new Date(2056, 5, 22, 21, 59, 12, 999) + ) + + testStandardDateToLocalDateTimeConversion(new Date(0), 1) + testStandardDateToLocalDateTimeConversion(new Date(0), 999999999) + testStandardDateToLocalDateTimeConversion( + new Date(1922, 1, 22, 23, 23, 45, 123), + 456789 + ) + + testStandardDateToLocalDateTimeConversion( + new Date(1999, 1, 1, 10, 10, 10), + neo4j.int(999) + ) + + testStandardDateToLocalDateTimeConversion(new Date(2192, 0, 17, 20, 30, 40)) + testStandardDateToLocalDateTimeConversion(new Date(2239, 0, 9, 1, 2, 3), 4) + }) it('should fail to convert invalid standard Date to neo4j LocalDateTime', () => { - const LocalDateTime = neo4j.types.LocalDateTime; - - expect(() => LocalDateTime.fromStandardDate()).toThrowError(TypeError); - expect(() => LocalDateTime.fromStandardDate('2007-04-05T12:30-02:00')).toThrowError(TypeError); - expect(() => LocalDateTime.fromStandardDate({})).toThrowError(TypeError); - - expect(() => LocalDateTime.fromStandardDate(new Date({}))).toThrowError(TypeError); - expect(() => LocalDateTime.fromStandardDate(new Date([]))).toThrowError(TypeError); - expect(() => LocalDateTime.fromStandardDate(new Date(NaN))).toThrowError(TypeError); - - expect(() => LocalDateTime.fromStandardDate(new Date(), '1')).toThrowError(TypeError); - expect(() => LocalDateTime.fromStandardDate(new Date(), {nanosecond: 1})).toThrowError(TypeError); - expect(() => LocalDateTime.fromStandardDate(new Date(), [1])).toThrowError(TypeError); - }); + const LocalDateTime = neo4j.types.LocalDateTime + + expect(() => LocalDateTime.fromStandardDate()).toThrowError(TypeError) + expect(() => + LocalDateTime.fromStandardDate('2007-04-05T12:30-02:00') + ).toThrowError(TypeError) + expect(() => LocalDateTime.fromStandardDate({})).toThrowError(TypeError) + + expect(() => LocalDateTime.fromStandardDate(new Date({}))).toThrowError( + TypeError + ) + expect(() => LocalDateTime.fromStandardDate(new Date([]))).toThrowError( + TypeError + ) + expect(() => LocalDateTime.fromStandardDate(new Date(NaN))).toThrowError( + TypeError + ) + + expect(() => LocalDateTime.fromStandardDate(new Date(), '1')).toThrowError( + TypeError + ) + expect(() => + LocalDateTime.fromStandardDate(new Date(), { nanosecond: 1 }) + ).toThrowError(TypeError) + expect(() => LocalDateTime.fromStandardDate(new Date(), [1])).toThrowError( + TypeError + ) + }) it('should convert standard Date to neo4j DateTime', () => { - testStandardDateToDateTimeConversion(new Date(2011, 9, 18)); - testStandardDateToDateTimeConversion(new Date(1455, 0, 1)); - testStandardDateToDateTimeConversion(new Date(0)); - testStandardDateToDateTimeConversion(new Date(2056, 5, 22, 21, 59, 12, 999)); - - testStandardDateToDateTimeConversion(new Date(0), 1); - testStandardDateToDateTimeConversion(new Date(0), 999999999); - - testStandardDateToDateTimeConversion(new Date(1922, 1, 22, 23, 23, 45, 123), 456789); - testStandardDateToDateTimeConversion(new Date(1999, 1, 1, 10, 10, 10), neo4j.int(999)); - - testStandardDateToDateTimeConversion(new Date(1899, 0, 7, 7, 7, 7, 7)); - testStandardDateToDateTimeConversion(new Date(2005, 0, 1, 2, 3, 4, 5), 100); - }); + testStandardDateToDateTimeConversion(new Date(2011, 9, 18)) + testStandardDateToDateTimeConversion(new Date(1455, 0, 1)) + testStandardDateToDateTimeConversion(new Date(0)) + testStandardDateToDateTimeConversion(new Date(2056, 5, 22, 21, 59, 12, 999)) + + testStandardDateToDateTimeConversion(new Date(0), 1) + testStandardDateToDateTimeConversion(new Date(0), 999999999) + + testStandardDateToDateTimeConversion( + new Date(1922, 1, 22, 23, 23, 45, 123), + 456789 + ) + testStandardDateToDateTimeConversion( + new Date(1999, 1, 1, 10, 10, 10), + neo4j.int(999) + ) + + testStandardDateToDateTimeConversion(new Date(1899, 0, 7, 7, 7, 7, 7)) + testStandardDateToDateTimeConversion(new Date(2005, 0, 1, 2, 3, 4, 5), 100) + }) it('should fail to convert invalid standard Date to neo4j DateTime', () => { - const DateTime = neo4j.types.DateTime; - - expect(() => DateTime.fromStandardDate()).toThrowError(TypeError); - expect(() => DateTime.fromStandardDate('2007-04-05T12:30-02:00')).toThrowError(TypeError); - expect(() => DateTime.fromStandardDate({})).toThrowError(TypeError); - - expect(() => DateTime.fromStandardDate(new Date({}))).toThrowError(TypeError); - expect(() => DateTime.fromStandardDate(new Date([]))).toThrowError(TypeError); - expect(() => DateTime.fromStandardDate(new Date(NaN))).toThrowError(TypeError); - - expect(() => DateTime.fromStandardDate(new Date(), '1')).toThrowError(TypeError); - expect(() => DateTime.fromStandardDate(new Date(), {nanosecond: 1})).toThrowError(TypeError); - expect(() => DateTime.fromStandardDate(new Date(), [1])).toThrowError(TypeError); - }); + const DateTime = neo4j.types.DateTime + + expect(() => DateTime.fromStandardDate()).toThrowError(TypeError) + expect(() => + DateTime.fromStandardDate('2007-04-05T12:30-02:00') + ).toThrowError(TypeError) + expect(() => DateTime.fromStandardDate({})).toThrowError(TypeError) + + expect(() => DateTime.fromStandardDate(new Date({}))).toThrowError( + TypeError + ) + expect(() => DateTime.fromStandardDate(new Date([]))).toThrowError( + TypeError + ) + expect(() => DateTime.fromStandardDate(new Date(NaN))).toThrowError( + TypeError + ) + + expect(() => DateTime.fromStandardDate(new Date(), '1')).toThrowError( + TypeError + ) + expect(() => + DateTime.fromStandardDate(new Date(), { nanosecond: 1 }) + ).toThrowError(TypeError) + expect(() => DateTime.fromStandardDate(new Date(), [1])).toThrowError( + TypeError + ) + }) it('should send and receive neo4j Date created from standard Date with zero month', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } // return numbers and not integers to simplify the equality comparison - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - const standardDate = new Date(2000, 0, 1); - const neo4jDate = neo4j.types.Date.fromStandardDate(standardDate); - testSendReceiveTemporalValue(neo4jDate, done); - }); + const standardDate = new Date(2000, 0, 1) + const neo4jDate = neo4j.types.Date.fromStandardDate(standardDate) + testSendReceiveTemporalValue(neo4jDate, done) + }) it('should send and receive neo4j LocalDateTime created from standard Date with zero month', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } // return numbers and not integers to simplify the equality comparison - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - const standardDate = new Date(2121, 0, 7, 10, 20, 30, 40); - const neo4jLocalDateTime = neo4j.types.LocalDateTime.fromStandardDate(standardDate); - testSendReceiveTemporalValue(neo4jLocalDateTime, done); - }); + const standardDate = new Date(2121, 0, 7, 10, 20, 30, 40) + const neo4jLocalDateTime = neo4j.types.LocalDateTime.fromStandardDate( + standardDate + ) + testSendReceiveTemporalValue(neo4jLocalDateTime, done) + }) it('should send and receive neo4j DateTime created from standard Date with zero month', done => { if (neo4jDoesNotSupportTemporalTypes(done)) { - return; + return } // return numbers and not integers to simplify the equality comparison - session = driverWithNativeNumbers.session(); + session = driverWithNativeNumbers.session() - const standardDate = new Date(1756, 0, 29, 23, 15, 59, 12); - const neo4jDateTime = neo4j.types.DateTime.fromStandardDate(standardDate); - testSendReceiveTemporalValue(neo4jDateTime, done); - }); + const standardDate = new Date(1756, 0, 29, 23, 15, 59, 12) + const neo4jDateTime = neo4j.types.DateTime.fromStandardDate(standardDate) + testSendReceiveTemporalValue(neo4jDateTime, done) + }) it('should fail to create LocalTime with out of range values', () => { - expect(() => localTime(999, 1, 1, 1)).toThrow(); - expect(() => localTime(1, 999, 1, 1)).toThrow(); - expect(() => localTime(1, 1, 999, 1)).toThrow(); - expect(() => localTime(1, 1, 1, -999)).toThrow(); - expect(() => localTime(1, 1, 1, 1000000000)).toThrow(); - }); + expect(() => localTime(999, 1, 1, 1)).toThrow() + expect(() => localTime(1, 999, 1, 1)).toThrow() + expect(() => localTime(1, 1, 999, 1)).toThrow() + expect(() => localTime(1, 1, 1, -999)).toThrow() + expect(() => localTime(1, 1, 1, 1000000000)).toThrow() + }) it('should fail to create Time with out of range values', () => { - expect(() => time(999, 1, 1, 1, 1)).toThrow(); - expect(() => time(1, 999, 1, 1, 1)).toThrow(); - expect(() => time(1, 1, 999, 1, 1)).toThrow(); - expect(() => time(1, 1, 1, -999, 1)).toThrow(); - expect(() => time(1, 1, 1, 1000000000, 1)).toThrow(); - }); + expect(() => time(999, 1, 1, 1, 1)).toThrow() + expect(() => time(1, 999, 1, 1, 1)).toThrow() + expect(() => time(1, 1, 999, 1, 1)).toThrow() + expect(() => time(1, 1, 1, -999, 1)).toThrow() + expect(() => time(1, 1, 1, 1000000000, 1)).toThrow() + }) it('should fail to create Date with out of range values', () => { - expect(() => date(1000000000, 1, 1)).toThrow(); - expect(() => date(1, 0, 1)).toThrow(); - expect(() => date(1, 13, 1)).toThrow(); - expect(() => date(1, 1, 0)).toThrow(); - expect(() => date(1, 1, -1)).toThrow(); - expect(() => date(1, 1, 33)).toThrow(); - }); + expect(() => date(1000000000, 1, 1)).toThrow() + expect(() => date(1, 0, 1)).toThrow() + expect(() => date(1, 13, 1)).toThrow() + expect(() => date(1, 1, 0)).toThrow() + expect(() => date(1, 1, -1)).toThrow() + expect(() => date(1, 1, 33)).toThrow() + }) it('should fail to create LocalDateTime with out of range values', () => { - expect(() => localDateTime(1000000000, 1, 1, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 0, 1, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 13, 1, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, -1, 1, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 0, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, -1, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 33, 1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, -1, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 24, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 42, 1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, -1, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 60, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 999, 1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 1, -1, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 1, 60, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 1, 99, 1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 1, 1, -1)).toThrow(); - expect(() => localDateTime(1, 1, 1, 1, 1, 1, 1000000000)).toThrow(); - }); + expect(() => localDateTime(1000000000, 1, 1, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 0, 1, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 13, 1, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, -1, 1, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 0, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, -1, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 33, 1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, -1, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 24, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 42, 1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, -1, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 60, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 999, 1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 1, -1, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 1, 60, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 1, 99, 1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 1, 1, -1)).toThrow() + expect(() => localDateTime(1, 1, 1, 1, 1, 1, 1000000000)).toThrow() + }) it('should fail to create DateTime with out of range values', () => { - expect(() => dateTimeWithZoneOffset(1000000000, 1, 1, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 0, 1, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 13, 1, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, -1, 1, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 0, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, -1, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 33, 1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, -1, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 24, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 42, 1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, -1, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 60, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 999, 1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, -1, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 60, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 99, 1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 1, -1, 0)).toThrow(); - expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 1, 1000000000, 0)).toThrow(); - }); + expect(() => + dateTimeWithZoneOffset(1000000000, 1, 1, 1, 1, 1, 1, 0) + ).toThrow() + expect(() => dateTimeWithZoneOffset(1, 0, 1, 1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 13, 1, 1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, -1, 1, 1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 0, 1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, -1, 1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 33, 1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, -1, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 24, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 42, 1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, -1, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 60, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 999, 1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, -1, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 60, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 99, 1, 0)).toThrow() + expect(() => dateTimeWithZoneOffset(1, 1, 1, 1, 1, 1, -1, 0)).toThrow() + expect(() => + dateTimeWithZoneOffset(1, 1, 1, 1, 1, 1, 1000000000, 0) + ).toThrow() + }) it('should convert standard Date with offset to neo4j Time', () => { - const standardDate1 = testUtils.fakeStandardDateWithOffset(0); - const neo4jTime1 = neo4j.types.Time.fromStandardDate(standardDate1); - verifyTimeZoneOffset(neo4jTime1, 0, 'Z'); + const standardDate1 = testUtils.fakeStandardDateWithOffset(0) + const neo4jTime1 = neo4j.types.Time.fromStandardDate(standardDate1) + verifyTimeZoneOffset(neo4jTime1, 0, 'Z') - const standardDate2 = testUtils.fakeStandardDateWithOffset(-600); - const neo4jTime2 = neo4j.types.Time.fromStandardDate(standardDate2); - verifyTimeZoneOffset(neo4jTime2, 600 * 60, '+10:00'); + const standardDate2 = testUtils.fakeStandardDateWithOffset(-600) + const neo4jTime2 = neo4j.types.Time.fromStandardDate(standardDate2) + verifyTimeZoneOffset(neo4jTime2, 600 * 60, '+10:00') - const standardDate3 = testUtils.fakeStandardDateWithOffset(480); - const neo4jTime3 = neo4j.types.Time.fromStandardDate(standardDate3); - verifyTimeZoneOffset(neo4jTime3, -1 * 480 * 60, '-08:00'); + const standardDate3 = testUtils.fakeStandardDateWithOffset(480) + const neo4jTime3 = neo4j.types.Time.fromStandardDate(standardDate3) + verifyTimeZoneOffset(neo4jTime3, -1 * 480 * 60, '-08:00') - const standardDate4 = testUtils.fakeStandardDateWithOffset(-180); - const neo4jTime4 = neo4j.types.Time.fromStandardDate(standardDate4); - verifyTimeZoneOffset(neo4jTime4, 180 * 60, '+03:00'); + const standardDate4 = testUtils.fakeStandardDateWithOffset(-180) + const neo4jTime4 = neo4j.types.Time.fromStandardDate(standardDate4) + verifyTimeZoneOffset(neo4jTime4, 180 * 60, '+03:00') - const standardDate5 = testUtils.fakeStandardDateWithOffset(150); - const neo4jTime5 = neo4j.types.Time.fromStandardDate(standardDate5); - verifyTimeZoneOffset(neo4jTime5, -1 * 150 * 60, '-02:30'); - }); + const standardDate5 = testUtils.fakeStandardDateWithOffset(150) + const neo4jTime5 = neo4j.types.Time.fromStandardDate(standardDate5) + verifyTimeZoneOffset(neo4jTime5, -1 * 150 * 60, '-02:30') + }) it('should convert standard Date with offset to neo4j DateTime', () => { - const standardDate1 = testUtils.fakeStandardDateWithOffset(0); - const neo4jDateTime1 = neo4j.types.DateTime.fromStandardDate(standardDate1); - verifyTimeZoneOffset(neo4jDateTime1, 0, 'Z'); + const standardDate1 = testUtils.fakeStandardDateWithOffset(0) + const neo4jDateTime1 = neo4j.types.DateTime.fromStandardDate(standardDate1) + verifyTimeZoneOffset(neo4jDateTime1, 0, 'Z') - const standardDate2 = testUtils.fakeStandardDateWithOffset(-600); - const neo4jDateTime2 = neo4j.types.DateTime.fromStandardDate(standardDate2); - verifyTimeZoneOffset(neo4jDateTime2, 600 * 60, '+10:00'); + const standardDate2 = testUtils.fakeStandardDateWithOffset(-600) + const neo4jDateTime2 = neo4j.types.DateTime.fromStandardDate(standardDate2) + verifyTimeZoneOffset(neo4jDateTime2, 600 * 60, '+10:00') - const standardDate3 = testUtils.fakeStandardDateWithOffset(480); - const neo4jDateTime3 = neo4j.types.DateTime.fromStandardDate(standardDate3); - verifyTimeZoneOffset(neo4jDateTime3, -1 * 480 * 60, '-08:00'); + const standardDate3 = testUtils.fakeStandardDateWithOffset(480) + const neo4jDateTime3 = neo4j.types.DateTime.fromStandardDate(standardDate3) + verifyTimeZoneOffset(neo4jDateTime3, -1 * 480 * 60, '-08:00') - const standardDate4 = testUtils.fakeStandardDateWithOffset(-180); - const neo4jDateTime4 = neo4j.types.DateTime.fromStandardDate(standardDate4); - verifyTimeZoneOffset(neo4jDateTime4, 180 * 60, '+03:00'); + const standardDate4 = testUtils.fakeStandardDateWithOffset(-180) + const neo4jDateTime4 = neo4j.types.DateTime.fromStandardDate(standardDate4) + verifyTimeZoneOffset(neo4jDateTime4, 180 * 60, '+03:00') - const standardDate5 = testUtils.fakeStandardDateWithOffset(150); - const neo4jDateTime5 = neo4j.types.DateTime.fromStandardDate(standardDate5); - verifyTimeZoneOffset(neo4jDateTime5, -1 * 150 * 60, '-02:30'); - }); + const standardDate5 = testUtils.fakeStandardDateWithOffset(150) + const neo4jDateTime5 = neo4j.types.DateTime.fromStandardDate(standardDate5) + verifyTimeZoneOffset(neo4jDateTime5, -1 * 150 * 60, '-02:30') + }) - function testSendAndReceiveRandomTemporalValues(valueGenerator, done) { + function testSendAndReceiveRandomTemporalValues (valueGenerator, done) { const asyncFunction = (index, callback) => { - const next = () => callback(); - next.fail = error => callback(error); - testSendReceiveTemporalValue(valueGenerator(), next); - }; + const next = () => callback() + next.fail = error => callback(error) + testSendReceiveTemporalValue(valueGenerator(), next) + } const doneFunction = error => { if (error) { - done.fail(error); + done.fail(error) } else { - done(); + done() } - }; + } - timesSeries(RANDOM_VALUES_TO_TEST, asyncFunction, doneFunction); + timesSeries(RANDOM_VALUES_TO_TEST, asyncFunction, doneFunction) } - function testSendAndReceiveArrayOfRandomTemporalValues(valueGenerator, done) { - const arrayLength = _.random(MIN_TEMPORAL_ARRAY_LENGTH, MAX_TEMPORAL_ARRAY_LENGTH); - const values = _.range(arrayLength).map(() => valueGenerator()); - testSendReceiveTemporalValue(values, done); + function testSendAndReceiveArrayOfRandomTemporalValues (valueGenerator, done) { + const arrayLength = _.random( + MIN_TEMPORAL_ARRAY_LENGTH, + MAX_TEMPORAL_ARRAY_LENGTH + ) + const values = _.range(arrayLength).map(() => valueGenerator()) + testSendReceiveTemporalValue(values, done) } - function testReceiveTemporalValue(query, expectedValue, done) { - session.run(query).then(result => { - const records = result.records; - expect(records.length).toEqual(1); - - const value = records[0].get(0); - expect(value).toEqual(expectedValue); - - session.close(); - done(); - }).catch(error => { - done.fail(error); - }); + function testReceiveTemporalValue (query, expectedValue, done) { + session + .run(query) + .then(result => { + const records = result.records + expect(records.length).toEqual(1) + + const value = records[0].get(0) + expect(value).toEqual(expectedValue) + + session.close() + done() + }) + .catch(error => { + done.fail(error) + }) } - function testSendReceiveTemporalValue(value, done) { - session.run('CREATE (n:Node {value: $value}) RETURN n.value', {value: value}).then(result => { - const records = result.records; - expect(records.length).toEqual(1); - - const receivedValue = records[0].get(0); - expect(receivedValue).toEqual(value); - - session.close(); - done(); - }).catch(error => { - done.fail(error); - }); + function testSendReceiveTemporalValue (value, done) { + session + .run('CREATE (n:Node {value: $value}) RETURN n.value', { value: value }) + .then(result => { + const records = result.records + expect(records.length).toEqual(1) + + const receivedValue = records[0].get(0) + expect(receivedValue).toEqual(value) + + session.close() + done() + }) + .catch(error => { + done.fail(error) + }) } - function testDurationToString(values, done) { - const durations = values.map(value => value.duration); - const expectedDurationStrings = values.map(value => value.expectedString); - - session.run('UNWIND $durations AS d RETURN d', {durations: durations}).then(result => { - const receivedDurationStrings = result.records - .map(record => record.get(0)) - .map(duration => duration.toString()); - - expect(expectedDurationStrings).toEqual(receivedDurationStrings); - done(); - }).catch(error => { - done.fail(error); - }); + function testDurationToString (values, done) { + const durations = values.map(value => value.duration) + const expectedDurationStrings = values.map(value => value.expectedString) + + session + .run('UNWIND $durations AS d RETURN d', { durations: durations }) + .then(result => { + const receivedDurationStrings = result.records + .map(record => record.get(0)) + .map(duration => duration.toString()) + + expect(expectedDurationStrings).toEqual(receivedDurationStrings) + done() + }) + .catch(error => { + done.fail(error) + }) } - function neo4jDoesNotSupportTemporalTypes(done) { + function neo4jDoesNotSupportTemporalTypes (done) { if (serverVersion.compareTo(VERSION_3_4_0) < 0) { - done(); - return true; + done() + return true } - return false; + return false } - function randomDuration() { - const sign = _.sample([-1, 1]); // duration can be negative + function randomDuration () { + const sign = _.sample([-1, 1]) // duration can be negative return duration( sign * _.random(0, MAX_DURATION_COMPONENT), sign * _.random(0, MAX_DURATION_COMPONENT), sign * _.random(0, MAX_DURATION_COMPONENT), - _.random(0, MAX_NANO_OF_SECOND), - ); + _.random(0, MAX_NANO_OF_SECOND) + ) } - function randomDateTimeWithZoneOffset() { - const dateTime = randomDstSafeLocalDateTime(); - return new neo4j.types.DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute, dateTime.second, dateTime.nanosecond, - randomZoneOffsetSeconds(), null); + function randomDateTimeWithZoneOffset () { + const dateTime = randomDstSafeLocalDateTime() + return new neo4j.types.DateTime( + dateTime.year, + dateTime.month, + dateTime.day, + dateTime.hour, + dateTime.minute, + dateTime.second, + dateTime.nanosecond, + randomZoneOffsetSeconds(), + null + ) } - function randomDateTimeWithZoneId() { - const dateTime = randomDstSafeLocalDateTime(); - return new neo4j.types.DateTime(dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute, dateTime.second, dateTime.nanosecond, - null, randomZoneId()); + function randomDateTimeWithZoneId () { + const dateTime = randomDstSafeLocalDateTime() + return new neo4j.types.DateTime( + dateTime.year, + dateTime.month, + dateTime.day, + dateTime.hour, + dateTime.minute, + dateTime.second, + dateTime.nanosecond, + null, + randomZoneId() + ) } - function randomDstSafeLocalDateTime() { - const date = randomDate(); - const time = randomDstSafeLocalTime(); - return new neo4j.types.LocalDateTime(date.year, date.month, date.day, time.hour, time.minute, time.second, time.nanosecond); + function randomDstSafeLocalDateTime () { + const date = randomDate() + const time = randomDstSafeLocalTime() + return new neo4j.types.LocalDateTime( + date.year, + date.month, + date.day, + time.hour, + time.minute, + time.second, + time.nanosecond + ) } - function randomLocalDateTime() { - const date = randomDate(); - const time = randomLocalTime(); - return new neo4j.types.LocalDateTime(date.year, date.month, date.day, time.hour, time.minute, time.second, time.nanosecond); + function randomLocalDateTime () { + const date = randomDate() + const time = randomLocalTime() + return new neo4j.types.LocalDateTime( + date.year, + date.month, + date.day, + time.hour, + time.minute, + time.second, + time.nanosecond + ) } - function randomDate() { + function randomDate () { return new neo4j.types.Date( randomInt(MIN_YEAR, MAX_YEAR), randomInt(1, 12), randomInt(1, 28) - ); + ) } - function randomTime() { - const localTime = randomLocalTime(); - return new neo4j.types.Time(localTime.hour, localTime.minute, localTime.second, localTime.nanosecond, randomZoneOffsetSeconds()); + function randomTime () { + const localTime = randomLocalTime() + return new neo4j.types.Time( + localTime.hour, + localTime.minute, + localTime.second, + localTime.nanosecond, + randomZoneOffsetSeconds() + ) } - function randomLocalTime() { + function randomLocalTime () { return new neo4j.types.LocalTime( randomInt(0, 23), randomInt(0, 59), randomInt(0, 59), randomInt(0, MAX_NANO_OF_SECOND) - ); + ) } - function randomDstSafeLocalTime() { + function randomDstSafeLocalTime () { return new neo4j.types.LocalTime( randomInt(4, 23), // do not generate hours in range where DST adjustment happens randomInt(0, 59), randomInt(0, 59), randomInt(0, MAX_NANO_OF_SECOND) - ); + ) } - function randomZoneOffsetSeconds() { - const randomOffsetWithSeconds = neo4j.int(randomInt(MIN_TIME_ZONE_OFFSET, MAX_TIME_ZONE_OFFSET)); - return randomOffsetWithSeconds.div(SECONDS_PER_MINUTE).multiply(SECONDS_PER_MINUTE); // truncate seconds + function randomZoneOffsetSeconds () { + const randomOffsetWithSeconds = neo4j.int( + randomInt(MIN_TIME_ZONE_OFFSET, MAX_TIME_ZONE_OFFSET) + ) + return randomOffsetWithSeconds + .div(SECONDS_PER_MINUTE) + .multiply(SECONDS_PER_MINUTE) // truncate seconds } - function randomZoneId() { - return _.sample(ZONE_IDS); + function randomZoneId () { + return _.sample(ZONE_IDS) } - function duration(months, days, seconds, nanoseconds) { - return new neo4j.types.Duration(neo4j.int(months), neo4j.int(days), neo4j.int(seconds), neo4j.int(nanoseconds)); + function duration (months, days, seconds, nanoseconds) { + return new neo4j.types.Duration( + neo4j.int(months), + neo4j.int(days), + neo4j.int(seconds), + neo4j.int(nanoseconds) + ) } - function localTime(hour, minute, second, nanosecond) { - return new neo4j.types.LocalTime(neo4j.int(hour), neo4j.int(minute), neo4j.int(second), neo4j.int(nanosecond)); + function localTime (hour, minute, second, nanosecond) { + return new neo4j.types.LocalTime( + neo4j.int(hour), + neo4j.int(minute), + neo4j.int(second), + neo4j.int(nanosecond) + ) } - function time(hour, minute, second, nanosecond, offsetSeconds) { - return new neo4j.types.Time(neo4j.int(hour), neo4j.int(minute), neo4j.int(second), neo4j.int(nanosecond), neo4j.int(offsetSeconds)); + function time (hour, minute, second, nanosecond, offsetSeconds) { + return new neo4j.types.Time( + neo4j.int(hour), + neo4j.int(minute), + neo4j.int(second), + neo4j.int(nanosecond), + neo4j.int(offsetSeconds) + ) } - function date(year, month, day) { - return new neo4j.types.Date(neo4j.int(year), neo4j.int(month), neo4j.int(day)); + function date (year, month, day) { + return new neo4j.types.Date( + neo4j.int(year), + neo4j.int(month), + neo4j.int(day) + ) } - function localDateTime(year, month, day, hour, minute, second, nanosecond) { - return new neo4j.types.LocalDateTime(neo4j.int(year), neo4j.int(month), neo4j.int(day), - neo4j.int(hour), neo4j.int(minute), neo4j.int(second), neo4j.int(nanosecond)); + function localDateTime (year, month, day, hour, minute, second, nanosecond) { + return new neo4j.types.LocalDateTime( + neo4j.int(year), + neo4j.int(month), + neo4j.int(day), + neo4j.int(hour), + neo4j.int(minute), + neo4j.int(second), + neo4j.int(nanosecond) + ) } - function dateTimeWithZoneOffset(year, month, day, hour, minute, second, nanosecond, offsetSeconds) { - return new neo4j.types.DateTime(neo4j.int(year), neo4j.int(month), neo4j.int(day), - neo4j.int(hour), neo4j.int(minute), neo4j.int(second), neo4j.int(nanosecond), neo4j.int(offsetSeconds), null); + function dateTimeWithZoneOffset ( + year, + month, + day, + hour, + minute, + second, + nanosecond, + offsetSeconds + ) { + return new neo4j.types.DateTime( + neo4j.int(year), + neo4j.int(month), + neo4j.int(day), + neo4j.int(hour), + neo4j.int(minute), + neo4j.int(second), + neo4j.int(nanosecond), + neo4j.int(offsetSeconds), + null + ) } - function dateTimeWithZoneId(year, month, day, hour, minute, second, nanosecond, zoneId) { - return new neo4j.types.DateTime(neo4j.int(year), neo4j.int(month), neo4j.int(day), - neo4j.int(hour), neo4j.int(minute), neo4j.int(second), neo4j.int(nanosecond), null, zoneId); + function dateTimeWithZoneId ( + year, + month, + day, + hour, + minute, + second, + nanosecond, + zoneId + ) { + return new neo4j.types.DateTime( + neo4j.int(year), + neo4j.int(month), + neo4j.int(day), + neo4j.int(hour), + neo4j.int(minute), + neo4j.int(second), + neo4j.int(nanosecond), + null, + zoneId + ) } - function randomInt(lower, upper) { - return neo4j.int(_.random(lower, upper)); + function randomInt (lower, upper) { + return neo4j.int(_.random(lower, upper)) } - function testStandardDateToLocalTimeConversion(date, nanosecond) { - const converted = neo4j.types.LocalTime.fromStandardDate(date, nanosecond); - const expected = new neo4j.types.LocalTime(date.getHours(), date.getMinutes(), date.getSeconds(), totalNanoseconds(date, nanosecond)); - expect(converted).toEqual(expected); + function testStandardDateToLocalTimeConversion (date, nanosecond) { + const converted = neo4j.types.LocalTime.fromStandardDate(date, nanosecond) + const expected = new neo4j.types.LocalTime( + date.getHours(), + date.getMinutes(), + date.getSeconds(), + totalNanoseconds(date, nanosecond) + ) + expect(converted).toEqual(expected) } - function testStandardDateToTimeConversion(date, nanosecond) { - const converted = neo4j.types.Time.fromStandardDate(date, nanosecond); - const expected = new neo4j.types.Time(date.getHours(), date.getMinutes(), date.getSeconds(), totalNanoseconds(date, nanosecond), - timeZoneOffsetInSeconds(date)); - expect(converted).toEqual(expected); + function testStandardDateToTimeConversion (date, nanosecond) { + const converted = neo4j.types.Time.fromStandardDate(date, nanosecond) + const expected = new neo4j.types.Time( + date.getHours(), + date.getMinutes(), + date.getSeconds(), + totalNanoseconds(date, nanosecond), + timeZoneOffsetInSeconds(date) + ) + expect(converted).toEqual(expected) } - function testStandardDateToNeo4jDateConversion(date) { - const converted = neo4j.types.Date.fromStandardDate(date); - const expected = new neo4j.types.Date(date.getFullYear(), date.getMonth() + 1, date.getDate()); - expect(converted).toEqual(expected); + function testStandardDateToNeo4jDateConversion (date) { + const converted = neo4j.types.Date.fromStandardDate(date) + const expected = new neo4j.types.Date( + date.getFullYear(), + date.getMonth() + 1, + date.getDate() + ) + expect(converted).toEqual(expected) } - function testStandardDateToLocalDateTimeConversion(date, nanosecond) { - const converted = neo4j.types.LocalDateTime.fromStandardDate(date, nanosecond); - const expected = new neo4j.types.LocalDateTime(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), - date.getSeconds(), totalNanoseconds(date, nanosecond)); - expect(converted).toEqual(expected); + function testStandardDateToLocalDateTimeConversion (date, nanosecond) { + const converted = neo4j.types.LocalDateTime.fromStandardDate( + date, + nanosecond + ) + const expected = new neo4j.types.LocalDateTime( + date.getFullYear(), + date.getMonth() + 1, + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + totalNanoseconds(date, nanosecond) + ) + expect(converted).toEqual(expected) } - function testStandardDateToDateTimeConversion(date, nanosecond) { - const converted = neo4j.types.DateTime.fromStandardDate(date, nanosecond); - const expected = new neo4j.types.DateTime(date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), - totalNanoseconds(date, nanosecond), timeZoneOffsetInSeconds(date)); - expect(converted).toEqual(expected); + function testStandardDateToDateTimeConversion (date, nanosecond) { + const converted = neo4j.types.DateTime.fromStandardDate(date, nanosecond) + const expected = new neo4j.types.DateTime( + date.getFullYear(), + date.getMonth() + 1, + date.getDate(), + date.getHours(), + date.getMinutes(), + date.getSeconds(), + totalNanoseconds(date, nanosecond), + timeZoneOffsetInSeconds(date) + ) + expect(converted).toEqual(expected) } - function verifyTimeZoneOffset(temporal, expectedValue, expectedStringValue) { - expect(temporal.timeZoneOffsetSeconds).toEqual(expectedValue); - const isoString = temporal.toString(); + function verifyTimeZoneOffset (temporal, expectedValue, expectedStringValue) { + expect(temporal.timeZoneOffsetSeconds).toEqual(expectedValue) + const isoString = temporal.toString() // assert ISO string ends with the expected suffix - expect(isoString.indexOf(expectedStringValue, isoString.length - expectedStringValue.length)).toBeGreaterThan(0); + expect( + isoString.indexOf( + expectedStringValue, + isoString.length - expectedStringValue.length + ) + ).toBeGreaterThan(0) } -}); +}) diff --git a/test/v1/transaction.test.js b/test/v1/transaction.test.js index 46b03584b..ef801dad9 100644 --- a/test/v1/transaction.test.js +++ b/test/v1/transaction.test.js @@ -16,534 +16,599 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import neo4j, {Neo4jError} from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import {ServerVersion, VERSION_3_1_0} from '../../src/v1/internal/server-version'; -import {newError} from "../../src/v1/error"; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import { ServerVersion } from '../../src/v1/internal/server-version' describe('transaction', () => { - - let driver; - let session; - let serverVersion; - let originalTimeout; + let driver + let session + // eslint-disable-next-line no-unused-vars + let serverVersion + let originalTimeout beforeEach(done => { // make jasmine timeout high enough to test unreachable bookmarks - originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - jasmine.DEFAULT_TIMEOUT_INTERVAL = 40000; + originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + jasmine.DEFAULT_TIMEOUT_INTERVAL = 40000 - driver = neo4j.driver("bolt://localhost", sharedNeo4j.authToken); - session = driver.session(); + driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + session = driver.session() session.run('MATCH (n) DETACH DELETE n').then(result => { - serverVersion = ServerVersion.fromString(result.summary.server.version); - done(); - }); - }); + serverVersion = ServerVersion.fromString(result.summary.server.version) + done() + }) + }) afterEach(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - driver.close(); - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + driver.close() + }) it('should commit simple case', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.run("CREATE (:TXNode2)").then(() => { - tx.commit().then(() => { - session.run("MATCH (t1:TXNode1), (t2:TXNode2) RETURN count(t1), count(t2)").then(result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('count(t1)').toInt()).toBe(1); - expect(result.records[0].get('count(t2)').toInt()).toBe(1); - done(); - }).catch(console.log); - }).catch(console.log); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.run('CREATE (:TXNode2)') + .then(() => { + tx.commit() + .then(() => { + session + .run( + 'MATCH (t1:TXNode1), (t2:TXNode2) RETURN count(t1), count(t2)' + ) + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('count(t1)').toInt()).toBe(1) + expect(result.records[0].get('count(t2)').toInt()).toBe(1) + done() + }) + .catch(console.log) + }) + .catch(console.log) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should populate resultAvailableAfter for transaction#run', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(result => { - tx.commit().then(() => { - expect(result.summary.resultAvailableAfter).toBeDefined(); - expect(result.summary.resultAvailableAfter.toInt()).not.toBeLessThan(0); - done(); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(result => { + tx.commit() + .then(() => { + expect(result.summary.resultAvailableAfter).toBeDefined() + expect( + result.summary.resultAvailableAfter.toInt() + ).not.toBeLessThan(0) + done() + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should handle interactive session', done => { - const tx = session.beginTransaction(); - tx.run("RETURN 'foo' AS res").then(result => { - tx.run("CREATE ({name: {param}})", {param: result.records[0].get('res')}).then(() => { - tx.commit().then(() => { - session.run("MATCH (a {name:'foo'}) RETURN count(a)").then(result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('count(a)').toInt()).toBe(1); - done(); - }); - }).catch(console.log); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run("RETURN 'foo' AS res") + .then(result => { + tx.run('CREATE ({name: {param}})', { + param: result.records[0].get('res') + }) + .then(() => { + tx.commit() + .then(() => { + session + .run("MATCH (a {name:'foo'}) RETURN count(a)") + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('count(a)').toInt()).toBe(1) + done() + }) + }) + .catch(console.log) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should handle failures with subscribe', done => { - const tx = session.beginTransaction(); - tx.run('THIS IS NOT CYPHER') - .catch(error => { - expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError'); - driver.close(); - done(); - }); - }); + const tx = session.beginTransaction() + tx.run('THIS IS NOT CYPHER').catch(error => { + expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError') + driver.close() + done() + }) + }) it('should handle failures with catch', done => { - const tx = session.beginTransaction(); - tx.run('THIS IS NOT CYPHER') - .subscribe({ - onError: error => { - expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError'); - driver.close(); - done(); - } - }); - }); + const tx = session.beginTransaction() + tx.run('THIS IS NOT CYPHER').subscribe({ + onError: error => { + expect(error.code).toEqual('Neo.ClientError.Statement.SyntaxError') + driver.close() + done() + } + }) + }) it('should handle failures on commit', done => { // When - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.run("THIS IS NOT CYPHER").catch(statementError => { - expectSyntaxError(statementError); - - tx.run("CREATE (:TXNode2)").catch(() => { - tx.commit().catch(commitError => { - expect(commitError.error).toBeDefined(); - driver.close(); - done(); - }); - }); - }); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.run('THIS IS NOT CYPHER').catch(statementError => { + expectSyntaxError(statementError) + + tx.run('CREATE (:TXNode2)').catch(() => { + tx.commit().catch(commitError => { + expect(commitError.error).toBeDefined() + driver.close() + done() + }) + }) + }) + }) + .catch(console.log) + }) it('should fail when committing on a failed query', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.run("THIS IS NOT CYPHER").catch(() => { - tx.commit().catch(error => { - expect(error.error).toBeDefined(); - driver.close(); - done(); - }); - }); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.run('THIS IS NOT CYPHER').catch(() => { + tx.commit().catch(error => { + expect(error.error).toBeDefined() + driver.close() + done() + }) + }) + }) + .catch(console.log) + }) it('should handle when committing when another statement fails', done => { // When - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)") - .then(() => { - tx.commit() - .catch(error => { - expect(error).toBeDefined(); - driver.close(); - done(); - }); - }); - tx.run("THIS IS NOT CYPHER"); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)').then(() => { + tx.commit().catch(error => { + expect(error).toBeDefined() + driver.close() + done() + }) + }) + tx.run('THIS IS NOT CYPHER') + }) it('should handle rollbacks', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.run("CREATE (:TXNode2)").then(() => { - tx.rollback().then(() => { - session.run("MATCH (t1:TXNode1), (t2:TXNode2) RETURN count(t1), count(t2)").then(result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('count(t1)').toInt()).toBe(0); - expect(result.records[0].get('count(t2)').toInt()).toBe(0); - done(); - }).catch(console.log); - }).catch(console.log); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.run('CREATE (:TXNode2)') + .then(() => { + tx.rollback() + .then(() => { + session + .run( + 'MATCH (t1:TXNode1), (t2:TXNode2) RETURN count(t1), count(t2)' + ) + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('count(t1)').toInt()).toBe(0) + expect(result.records[0].get('count(t2)').toInt()).toBe(0) + done() + }) + .catch(console.log) + }) + .catch(console.log) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should fail when committing on a rolled back query', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.rollback().then(() => { - tx.commit().catch(error => { - expect(error.error).toBeDefined(); - driver.close(); - done(); - }); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.rollback() + .then(() => { + tx.commit().catch(error => { + expect(error.error).toBeDefined() + driver.close() + done() + }) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should fail when running on a rolled back transaction', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.rollback().then(() => { - tx.run("RETURN 42").catch(error => { - expect(error.error).toBeDefined(); - driver.close(); - done(); - }); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.rollback() + .then(() => { + tx.run('RETURN 42').catch(error => { + expect(error.error).toBeDefined() + driver.close() + done() + }) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should fail when running when a previous statement failed', done => { - const tx = session.beginTransaction(); - tx.run("THIS IS NOT CYPHER") - .catch(() => { - tx.run("RETURN 42") - .catch(error => { - expect(error.error).toBeDefined(); - driver.close(); - done(); - }); - }); - tx.rollback(); - }); + const tx = session.beginTransaction() + tx.run('THIS IS NOT CYPHER').catch(() => { + tx.run('RETURN 42').catch(error => { + expect(error.error).toBeDefined() + driver.close() + done() + }) + }) + tx.rollback() + }) it('should fail when trying to roll back a rolled back transaction', done => { - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.rollback().then(() => { - tx.rollback().catch(error => { - expect(error.error).toBeDefined(); - driver.close(); - done(); - }); - }).catch(console.log); - }).catch(console.log); - }); + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.rollback() + .then(() => { + tx.rollback().catch(error => { + expect(error.error).toBeDefined() + driver.close() + done() + }) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should provide bookmark on commit', done => { // new session without initial bookmark - session = driver.session(); - expect(session.lastBookmark()).toBeNull(); - - const tx = session.beginTransaction(); - tx.run("CREATE (:TXNode1)").then(() => { - tx.run("CREATE (:TXNode2)").then(() => { - tx.commit().then(() => { - expectValidLastBookmark(session); - done(); - }); - }).catch(console.log); - }).catch(console.log); - }); + session = driver.session() + expect(session.lastBookmark()).toBeNull() + + const tx = session.beginTransaction() + tx.run('CREATE (:TXNode1)') + .then(() => { + tx.run('CREATE (:TXNode2)') + .then(() => { + tx.commit().then(() => { + expectValidLastBookmark(session) + done() + }) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should have bookmark when tx is rolled back', done => { // new session without initial bookmark - session = driver.session(); - expect(session.lastBookmark()).toBeNull(); + session = driver.session() + expect(session.lastBookmark()).toBeNull() - const tx1 = session.beginTransaction(); + const tx1 = session.beginTransaction() tx1.run('CREATE ()').then(() => { tx1.commit().then(() => { - expectValidLastBookmark(session); - const bookmarkBefore = session.lastBookmark(); + expectValidLastBookmark(session) + const bookmarkBefore = session.lastBookmark() - const tx2 = session.beginTransaction(); + const tx2 = session.beginTransaction() tx2.run('CREATE ()').then(() => { tx2.rollback().then(() => { - expectValidLastBookmark(session); - const bookmarkAfter = session.lastBookmark(); - expect(bookmarkAfter).toEqual(bookmarkBefore); + expectValidLastBookmark(session) + const bookmarkAfter = session.lastBookmark() + expect(bookmarkAfter).toEqual(bookmarkBefore) - const tx3 = session.beginTransaction(); + const tx3 = session.beginTransaction() tx3.run('CREATE ()').then(() => { tx3.commit().then(() => { - expectValidLastBookmark(session); - done(); - }); - }); - }); - }); - }); - }); - }); + expectValidLastBookmark(session) + done() + }) + }) + }) + }) + }) + }) + }) it('should have no bookmark when tx fails', done => { // new session without initial bookmark - session = driver.session(); - expect(session.lastBookmark()).toBeNull(); + session = driver.session() + expect(session.lastBookmark()).toBeNull() - const tx1 = session.beginTransaction(); + const tx1 = session.beginTransaction() tx1.run('CREATE ()').then(() => { tx1.commit().then(() => { - expectValidLastBookmark(session); - const bookmarkBefore = session.lastBookmark(); + expectValidLastBookmark(session) + const bookmarkBefore = session.lastBookmark() - const tx2 = session.beginTransaction(); + const tx2 = session.beginTransaction() tx2.run('RETURN').catch(error => { - expectSyntaxError(error); - const bookmarkAfter = session.lastBookmark(); - expect(bookmarkAfter).toEqual(bookmarkBefore); + expectSyntaxError(error) + const bookmarkAfter = session.lastBookmark() + expect(bookmarkAfter).toEqual(bookmarkBefore) - const tx3 = session.beginTransaction(); + const tx3 = session.beginTransaction() tx3.run('CREATE ()').then(() => { tx3.commit().then(() => { - expectValidLastBookmark(session); - done(); - }); - }); - }); - }); - }); - }); + expectValidLastBookmark(session) + done() + }) + }) + }) + }) + }) + }) it('should fail for invalid bookmark', done => { - const invalidBookmark = 'hi, this is an invalid bookmark'; - const tx = session.beginTransaction(invalidBookmark); + const invalidBookmark = 'hi, this is an invalid bookmark' + const tx = session.beginTransaction(invalidBookmark) tx.run('RETURN 1').catch(error => { - expect(error.code).toBe('Neo.ClientError.Transaction.InvalidBookmark'); - done(); - }); - }); + expect(error.code).toBe('Neo.ClientError.Transaction.InvalidBookmark') + done() + }) + }) it('should fail to run query for unreachable bookmark', done => { - const tx1 = session.beginTransaction(); - tx1.run('CREATE ()').then(result => { - expect(result.summary.counters.nodesCreated()).toBe(1); - - tx1.commit().then(() => { - expectValidLastBookmark(session); - - const unreachableBookmark = session.lastBookmark() + "0"; - const tx2 = session.beginTransaction(unreachableBookmark); - tx2.run('CREATE ()').catch(error => { - const message = error.message; - const expectedPrefix = message.indexOf('Database not up to the requested version') === 0; - expect(expectedPrefix).toBeTruthy(); - done(); - }); - }).catch(console.log); - }).catch(console.log); - }); + const tx1 = session.beginTransaction() + tx1 + .run('CREATE ()') + .then(result => { + expect(result.summary.counters.nodesCreated()).toBe(1) + + tx1 + .commit() + .then(() => { + expectValidLastBookmark(session) + + const unreachableBookmark = session.lastBookmark() + '0' + const tx2 = session.beginTransaction(unreachableBookmark) + tx2.run('CREATE ()').catch(error => { + const message = error.message + const expectedPrefix = + message.indexOf('Database not up to the requested version') === + 0 + expect(expectedPrefix).toBeTruthy() + done() + }) + }) + .catch(console.log) + }) + .catch(console.log) + }) it('should rollback when very first run fails', done => { - const tx1 = session.beginTransaction(); + const tx1 = session.beginTransaction() tx1.run('RETURN foo').catch(error => { - expectSyntaxError(error); + expectSyntaxError(error) - const tx2 = session.beginTransaction(); + const tx2 = session.beginTransaction() tx2.run('RETURN 1').then(result => { - expect(result.records[0].get(0).toNumber()).toEqual(1); - tx2.commit().then(done); - }); - }); - }); + expect(result.records[0].get(0).toNumber()).toEqual(1) + tx2.commit().then(done) + }) + }) + }) it('should rollback when some run fails', done => { - const tx1 = session.beginTransaction(); + const tx1 = session.beginTransaction() tx1.run('CREATE (:Person)').then(() => { tx1.run('RETURN foo').catch(error => { - expectSyntaxError(error); + expectSyntaxError(error) - const tx2 = session.beginTransaction(); + const tx2 = session.beginTransaction() tx2.run('MATCH (n:Person) RETURN count(n)').then(result => { - expect(result.records[0].get(0).toNumber()).toEqual(0); - tx2.commit().then(done); - }); - }); - }); - }); + expect(result.records[0].get(0).toNumber()).toEqual(0) + tx2.commit().then(done) + }) + }) + }) + }) it('should fail to commit transaction that had run failures', done => { - const tx1 = session.beginTransaction(); + const tx1 = session.beginTransaction() tx1.run('CREATE (:Person)').then(() => { tx1.run('RETURN foo').catch(error => { - expectSyntaxError(error); + expectSyntaxError(error) tx1.commit().catch(error => { - const errorMessage = error.error; - const index = errorMessage.indexOf('Cannot commit statements in this transaction'); - expect(index).not.toBeLessThan(0); + const errorMessage = error.error + const index = errorMessage.indexOf( + 'Cannot commit statements in this transaction' + ) + expect(index).not.toBeLessThan(0) - const tx2 = session.beginTransaction(); + const tx2 = session.beginTransaction() tx2.run('MATCH (n:Person) RETURN count(n)').then(result => { - expect(result.records[0].get(0).toNumber()).toEqual(0); - done(); - }); - }); - }); - }); - }); + expect(result.records[0].get(0).toNumber()).toEqual(0) + done() + }) + }) + }) + }) + }) it('should expose server info on successful query', done => { - const statement = 'RETURN 1'; - - const tx = session.beginTransaction(); - tx.run(statement).then(result => { - const sum = result.summary; - expect(sum.server).toBeDefined(); - expect(sum.server.address).toEqual('localhost:7687'); - expect(sum.server.version).toBeDefined(); - tx.commit().then(done); - }).catch(console.log); - }); + const statement = 'RETURN 1' + + const tx = session.beginTransaction() + tx.run(statement) + .then(result => { + const sum = result.summary + expect(sum.server).toBeDefined() + expect(sum.server.address).toEqual('localhost:7687') + expect(sum.server.version).toBeDefined() + tx.commit().then(done) + }) + .catch(console.log) + }) it('should expose server info on successful query using observer', done => { // Given - const statement = 'RETURN 1'; + const statement = 'RETURN 1' // When & Then - const tx = session.beginTransaction(); - tx.run(statement) - .subscribe({ - onNext: record => { - }, - onError: error => { - }, - onCompleted: summary => { - const server = summary.server; - - expect(server).toBeDefined(); - expect(server.address).toEqual('localhost:7687'); - expect(server.version).toBeDefined(); - - done(); - } - }); - }); + const tx = session.beginTransaction() + tx.run(statement).subscribe({ + onNext: record => {}, + onError: () => {}, + onCompleted: summary => { + const server = summary.server + + expect(server).toBeDefined() + expect(server.address).toEqual('localhost:7687') + expect(server.version).toBeDefined() + + done() + } + }) + }) it('should fail nicely for illegal statement', () => { - const tx = session.beginTransaction(); + const tx = session.beginTransaction() - expect(() => tx.run()).toThrowError(TypeError); - expect(() => tx.run(null)).toThrowError(TypeError); - expect(() => tx.run({})).toThrowError(TypeError); - expect(() => tx.run(42)).toThrowError(TypeError); - expect(() => tx.run([])).toThrowError(TypeError); - expect(() => tx.run(['CREATE ()'])).toThrowError(TypeError); + expect(() => tx.run()).toThrowError(TypeError) + expect(() => tx.run(null)).toThrowError(TypeError) + expect(() => tx.run({})).toThrowError(TypeError) + expect(() => tx.run(42)).toThrowError(TypeError) + expect(() => tx.run([])).toThrowError(TypeError) + expect(() => tx.run(['CREATE ()'])).toThrowError(TypeError) - expect(() => tx.run({statement: 'CREATE ()'})).toThrowError(TypeError); - expect(() => tx.run({cypher: 'CREATE ()'})).toThrowError(TypeError); - }); + expect(() => tx.run({ statement: 'CREATE ()' })).toThrowError(TypeError) + expect(() => tx.run({ cypher: 'CREATE ()' })).toThrowError(TypeError) + }) it('should accept a statement object ', done => { - const tx = session.beginTransaction(); - const statement = {text: "RETURN 1 AS a"}; + const tx = session.beginTransaction() + const statement = { text: 'RETURN 1 AS a' } - tx.run(statement).then(result => { - expect(result.records.length).toBe(1); - expect(result.records[0].get('a').toInt()).toBe(1); - done(); - }).catch(console.log); - }); + tx.run(statement) + .then(result => { + expect(result.records.length).toBe(1) + expect(result.records[0].get('a').toInt()).toBe(1) + done() + }) + .catch(console.log) + }) it('should be open when neither committed nor rolled back', () => { - const tx = session.beginTransaction(); - expect(tx.isOpen()).toBeTruthy(); - }); + const tx = session.beginTransaction() + expect(tx.isOpen()).toBeTruthy() + }) it('should not be open after commit', done => { - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('CREATE ()').then(() => { tx.commit().then(() => { - expect(tx.isOpen()).toBeFalsy(); - done(); - }); - }); - }); + expect(tx.isOpen()).toBeFalsy() + done() + }) + }) + }) it('should not be open after rollback', done => { - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('CREATE ()').then(() => { tx.rollback().then(() => { - expect(tx.isOpen()).toBeFalsy(); - done(); - }); - }); - }); + expect(tx.isOpen()).toBeFalsy() + done() + }) + }) + }) it('should not be open after run error', done => { - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('RETURN').catch(() => { - expect(tx.isOpen()).toBeFalsy(); - done(); - }); - }); + expect(tx.isOpen()).toBeFalsy() + done() + }) + }) it('should respect socket connection timeout', done => { - testConnectionTimeout(false, done); - }); + testConnectionTimeout(false, done) + }) it('should respect TLS socket connection timeout', done => { - testConnectionTimeout(true, done); - }); + testConnectionTimeout(true, done) + }) it('should fail for invalid query parameters', done => { - const tx = session.beginTransaction(); + const tx = session.beginTransaction() - expect(() => tx.run('RETURN $value', 'Hello')).toThrowError(TypeError); - expect(() => tx.run('RETURN $value', 12345)).toThrowError(TypeError); - expect(() => tx.run('RETURN $value', () => 'Hello')).toThrowError(TypeError); + expect(() => tx.run('RETURN $value', 'Hello')).toThrowError(TypeError) + expect(() => tx.run('RETURN $value', 12345)).toThrowError(TypeError) + expect(() => tx.run('RETURN $value', () => 'Hello')).toThrowError(TypeError) - tx.rollback().then(() => done()); - }); + tx.rollback().then(() => done()) + }) it('should allow rollback after failure', done => { - const tx = session.beginTransaction(); + const tx = session.beginTransaction() tx.run('WRONG QUERY') .then(() => done.fail('Expected to fail')) .catch(error => { - expectSyntaxError(error); + expectSyntaxError(error) tx.rollback() .catch(error => done.fail(error)) - .then(() => done()); - }); - }); + .then(() => done()) + }) + }) - function expectSyntaxError(error) { - expect(error.code).toBe('Neo.ClientError.Statement.SyntaxError'); + function expectSyntaxError (error) { + expect(error.code).toBe('Neo.ClientError.Statement.SyntaxError') } - function expectValidLastBookmark(session) { - expect(session.lastBookmark()).toBeDefined(); - expect(session.lastBookmark()).not.toBeNull(); + function expectValidLastBookmark (session) { + expect(session.lastBookmark()).toBeDefined() + expect(session.lastBookmark()).not.toBeNull() } - function testConnectionTimeout(encrypted, done) { - const boltUri = 'bolt://10.0.0.0'; // use non-routable IP address which never responds - const config = {encrypted: encrypted, connectionTimeout: 1000}; - - const localDriver = neo4j.driver(boltUri, sharedNeo4j.authToken, config); - const session = localDriver.session(); - const tx = session.beginTransaction(); - tx.run('RETURN 1').then(() => { - tx.rollback(); - session.close(); - done.fail('Query did not fail'); - }).catch(error => { - tx.rollback(); - session.close(); - - expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE); - - // in some environments non-routable address results in immediate 'connection refused' error and connect - // timeout is not fired; skip message assertion for such cases, it is important for connect attempt to not hang - if (error.message.indexOf('Failed to establish connection') === 0) { - expect(error.message).toEqual('Failed to establish connection in 1000ms'); - } + function testConnectionTimeout (encrypted, done) { + const boltUri = 'bolt://10.0.0.0' // use non-routable IP address which never responds + const config = { encrypted: encrypted, connectionTimeout: 1000 } - done(); - }); - } + const localDriver = neo4j.driver(boltUri, sharedNeo4j.authToken, config) + const session = localDriver.session() + const tx = session.beginTransaction() + tx.run('RETURN 1') + .then(() => { + tx.rollback() + session.close() + done.fail('Query did not fail') + }) + .catch(error => { + tx.rollback() + session.close() + + expect(error.code).toEqual(neo4j.error.SERVICE_UNAVAILABLE) -}); + // in some environments non-routable address results in immediate 'connection refused' error and connect + // timeout is not fired; skip message assertion for such cases, it is important for connect attempt to not hang + if (error.message.indexOf('Failed to establish connection') === 0) { + expect(error.message).toEqual( + 'Failed to establish connection in 1000ms' + ) + } + + done() + }) + } +}) diff --git a/test/v1/types.test.js b/test/v1/types.test.js index dad2b70dd..d482ec6a1 100644 --- a/test/v1/types.test.js +++ b/test/v1/types.test.js @@ -17,277 +17,315 @@ * limitations under the License. */ -import neo4j from '../../src/v1'; -import sharedNeo4j from '../internal/shared-neo4j'; -import _ from 'lodash'; -import {ServerVersion, VERSION_3_2_0} from '../../src/v1/internal/server-version'; +import neo4j from '../../src/v1' +import sharedNeo4j from '../internal/shared-neo4j' +import _ from 'lodash' +import { + ServerVersion, + VERSION_3_2_0 +} from '../../src/v1/internal/server-version' describe('null value', () => { - it('should support null', testValue(null)); -}); + it('should support null', testValue(null)) +}) describe('floating point values', () => { - it('should support float 1.0 ', testValue(1)); - it('should support float 0.0 ', testValue(0.0)); - it('should support pretty big float ', testValue(3.4028235e+38)); // Max 32-bit - it('should support really big float ', testValue(1.7976931348623157e+308)); // Max 64-bit - it('should support pretty small float ', testValue(1.4e-45)); // Min 32-bit - it('should support really small float ', testValue(4.9e-324)); // Min 64-bit -}); + it('should support float 1.0 ', testValue(1)) + it('should support float 0.0 ', testValue(0.0)) + it('should support pretty big float ', testValue(3.4028235e38)) // Max 32-bit + it('should support really big float ', testValue(1.7976931348623157e308)) // Max 64-bit + it('should support pretty small float ', testValue(1.4e-45)) // Min 32-bit + it('should support really small float ', testValue(4.9e-324)) // Min 64-bit +}) describe('integer values', () => { - it('should support integer 1 ', testValue(neo4j.int(1))); - it('should support integer 0 ', testValue(neo4j.int(0))); - it('should support integer -1 ', testValue(neo4j.int(-1))); - it('should support integer larger than JS Numbers can model', testValue(neo4j.int('0x7fffffffffffffff'))); - it('should support integer smaller than JS Numbers can model', testValue(neo4j.int('0x8000000000000000'))); -}); + it('should support integer 1 ', testValue(neo4j.int(1))) + it('should support integer 0 ', testValue(neo4j.int(0))) + it('should support integer -1 ', testValue(neo4j.int(-1))) + it( + 'should support integer larger than JS Numbers can model', + testValue(neo4j.int('0x7fffffffffffffff')) + ) + it( + 'should support integer smaller than JS Numbers can model', + testValue(neo4j.int('0x8000000000000000')) + ) +}) describe('boolean values', () => { - it('should support true ', testValue(true)); - it('should support false ', testValue(false)); -}); + it('should support true ', testValue(true)) + it('should support false ', testValue(false)) +}) describe('string values', () => { - it('should support empty string ', testValue('')); - it('should support simple string ', testValue('abcdefghijklmnopqrstuvwxyz')); - it('should support awesome string ', testValue('All makt åt Tengil, vår befriare.')); + it('should support empty string ', testValue('')) + it('should support simple string ', testValue('abcdefghijklmnopqrstuvwxyz')) + it( + 'should support awesome string ', + testValue('All makt åt Tengil, vår befriare.') + ) it('should support long string', testValue('*'.repeat(10000))) -}); +}) describe('list values', () => { - it('should support empty lists ', testValue([])); - it('should support sparse lists ', testValue([undefined, 4], [null, 4])); - it('should support float lists ', testValue([1, 2, 3])); - it('should support boolean lists ', testValue([true, false])); - it('should support string lists ', testValue(['', 'hello!'])); - it('should support list lists ', testValue([[], [1, 2, 3]])); - it('should support map lists ', testValue([{}, {a: 12}])); - it('should support long list', testValue(Array.from({length: 1000}, (v, i) => i))) -}); + it('should support empty lists ', testValue([])) + it('should support sparse lists ', testValue([undefined, 4], [null, 4])) + it('should support float lists ', testValue([1, 2, 3])) + it('should support boolean lists ', testValue([true, false])) + it('should support string lists ', testValue(['', 'hello!'])) + it('should support list lists ', testValue([[], [1, 2, 3]])) + it('should support map lists ', testValue([{}, { a: 12 }])) + it( + 'should support long list', + testValue(Array.from({ length: 1000 }, (v, i) => i)) + ) +}) describe('map values', () => { - it('should support empty maps ', testValue({})); - it('should support basic maps ', testValue({a: 1, b: {}, c: [], d: {e: 1}})); - it('should support sparse maps ', testValue({foo: undefined, bar: null}, {bar: null})); - - function longMap() { - const map = {}; - for (let i = 0; i < 1000; i ++ ) - { - map["key"+i]=i; + it('should support empty maps ', testValue({})) + it( + 'should support basic maps ', + testValue({ a: 1, b: {}, c: [], d: { e: 1 } }) + ) + it( + 'should support sparse maps ', + testValue({ foo: undefined, bar: null }, { bar: null }) + ) + + function longMap () { + const map = {} + for (let i = 0; i < 1000; i++) { + map['key' + i] = i } - return map; + return map } it('should support long maps', testValue(longMap())) -}); +}) describe('node values', () => { it('should support returning nodes ', done => { // Given - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const session = driver.session(); + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const session = driver.session() // When - session.run('CREATE (n:User {name:\'Lisa\'}) RETURN n, id(n)').then(result => { - const node = result.records[0].get('n'); - - expect(node.properties).toEqual({name: 'Lisa'}); - expect(node.labels).toEqual(['User']); - expect(node.identity).toEqual(result.records[0].get('id(n)')); - driver.close(); - done(); + session + .run("CREATE (n:User {name:'Lisa'}) RETURN n, id(n)") + .then(result => { + const node = result.records[0].get('n') - }); - }); -}); + expect(node.properties).toEqual({ name: 'Lisa' }) + expect(node.labels).toEqual(['User']) + expect(node.identity).toEqual(result.records[0].get('id(n)')) + driver.close() + done() + }) + }) +}) describe('relationship values', () => { it('should support returning relationships', done => { // Given - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const session = driver.session(); + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const session = driver.session() // When - session.run('CREATE ()-[r:User {name:\'Lisa\'}]->() RETURN r, id(r)').then(result => { - const rel = result.records[0].get('r'); - - expect(rel.properties).toEqual({name: 'Lisa'}); - expect(rel.type).toEqual('User'); - expect(rel.identity).toEqual(result.records[0].get('id(r)')); - driver.close(); - done(); + session + .run("CREATE ()-[r:User {name:'Lisa'}]->() RETURN r, id(r)") + .then(result => { + const rel = result.records[0].get('r') - }); - }); -}); + expect(rel.properties).toEqual({ name: 'Lisa' }) + expect(rel.type).toEqual('User') + expect(rel.identity).toEqual(result.records[0].get('id(r)')) + driver.close() + done() + }) + }) +}) describe('path values', () => { it('should support returning paths', done => { // Given - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const session = driver.session(); + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const session = driver.session() // When - session.run('CREATE p=(:User { name:\'Lisa\' })<-[r:KNOWS {since:1234.0}]-() RETURN p') + session + .run( + "CREATE p=(:User { name:'Lisa' })<-[r:KNOWS {since:1234.0}]-() RETURN p" + ) .then(result => { - const path = result.records[0].get('p'); + const path = result.records[0].get('p') - expect(path.start.properties).toEqual({name: 'Lisa'}); - expect(path.end.properties).toEqual({}); + expect(path.start.properties).toEqual({ name: 'Lisa' }) + expect(path.end.properties).toEqual({}) // Accessing path segments - expect(path.length).toEqual(1); + expect(path.length).toEqual(1) for (let i = 0; i < path.length; i++) { - const segment = path.segments[i]; + const segment = path.segments[i] // The direction of the path segment goes from lisa to the blank node - expect(segment.start.properties).toEqual({name: 'Lisa'}); - expect(segment.end.properties).toEqual({}); + expect(segment.start.properties).toEqual({ name: 'Lisa' }) + expect(segment.end.properties).toEqual({}) // Which is the inverse of the relationship itself! - expect(segment.relationship.properties).toEqual({since: 1234}); + expect(segment.relationship.properties).toEqual({ since: 1234 }) } - driver.close(); - done(); - }).catch(err => { - console.log(err); - }); - }); -}); + driver.close() + done() + }) + .catch(err => { + console.log(err) + }) + }) +}) describe('byte arrays', () => { - - let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL; - let serverSupportsByteArrays = false; + let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL + let serverSupportsByteArrays = false beforeAll(done => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; + jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000 - const tmpDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); + const tmpDriver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) ServerVersion.fromDriver(tmpDriver).then(version => { - tmpDriver.close(); - serverSupportsByteArrays = version.compareTo(VERSION_3_2_0) >= 0; - done(); - }); - }); + tmpDriver.close() + serverSupportsByteArrays = version.compareTo(VERSION_3_2_0) >= 0 + done() + }) + }) afterAll(() => { - jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout; - }); + jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout + }) it('should support returning empty byte array if server supports byte arrays', done => { if (!serverSupportsByteArrays) { - done(); - return; + done() + return } - testValue(new Int8Array(0))(done); - }); + testValue(new Int8Array(0))(done) + }) it('should support returning empty byte array if server supports byte arrays', done => { if (!serverSupportsByteArrays) { - done(); - return; + done() + return } - testValues([new Int8Array(0)])(done); - }); + testValues([new Int8Array(0)])(done) + }) it('should support returning short byte arrays if server supports byte arrays', done => { if (!serverSupportsByteArrays) { - done(); - return; + done() + return } - testValues(randomByteArrays(100, 1, 255))(done); - }); + testValues(randomByteArrays(100, 1, 255))(done) + }) it('should support returning medium byte arrays if server supports byte arrays', done => { if (!serverSupportsByteArrays) { - done(); - return; + done() + return } - testValues(randomByteArrays(50, 256, 65535))(done); - }); + testValues(randomByteArrays(50, 256, 65535))(done) + }) it('should support returning long byte arrays if server supports byte arrays', done => { if (!serverSupportsByteArrays) { - done(); - return; + done() + return } - testValues(randomByteArrays(10, 65536, 2 * 65536))(done); - }); + testValues(randomByteArrays(10, 65536, 2 * 65536))(done) + }) it('should fail to return byte array if server does not support byte arrays', done => { if (serverSupportsByteArrays) { - done(); - return; + done() + return } - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const session = driver.session(); - session.run('RETURN {array}', {array: randomByteArray(42)}).catch(error => { - driver.close(); - expect(error.message).toEqual('Byte arrays are not supported by the database this driver is connected to'); - done(); - }); - }); -}); - -function testValue(actual, expected) { + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const session = driver.session() + session + .run('RETURN {array}', { array: randomByteArray(42) }) + .catch(error => { + driver.close() + expect(error.message).toEqual( + 'Byte arrays are not supported by the database this driver is connected to' + ) + done() + }) + }) +}) + +function testValue (actual, expected) { return done => { - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const queryPromise = runReturnQuery(driver, actual, expected); - - queryPromise.then(() => { - driver.close(); - done(); - }).catch(error => { - driver.close(); - console.log(error); - }); - }; + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const queryPromise = runReturnQuery(driver, actual, expected) + + queryPromise + .then(() => { + driver.close() + done() + }) + .catch(error => { + driver.close() + console.log(error) + }) + } } -function testValues(values) { +function testValues (values) { return done => { - const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken); - const queriesPromise = values.reduce((acc, value) => - acc.then(() => runReturnQuery(driver, value)), Promise.resolve()); - - queriesPromise.then(() => { - driver.close(); - done(); - }).catch(error => { - driver.close(); - console.log(error); - }); - }; + const driver = neo4j.driver('bolt://localhost', sharedNeo4j.authToken) + const queriesPromise = values.reduce( + (acc, value) => acc.then(() => runReturnQuery(driver, value)), + Promise.resolve() + ) + + queriesPromise + .then(() => { + driver.close() + done() + }) + .catch(error => { + driver.close() + console.log(error) + }) + } } -function runReturnQuery(driver, actual, expected) { - const session = driver.session(); +function runReturnQuery (driver, actual, expected) { + const session = driver.session() return new Promise((resolve, reject) => { - session.run('RETURN {val} as v', {val: actual}).then(result => { - expect(result.records[0].get('v')).toEqual(expected || actual); - session.close(); - resolve(); - }).catch(error => { - reject(error); - }); - }); + session + .run('RETURN {val} as v', { val: actual }) + .then(result => { + expect(result.records[0].get('v')).toEqual(expected || actual) + session.close() + resolve() + }) + .catch(error => { + reject(error) + }) + }) } -function randomByteArrays(count, minLength, maxLength) { +function randomByteArrays (count, minLength, maxLength) { return _.range(count).map(() => { - const length = _.random(minLength, maxLength); - return randomByteArray(length); - }); + const length = _.random(minLength, maxLength) + return randomByteArray(length) + }) } -function randomByteArray(length) { - const array = _.range(length).map(() => _.random(-128, 127)); - return new Int8Array(array); +function randomByteArray (length) { + const array = _.range(length).map(() => _.random(-128, 127)) + return new Int8Array(array) } diff --git a/tsconfig.json b/tsconfig.json index a8685bde8..4881be175 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,4 +5,4 @@ "noImplicitAny": true, "noImplicitReturns": true } -} \ No newline at end of file +} diff --git a/types/index.d.ts b/types/index.d.ts index 296efa715..5a8205b25 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -17,7 +17,7 @@ * limitations under the License. */ -import * as v1 from "./v1/index"; +import * as v1 from './v1/index' -export {v1} -export default v1; +export { v1 } +export default v1 diff --git a/types/v1/driver.d.ts b/types/v1/driver.d.ts index 57237a909..3a18e493c 100644 --- a/types/v1/driver.d.ts +++ b/types/v1/driver.d.ts @@ -17,68 +17,78 @@ * limitations under the License. */ -import Session from "./session"; -import {Parameters} from "./statement-runner"; -import {Neo4jError} from "./error"; -import {ServerInfo} from "./result-summary"; +import Session from './session' +import { Parameters } from './statement-runner' +import { Neo4jError } from './error' +import { ServerInfo } from './result-summary' declare interface AuthToken { - scheme: string; - principal: string; - credentials: string; - realm?: string; - parameters?: Parameters; + scheme: string + principal: string + credentials: string + realm?: string + parameters?: Parameters } -declare type EncryptionLevel = "ENCRYPTION_ON" | "ENCRYPTION_OFF"; +declare type EncryptionLevel = 'ENCRYPTION_ON' | 'ENCRYPTION_OFF' declare type TrustStrategy = - "TRUST_ALL_CERTIFICATES" | - "TRUST_ON_FIRST_USE" | - "TRUST_SIGNED_CERTIFICATES" | - "TRUST_CUSTOM_CA_SIGNED_CERTIFICATES" | - "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES"; + | 'TRUST_ALL_CERTIFICATES' + | 'TRUST_ON_FIRST_USE' + | 'TRUST_SIGNED_CERTIFICATES' + | 'TRUST_CUSTOM_CA_SIGNED_CERTIFICATES' + | 'TRUST_SYSTEM_CA_SIGNED_CERTIFICATES' -declare type LoadBalancingStrategy = "least_connected" | "round_robin"; +declare type LoadBalancingStrategy = 'least_connected' | 'round_robin' -declare type LogLevel = "error" | "warn" | "info" | "debug"; +declare type LogLevel = 'error' | 'warn' | 'info' | 'debug' declare interface LoggingConfig { - level?: LogLevel; - logger: (level: LogLevel, message: string) => void; + level?: LogLevel + logger: (level: LogLevel, message: string) => void } declare interface Config { - encrypted?: boolean | EncryptionLevel; - trust?: TrustStrategy; - trustedCertificates?: string[]; - knownHosts?: string; + encrypted?: boolean | EncryptionLevel + trust?: TrustStrategy + trustedCertificates?: string[] + knownHosts?: string /** * @deprecated use {@link maxConnectionPoolSize} instead. */ - connectionPoolSize?: number; - maxConnectionPoolSize?: number; - maxTransactionRetryTime?: number; - loadBalancingStrategy?: LoadBalancingStrategy; - maxConnectionLifetime?: number; - connectionTimeout?: number; - disableLosslessIntegers?: boolean; - logging?: LoggingConfig; + connectionPoolSize?: number + maxConnectionPoolSize?: number + maxTransactionRetryTime?: number + loadBalancingStrategy?: LoadBalancingStrategy + maxConnectionLifetime?: number + connectionTimeout?: number + disableLosslessIntegers?: boolean + logging?: LoggingConfig } -declare type SessionMode = "READ" | "WRITE"; +declare type SessionMode = 'READ' | 'WRITE' -declare const READ: SessionMode; -declare const WRITE: SessionMode; +declare const READ: SessionMode +declare const WRITE: SessionMode declare interface Driver { - session(mode?: SessionMode, bookmark?: string): Session; + session(mode?: SessionMode, bookmark?: string): Session - close(): void; + close(): void - onCompleted?: (serverInfo: ServerInfo) => void; - onError?: (error: Neo4jError) => void; + onCompleted?: (serverInfo: ServerInfo) => void + onError?: (error: Neo4jError) => void } -export {Driver, READ, WRITE, AuthToken, Config, EncryptionLevel, TrustStrategy, LoadBalancingStrategy, SessionMode} +export { + Driver, + READ, + WRITE, + AuthToken, + Config, + EncryptionLevel, + TrustStrategy, + LoadBalancingStrategy, + SessionMode +} -export default Driver; +export default Driver diff --git a/types/v1/error.d.ts b/types/v1/error.d.ts index f77a11a64..a91454164 100644 --- a/types/v1/error.d.ts +++ b/types/v1/error.d.ts @@ -17,17 +17,17 @@ * limitations under the License. */ -declare const SERVICE_UNAVAILABLE: string; -declare const SESSION_EXPIRED: string; -declare const PROTOCOL_ERROR: string; +declare const SERVICE_UNAVAILABLE: string +declare const SESSION_EXPIRED: string +declare const PROTOCOL_ERROR: string -declare function newError(message: any, code?: string): Neo4jError; +declare function newError(message: any, code?: string): Neo4jError declare class Neo4jError extends Error { - code: string; - message: string; + code: string + message: string - constructor(message: any, code?: string); + constructor(message: any, code?: string) } export { diff --git a/types/v1/graph-types.d.ts b/types/v1/graph-types.d.ts index cb3bffadb..fe689a312 100644 --- a/types/v1/graph-types.d.ts +++ b/types/v1/graph-types.d.ts @@ -17,72 +17,60 @@ * limitations under the License. */ -import Integer from "./integer"; +import Integer from './integer' -declare type StandardDate = Date; -declare type NumberOrInteger = number | Integer; +declare type StandardDate = Date +declare type NumberOrInteger = number | Integer declare class Node { - identity: T; - labels: string[]; - properties: object; + identity: T + labels: string[] + properties: object - constructor(identity: T, - labels: string[], - properties: object) + constructor(identity: T, labels: string[], properties: object) - toString(): string; + toString(): string } declare class Relationship { - identity: T; - start: T; - end: T; - type: string; - properties: object; - - constructor(identity: T, - start: T, - end: T, - type: string, - properties: object); - - toString(): string; + identity: T + start: T + end: T + type: string + properties: object + + constructor(identity: T, start: T, end: T, type: string, properties: object) + + toString(): string } declare class UnboundRelationship { - identity: T; - type: string; - properties: object; + identity: T + type: string + properties: object - constructor(identity: T, - type: string, - properties: object); + constructor(identity: T, type: string, properties: object) - bind(start: T, end: T): Relationship; + bind(start: T, end: T): Relationship - toString(): string; + toString(): string } declare class PathSegment { - start: Node; - relationship: Relationship; - end: Node; + start: Node + relationship: Relationship + end: Node - constructor(start: Node, - rel: Relationship, - end: Node); + constructor(start: Node, rel: Relationship, end: Node) } declare class Path { - start: Node; - end: Node; - segments: PathSegment[]; - length: number; - - constructor(start: Node, - end: Node, - segments: PathSegment[]); + start: Node + end: Node + segments: PathSegment[] + length: number + + constructor(start: Node, end: Node, segments: PathSegment[]) } export { diff --git a/types/v1/index.d.ts b/types/v1/index.d.ts index cd74e1d77..5062de5ab 100644 --- a/types/v1/index.d.ts +++ b/types/v1/index.d.ts @@ -17,84 +17,126 @@ * limitations under the License. */ -import Integer, {inSafeRange, int, isInt, toNumber, toString} from "./integer"; -import {Node, Path, PathSegment, Relationship, UnboundRelationship} from "./graph-types"; -import {isPoint, Point} from "./spatial-types"; -import {Date, DateTime, Duration, isDate, isDateTime, isDuration, isLocalDateTime, isLocalTime, isTime, LocalDateTime, LocalTime, Time} from "./temporal-types"; -import {Neo4jError, PROTOCOL_ERROR, SERVICE_UNAVAILABLE, SESSION_EXPIRED} from "./error"; -import Result, {Observer, StatementResult} from "./result"; -import ResultSummary, {Notification, NotificationPosition, Plan, ProfiledPlan, ServerInfo, StatementStatistic} from "./result-summary"; -import Record from "./record"; -import Session from "./session"; -import {AuthToken, Config, Driver, EncryptionLevel, READ, SessionMode, TrustStrategy, WRITE} from "./driver"; -import Transaction from "./transaction"; -import {Parameters} from "./statement-runner"; +import Integer, { inSafeRange, int, isInt, toNumber, toString } from './integer' +import { + Node, + Path, + PathSegment, + Relationship, + UnboundRelationship +} from './graph-types' +import { isPoint, Point } from './spatial-types' +import { + Date, + DateTime, + Duration, + isDate, + isDateTime, + isDuration, + isLocalDateTime, + isLocalTime, + isTime, + LocalDateTime, + LocalTime, + Time +} from './temporal-types' +import { + Neo4jError, + PROTOCOL_ERROR, + SERVICE_UNAVAILABLE, + SESSION_EXPIRED +} from './error' +import Result, { Observer, StatementResult } from './result' +import ResultSummary, { + Notification, + NotificationPosition, + Plan, + ProfiledPlan, + ServerInfo, + StatementStatistic +} from './result-summary' +import Record from './record' +import Session from './session' +import { + AuthToken, + Config, + Driver, + EncryptionLevel, + READ, + SessionMode, + TrustStrategy, + WRITE +} from './driver' +import Transaction from './transaction' +import { Parameters } from './statement-runner' declare const auth: { - basic: (username: string, - password: string, - realm?: string) => AuthToken, + basic: (username: string, password: string, realm?: string) => AuthToken - kerberos: (base64EncodedTicket: string) => AuthToken, + kerberos: (base64EncodedTicket: string) => AuthToken - custom: (principal: string, - credentials: string, - realm: string, - scheme: string, - parameters?: Parameters) => AuthToken, -}; + custom: ( + principal: string, + credentials: string, + realm: string, + scheme: string, + parameters?: Parameters + ) => AuthToken +} -declare function driver(url: string, - authToken?: AuthToken, - config?: Config): Driver; +declare function driver( + url: string, + authToken?: AuthToken, + config?: Config +): Driver declare const types: { - Node: Node; - Relationship: Relationship; - UnboundRelationship: UnboundRelationship; - PathSegment: PathSegment; - Path: Path; - Result: Result; - ResultSummary: ResultSummary; - Record: Record; - Point: typeof Point; - Duration: typeof Duration; - LocalTime: typeof LocalTime; - Time: typeof Time; - Date: typeof Date; - LocalDateTime: typeof LocalDateTime; - DateTime: typeof DateTime; -}; + Node: Node + Relationship: Relationship + UnboundRelationship: UnboundRelationship + PathSegment: PathSegment + Path: Path + Result: Result + ResultSummary: ResultSummary + Record: Record + Point: typeof Point + Duration: typeof Duration + LocalTime: typeof LocalTime + Time: typeof Time + Date: typeof Date + LocalDateTime: typeof LocalDateTime + DateTime: typeof DateTime +} declare const session: { - READ: typeof READ; - WRITE: typeof WRITE; -}; + READ: typeof READ + WRITE: typeof WRITE +} declare const error: { - SERVICE_UNAVAILABLE: typeof SERVICE_UNAVAILABLE; - SESSION_EXPIRED: typeof SESSION_EXPIRED; - PROTOCOL_ERROR: typeof PROTOCOL_ERROR; -}; + SERVICE_UNAVAILABLE: typeof SERVICE_UNAVAILABLE + SESSION_EXPIRED: typeof SESSION_EXPIRED + PROTOCOL_ERROR: typeof PROTOCOL_ERROR +} declare const integer: { - toNumber: typeof toNumber; - toString: typeof toString; - inSafeRange: typeof inSafeRange; -}; + toNumber: typeof toNumber + toString: typeof toString + inSafeRange: typeof inSafeRange +} declare const spatial: { - isPoint: typeof isPoint; -}; + isPoint: typeof isPoint +} declare const temporal: { - isDuration: typeof isDuration; - isLocalTime: typeof isLocalTime; - isTime: typeof isTime; - isDate: typeof isDate; - isLocalDateTime: typeof isLocalDateTime; - isDateTime: typeof isDateTime; -}; + isDuration: typeof isDuration + isLocalTime: typeof isLocalTime + isTime: typeof isTime + isDate: typeof isDate + isLocalDateTime: typeof isLocalDateTime + isDateTime: typeof isDateTime +} /* Both default and non-default exports declare all visible types so that they can be used in client code like this: @@ -106,57 +148,57 @@ declare const temporal: { */ declare const forExport: { - driver: typeof driver; - int: typeof int; - isInt: typeof isInt; - integer: typeof integer; - auth: typeof auth; - types: typeof types; - session: typeof session; - error: typeof error; - spatial: typeof spatial; - temporal: typeof temporal; - Driver: Driver; - AuthToken: AuthToken; - Config: Config; - EncryptionLevel: EncryptionLevel; - TrustStrategy: TrustStrategy; - SessionMode: SessionMode; - Neo4jError: Neo4jError; - Node: Node; - Relationship: Relationship; - UnboundRelationship: UnboundRelationship; - PathSegment: PathSegment; - Path: Path; - Integer: Integer; - Record: Record; - Result: Result; - StatementResult: StatementResult; - Observer: Observer; - ResultSummary: ResultSummary; - Plan: Plan, - ProfiledPlan: ProfiledPlan, - StatementStatistic: StatementStatistic, - Notification: Notification, - ServerInfo: ServerInfo, - NotificationPosition: NotificationPosition, - Session: Session; - Transaction: Transaction; - Point: Point; - isPoint: typeof isPoint; - Duration: Duration; - LocalTime: LocalTime; - Time: Time; - Date: Date; - LocalDateTime: LocalDateTime; - DateTime: DateTime; - isDuration: typeof isDuration; - isLocalTime: typeof isLocalTime; - isTime: typeof isTime; - isDate: typeof isDate; - isLocalDateTime: typeof isLocalDateTime; - isDateTime: typeof isDateTime; -}; + driver: typeof driver + int: typeof int + isInt: typeof isInt + integer: typeof integer + auth: typeof auth + types: typeof types + session: typeof session + error: typeof error + spatial: typeof spatial + temporal: typeof temporal + Driver: Driver + AuthToken: AuthToken + Config: Config + EncryptionLevel: EncryptionLevel + TrustStrategy: TrustStrategy + SessionMode: SessionMode + Neo4jError: Neo4jError + Node: Node + Relationship: Relationship + UnboundRelationship: UnboundRelationship + PathSegment: PathSegment + Path: Path + Integer: Integer + Record: Record + Result: Result + StatementResult: StatementResult + Observer: Observer + ResultSummary: ResultSummary + Plan: Plan + ProfiledPlan: ProfiledPlan + StatementStatistic: StatementStatistic + Notification: Notification + ServerInfo: ServerInfo + NotificationPosition: NotificationPosition + Session: Session + Transaction: Transaction + Point: Point + isPoint: typeof isPoint + Duration: Duration + LocalTime: LocalTime + Time: Time + Date: Date + LocalDateTime: LocalDateTime + DateTime: DateTime + isDuration: typeof isDuration + isLocalTime: typeof isLocalTime + isTime: typeof isTime + isDate: typeof isDate + isLocalDateTime: typeof isLocalDateTime + isDateTime: typeof isDateTime +} export { driver, @@ -211,4 +253,4 @@ export { isDateTime } -export default forExport; +export default forExport diff --git a/types/v1/integer.d.ts b/types/v1/integer.d.ts index 1b631e143..b2763beb4 100644 --- a/types/v1/integer.d.ts +++ b/types/v1/integer.d.ts @@ -18,118 +18,130 @@ */ declare class Integer { - low: number; - high: number; + low: number + high: number constructor(low?: number, high?: number) - inSafeRange(): boolean; + inSafeRange(): boolean - toInt(): number; + toInt(): number - toNumber(): number; + toNumber(): number - toString(radix: number): string; + toString(radix: number): string - getHighBits(): number; + getHighBits(): number - getLowBits(): number; + getLowBits(): number - getNumBitsAbs(): number; + getNumBitsAbs(): number - isZero(): boolean; + isZero(): boolean - isNegative(): boolean; + isNegative(): boolean - isPositive(): boolean; + isPositive(): boolean - isOdd(): boolean; + isOdd(): boolean - isEven(): boolean; + isEven(): boolean - equals(other: Integer | number | string): boolean; + equals(other: Integer | number | string): boolean - notEquals(other: Integer | number | string): boolean; + notEquals(other: Integer | number | string): boolean - lessThan(other: Integer | number | string): boolean; + lessThan(other: Integer | number | string): boolean - lessThanOrEqual(other: Integer | number | string): boolean; + lessThanOrEqual(other: Integer | number | string): boolean - greaterThan(other: Integer | number | string): boolean; + greaterThan(other: Integer | number | string): boolean - greaterThanOrEqual(other: Integer | number | string): boolean; + greaterThanOrEqual(other: Integer | number | string): boolean - compare(other: Integer | number | string): number; + compare(other: Integer | number | string): number - negate(): Integer; + negate(): Integer - add(addend: Integer | number | string): Integer; + add(addend: Integer | number | string): Integer - subtract(subtrahend: Integer | number | string): Integer; + subtract(subtrahend: Integer | number | string): Integer - multiply(multiplier: Integer | number | string): Integer; + multiply(multiplier: Integer | number | string): Integer - div(divisor: Integer | number | string): Integer; + div(divisor: Integer | number | string): Integer - modulo(divisor: Integer | number | string): Integer; + modulo(divisor: Integer | number | string): Integer - not(): Integer; + not(): Integer - and(other: Integer | number | string): Integer; + and(other: Integer | number | string): Integer - or(other: Integer | number | string): Integer; + or(other: Integer | number | string): Integer - xor(other: Integer | number | string): Integer; + xor(other: Integer | number | string): Integer - shiftLeft(numBits: Integer | number): Integer; + shiftLeft(numBits: Integer | number): Integer - shiftRight(numBits: Integer | number): Integer; + shiftRight(numBits: Integer | number): Integer - static __isInteger__: true; + static __isInteger__: true - static isInteger(obj: object): boolean; + static isInteger(obj: object): boolean - static fromInt(value: number): Integer; + static fromInt(value: number): Integer - static fromNumber(value: number): Integer; + static fromNumber(value: number): Integer - static fromBits(lowBits: number, highBits: number): Integer; + static fromBits(lowBits: number, highBits: number): Integer - static fromString(str: string, radix?: number): Integer; + static fromString(str: string, radix?: number): Integer - static fromValue(value: Integer | number | string | { low: number, high: number }): Integer; + static fromValue( + value: Integer | number | string | { low: number; high: number } + ): Integer - static toNumber(value: Integer | number | string | { low: number, high: number }): number; + static toNumber( + value: Integer | number | string | { low: number; high: number } + ): number - static toString(value: Integer | number | string | { low: number, high: number }, radix?: number): string; + static toString( + value: Integer | number | string | { low: number; high: number }, + radix?: number + ): string - static inSafeRange(value: Integer | number | string | { low: number, high: number }): boolean; + static inSafeRange( + value: Integer | number | string | { low: number; high: number } + ): boolean - static ZERO: Integer; - static ONE: Integer; - static NEG_ONE: Integer; - static MAX_VALUE: Integer; - static MIN_VALUE: Integer; - static MIN_SAFE_VALUE: Integer; - static MAX_SAFE_VALUE: Integer; + static ZERO: Integer + static ONE: Integer + static NEG_ONE: Integer + static MAX_VALUE: Integer + static MIN_VALUE: Integer + static MIN_SAFE_VALUE: Integer + static MAX_SAFE_VALUE: Integer } -declare function int(value: Integer | number | string | { low: number, high: number }): Integer; +declare function int( + value: Integer | number | string | { low: number; high: number } +): Integer -declare function isInt(obj: object): boolean; +declare function isInt(obj: object): boolean -declare function inSafeRange(val: Integer | number | string | { low: number, high: number }): boolean; +declare function inSafeRange( + val: Integer | number | string | { low: number; high: number } +): boolean -declare function toNumber(val: Integer | number | string | { low: number, high: number }): number; +declare function toNumber( + val: Integer | number | string | { low: number; high: number } +): number -declare function toString(val: Integer | number | string | { low: number, high: number }, radix?: number): string; +declare function toString( + val: Integer | number | string | { low: number; high: number }, + radix?: number +): string -export { - int, - isInt, - inSafeRange, - toNumber, - toString -} +export { int, isInt, inSafeRange, toNumber, toString } -export default Integer; +export default Integer diff --git a/types/v1/record.d.ts b/types/v1/record.d.ts index d8cb3d25f..2622a9419 100644 --- a/types/v1/record.d.ts +++ b/types/v1/record.d.ts @@ -17,21 +17,25 @@ * limitations under the License. */ -declare type Visitor = (value: any, key: string, record: Record) => void; +declare type Visitor = (value: any, key: string, record: Record) => void declare class Record { - keys: string[]; - length: number; + keys: string[] + length: number - constructor(keys: string[], fields: any[], fieldLookup?: { [index: string]: string }); + constructor( + keys: string[], + fields: any[], + fieldLookup?: { [index: string]: string } + ) - forEach(visitor: Visitor): void; + forEach(visitor: Visitor): void - toObject(): object; + toObject(): object - get(key: string | number): any; + get(key: string | number): any - has(key: string | number): boolean; + has(key: string | number): boolean } -export default Record; +export default Record diff --git a/types/v1/result-summary.d.ts b/types/v1/result-summary.d.ts index 1704a6e07..fc14a0bcc 100644 --- a/types/v1/result-summary.d.ts +++ b/types/v1/result-summary.d.ts @@ -17,89 +17,101 @@ * limitations under the License. */ -import Integer from "./integer"; -import {NumberOrInteger} from "./graph-types"; +import Integer from './integer' +import { NumberOrInteger } from './graph-types' declare interface ResultSummary { - statement: { text: string, parameters: { [key: string]: any } }; - statementType: string; - counters: StatementStatistic; - plan: Plan; - profile: ProfiledPlan; - notifications: Notification[]; - server: ServerInfo; - resultConsumedAfter: T; - resultAvailableAfter: T; - - hasPlan(): boolean; - - hasProfile(): boolean; + statement: { text: string; parameters: { [key: string]: any } } + statementType: string + counters: StatementStatistic + plan: Plan + profile: ProfiledPlan + notifications: Notification[] + server: ServerInfo + resultConsumedAfter: T + resultAvailableAfter: T + + hasPlan(): boolean + + hasProfile(): boolean } declare interface Plan { - operatorType: string; - identifiers: string[]; - arguments: { [key: string]: string }; - children: Plan[]; + operatorType: string + identifiers: string[] + arguments: { [key: string]: string } + children: Plan[] } declare interface ProfiledPlan { - operatorType: string; - identifiers: string[]; - arguments: { [key: string]: string }; - dbHits: number; - rows: number; - children: ProfiledPlan[]; + operatorType: string + identifiers: string[] + arguments: { [key: string]: string } + dbHits: number + rows: number + children: ProfiledPlan[] } declare interface StatementStatistic { - containsUpdates(): boolean; + containsUpdates(): boolean - nodesCreated(): number; + nodesCreated(): number - nodesDeleted(): number; + nodesDeleted(): number - relationshipsCreated(): number; + relationshipsCreated(): number - relationshipsDeleted(): number; + relationshipsDeleted(): number - propertiesSet(): number; + propertiesSet(): number - labelsAdded(): number; + labelsAdded(): number - labelsRemoved(): number; + labelsRemoved(): number - indexesAdded(): number; + indexesAdded(): number - indexesRemoved(): number; + indexesRemoved(): number - constraintsAdded(): number; + constraintsAdded(): number - constraintsRemoved(): number; + constraintsRemoved(): number } -declare type NotificationPosition = { offset: number; line: number; column: number; } +declare type NotificationPosition = { + offset: number + line: number + column: number +} declare interface Notification { - code: string; - title: string; - description: string; - severity: string; - position: NotificationPosition | {}; + code: string + title: string + description: string + severity: string + position: NotificationPosition | {} } declare interface ServerInfo { - address: string; - version: string; + address: string + version: string } declare const statementType: { - READ_ONLY: "r"; - READ_WRITE: "rw"; - WRITE_ONLY: "w"; - SCHEMA_WRITE: "s"; -}; + READ_ONLY: 'r' + READ_WRITE: 'rw' + WRITE_ONLY: 'w' + SCHEMA_WRITE: 's' +} -export {statementType, Plan, ProfiledPlan, StatementStatistic, Notification, ServerInfo, NotificationPosition} +export { + statementType, + Plan, + ProfiledPlan, + StatementStatistic, + Notification, + ServerInfo, + NotificationPosition +} -export default ResultSummary; +export default ResultSummary diff --git a/types/v1/result.d.ts b/types/v1/result.d.ts index 1788ccfcf..8a2d2bc9a 100644 --- a/types/v1/result.d.ts +++ b/types/v1/result.d.ts @@ -17,23 +17,23 @@ * limitations under the License. */ -import ResultSummary from "./result-summary"; -import Record from "./record"; +import ResultSummary from './result-summary' +import Record from './record' declare type StatementResult = { - records: Record[]; - summary: ResultSummary; + records: Record[] + summary: ResultSummary } declare type Observer = { - onNext?(record: Record): void; - onCompleted?(summary: ResultSummary): void; - onError?(error: Error): void; + onNext?(record: Record): void + onCompleted?(summary: ResultSummary): void + onError?(error: Error): void } declare interface Result extends Promise { - subscribe(observer: Observer): void; + subscribe(observer: Observer): void } -export {StatementResult, Observer}; -export default Result; +export { StatementResult, Observer } +export default Result diff --git a/types/v1/session.d.ts b/types/v1/session.d.ts index be01b11b9..457329869 100644 --- a/types/v1/session.d.ts +++ b/types/v1/session.d.ts @@ -17,34 +17,42 @@ * limitations under the License. */ -import Transaction from "./transaction"; -import StatementRunner, {Parameters} from "./statement-runner"; -import Result from "./result"; -import {NumberOrInteger} from "./graph-types"; +import Transaction from './transaction' +import StatementRunner, { Parameters } from './statement-runner' +import Result from './result' +import { NumberOrInteger } from './graph-types' -declare type TransactionWork = (tx: Transaction) => T | Promise; +declare type TransactionWork = (tx: Transaction) => T | Promise declare interface TransactionConfig { - timeout?: NumberOrInteger; - metadata?: object; + timeout?: NumberOrInteger + metadata?: object } declare interface Session extends StatementRunner { - run(statement: string, parameters?: Parameters, config?: TransactionConfig): Result; + run( + statement: string, + parameters?: Parameters, + config?: TransactionConfig + ): Result - beginTransaction(config?: TransactionConfig): Transaction; + beginTransaction(config?: TransactionConfig): Transaction - lastBookmark(): string | null; + lastBookmark(): string | null - readTransaction(work: TransactionWork, config?: TransactionConfig): Promise; + readTransaction( + work: TransactionWork, + config?: TransactionConfig + ): Promise - writeTransaction(work: TransactionWork, config?: TransactionConfig): Promise; + writeTransaction( + work: TransactionWork, + config?: TransactionConfig + ): Promise - close(callback?: () => void): void; + close(callback?: () => void): void } -export { - TransactionConfig -} +export { TransactionConfig } -export default Session; +export default Session diff --git a/types/v1/spatial-types.d.ts b/types/v1/spatial-types.d.ts index c7b060e9e..50c0d83f1 100644 --- a/types/v1/spatial-types.d.ts +++ b/types/v1/spatial-types.d.ts @@ -17,22 +17,18 @@ * limitations under the License. */ -import {NumberOrInteger} from './graph-types'; -import Integer from "./integer"; +import { NumberOrInteger } from './graph-types' +import Integer from './integer' declare class Point { - - readonly srid: T; - readonly x: number; - readonly y: number; - readonly z?: number; + readonly srid: T + readonly x: number + readonly y: number + readonly z?: number constructor(srid: T, x: number, y: number, z?: number) } -declare function isPoint(obj: object): boolean; +declare function isPoint(obj: object): boolean -export { - Point, - isPoint -} +export { Point, isPoint } diff --git a/types/v1/statement-runner.d.ts b/types/v1/statement-runner.d.ts index 0cb2e056e..026fe2258 100644 --- a/types/v1/statement-runner.d.ts +++ b/types/v1/statement-runner.d.ts @@ -17,14 +17,14 @@ * limitations under the License. */ -import Result from "./result"; +import Result from './result' -declare type Parameters = { [key: string]: any }; +declare type Parameters = { [key: string]: any } declare interface StatementRunner { - run(statement: string, parameters?: Parameters): Result; + run(statement: string, parameters?: Parameters): Result } -export {Parameters} +export { Parameters } -export default StatementRunner; +export default StatementRunner diff --git a/types/v1/temporal-types.d.ts b/types/v1/temporal-types.d.ts index 720d01ae0..10a7fcbe5 100644 --- a/types/v1/temporal-types.d.ts +++ b/types/v1/temporal-types.d.ts @@ -17,98 +17,128 @@ * limitations under the License. */ -import {NumberOrInteger, StandardDate} from './graph-types'; -import Integer from "./integer"; +import { NumberOrInteger, StandardDate } from './graph-types' +import Integer from './integer' declare class Duration { - - readonly months: T; - readonly days: T; - readonly seconds: T; - readonly nanoseconds: T; + readonly months: T + readonly days: T + readonly seconds: T + readonly nanoseconds: T constructor(months: T, days: T, seconds: T, nanoseconds: T) } declare class LocalTime { + readonly hour: T + readonly minute: T + readonly second: T + readonly nanosecond: T - readonly hour: T; - readonly minute: T; - readonly second: T; - readonly nanosecond: T; - - constructor(hour: T, minute: T, second: T, nanosecond: T); + constructor(hour: T, minute: T, second: T, nanosecond: T) - static fromStandardDate(standardDate: StandardDate, nanosecond?: number): LocalTime; + static fromStandardDate( + standardDate: StandardDate, + nanosecond?: number + ): LocalTime } declare class Time { - - readonly hour: T; - readonly minute: T; - readonly second: T; - readonly nanosecond: T; - readonly timeZoneOffsetSeconds: T; - - constructor(hour: T, minute: T, second: T, nanosecond: T, timeZoneOffsetSeconds: T); - - static fromStandardDate(standardDate: StandardDate, nanosecond?: number): Time; + readonly hour: T + readonly minute: T + readonly second: T + readonly nanosecond: T + readonly timeZoneOffsetSeconds: T + + constructor( + hour: T, + minute: T, + second: T, + nanosecond: T, + timeZoneOffsetSeconds: T + ) + + static fromStandardDate( + standardDate: StandardDate, + nanosecond?: number + ): Time } declare class Date { + readonly year: T + readonly month: T + readonly day: T - readonly year: T; - readonly month: T; - readonly day: T; - - constructor(year: T, month: T, day: T); + constructor(year: T, month: T, day: T) - static fromStandardDate(standardDate: StandardDate): Date; + static fromStandardDate(standardDate: StandardDate): Date } declare class LocalDateTime { - - readonly year: T; - readonly month: T; - readonly day: T; - readonly hour: T; - readonly minute: T; - readonly second: T; - readonly nanosecond: T; - - constructor(year: T, month: T, day: T, hour: T, minute: T, second: T, nanosecond: T); - - static fromStandardDate(standardDate: StandardDate, nanosecond?: number): LocalDateTime; + readonly year: T + readonly month: T + readonly day: T + readonly hour: T + readonly minute: T + readonly second: T + readonly nanosecond: T + + constructor( + year: T, + month: T, + day: T, + hour: T, + minute: T, + second: T, + nanosecond: T + ) + + static fromStandardDate( + standardDate: StandardDate, + nanosecond?: number + ): LocalDateTime } declare class DateTime { - - readonly year: T; - readonly month: T; - readonly day: T; - readonly hour: T; - readonly minute: T; - readonly second: T; - readonly nanosecond: T; - readonly timeZoneOffsetSeconds?: T; - readonly timeZoneId?: string; - - constructor(year: T, month: T, day: T, hour: T, minute: T, second: T, nanosecond: T, timeZoneOffsetSeconds?: T, timeZoneId?: string); - - static fromStandardDate(standardDate: StandardDate, nanosecond?: number): DateTime; + readonly year: T + readonly month: T + readonly day: T + readonly hour: T + readonly minute: T + readonly second: T + readonly nanosecond: T + readonly timeZoneOffsetSeconds?: T + readonly timeZoneId?: string + + constructor( + year: T, + month: T, + day: T, + hour: T, + minute: T, + second: T, + nanosecond: T, + timeZoneOffsetSeconds?: T, + timeZoneId?: string + ) + + static fromStandardDate( + standardDate: StandardDate, + nanosecond?: number + ): DateTime } -declare function isDuration(obj: object): boolean; +declare function isDuration(obj: object): boolean -declare function isLocalTime(obj: object): boolean; +declare function isLocalTime(obj: object): boolean -declare function isTime(obj: object): boolean; +declare function isTime(obj: object): boolean -declare function isDate(obj: object): boolean; +declare function isDate(obj: object): boolean -declare function isLocalDateTime(obj: object): boolean; +declare function isLocalDateTime(obj: object): boolean -declare function isDateTime(obj: object): boolean; +declare function isDateTime(obj: object): boolean export { Duration, diff --git a/types/v1/transaction.d.ts b/types/v1/transaction.d.ts index b0f43edc9..576ad20a5 100644 --- a/types/v1/transaction.d.ts +++ b/types/v1/transaction.d.ts @@ -17,15 +17,15 @@ * limitations under the License. */ -import Result from "./result"; -import StatementRunner from "./statement-runner"; +import Result from './result' +import StatementRunner from './statement-runner' declare interface Transaction extends StatementRunner { - commit(): Result; + commit(): Result - rollback(): Result; + rollback(): Result - isOpen(): boolean; + isOpen(): boolean } -export default Transaction; +export default Transaction From 187de87aa8095122d0551119e1369cfe02f61647 Mon Sep 17 00:00:00 2001 From: Ali Ince Date: Wed, 15 May 2019 15:50:36 +0100 Subject: [PATCH 4/5] Inspect all transaction records for assertion --- test/v1/bolt-v3.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/v1/bolt-v3.test.js b/test/v1/bolt-v3.test.js index 96c4074a2..7d146d82c 100644 --- a/test/v1/bolt-v3.test.js +++ b/test/v1/bolt-v3.test.js @@ -74,8 +74,8 @@ describe('Bolt V3 API', () => { session .run('CALL dbms.listTransactions()', {}, { metadata: metadata }) .then(result => { - const receivedMetadata = result.records[0].get('metaData') - expect(receivedMetadata).toEqual(metadata) + const receivedMetadatas = result.records.map(r => r.get('metaData')) + expect(receivedMetadatas).toContain(metadata) done() }) .catch(error => { @@ -186,8 +186,8 @@ describe('Bolt V3 API', () => { // call listTransactions procedure that should list itself with the specified metadata tx.run('CALL dbms.listTransactions()') .then(result => { - const receivedMetadata = result.records[0].get('metaData') - expect(receivedMetadata).toEqual(metadata) + const receivedMetadatas = result.records.map(r => r.get('metaData')) + expect(receivedMetadatas).toContain(metadata) tx.commit() .then(() => done()) .catch(error => done.fail(error)) @@ -479,8 +479,8 @@ describe('Bolt V3 API', () => { txFunctionWithMetadata(tx => tx.run('CALL dbms.listTransactions()')) .then(result => { - const receivedMetadata = result.records[0].get('metaData') - expect(receivedMetadata).toEqual(metadata) + const receivedMetadatas = result.records.map(r => r.get('metaData')) + expect(receivedMetadatas).toContain(metadata) done() }) .catch(error => { From 934237013169b98b9f6d1e537afe2aab87c2ef60 Mon Sep 17 00:00:00 2001 From: Ali Ince Date: Tue, 21 May 2019 10:50:50 +0100 Subject: [PATCH 5/5] Remove finally in promise chaining --- test/internal/node/direct.driver.boltkit.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/internal/node/direct.driver.boltkit.test.js b/test/internal/node/direct.driver.boltkit.test.js index c1ea11d3a..8afb2a85d 100644 --- a/test/internal/node/direct.driver.boltkit.test.js +++ b/test/internal/node/direct.driver.boltkit.test.js @@ -469,7 +469,7 @@ describe('direct driver with stub server', () => { } ) ) - .finally(() => + .then(() => session.close(() => { driver.close()