oojs/router: main (log #1038933)

sourcepatches

This run took 33 seconds.

$ date
--- stdout ---
Sat May 27 02:37:50 UTC 2023

--- end ---
$ git clone file:///srv/git/oojs-router.git repo --depth=1 -b master
--- stderr ---
Cloning into 'repo'...
--- stdout ---

--- end ---
$ git config user.name libraryupgrader
--- stdout ---

--- end ---
$ git config user.email tools.libraryupgrader@tools.wmflabs.org
--- stdout ---

--- end ---
$ git submodule update --init
--- stdout ---

--- end ---
$ grr init
--- stdout ---
Installed commit-msg hook.

--- end ---
$ git show-ref refs/heads/master
--- stdout ---
dedadd4969c81b7fac2a08b299b126798463692e refs/heads/master

--- end ---
$ /usr/bin/npm audit --json --legacy-peer-deps
--- stdout ---
{
  "auditReportVersion": 2,
  "vulnerabilities": {
    "engine.io": {
      "name": "engine.io",
      "severity": "moderate",
      "isDirect": false,
      "via": [
        {
          "source": 1091957,
          "name": "engine.io",
          "dependency": "engine.io",
          "title": "engine.io Uncaught Exception vulnerability",
          "url": "https://github.com/advisories/GHSA-q9mw-68c2-j6m5",
          "severity": "moderate",
          "cwe": [
            "CWE-248"
          ],
          "cvss": {
            "score": 6.5,
            "vectorString": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H"
          },
          "range": ">=5.1.0 <6.4.2"
        }
      ],
      "effects": [
        "socket.io"
      ],
      "range": "5.1.0 - 6.4.1",
      "nodes": [
        "node_modules/engine.io"
      ],
      "fixAvailable": true
    },
    "socket.io": {
      "name": "socket.io",
      "severity": "moderate",
      "isDirect": false,
      "via": [
        "engine.io"
      ],
      "effects": [],
      "range": "4.1.0 - 4.6.0-alpha1",
      "nodes": [
        "node_modules/socket.io"
      ],
      "fixAvailable": true
    },
    "socket.io-parser": {
      "name": "socket.io-parser",
      "severity": "high",
      "isDirect": false,
      "via": [
        {
          "source": 1092102,
          "name": "socket.io-parser",
          "dependency": "socket.io-parser",
          "title": "Insufficient validation when decoding a Socket.IO packet",
          "url": "https://github.com/advisories/GHSA-cqmj-92xf-r6r9",
          "severity": "high",
          "cwe": [],
          "cvss": {
            "score": 0,
            "vectorString": null
          },
          "range": ">=4.0.4 <4.2.3"
        }
      ],
      "effects": [],
      "range": "4.0.4 - 4.2.2",
      "nodes": [
        "node_modules/socket.io-parser"
      ],
      "fixAvailable": true
    }
  },
  "metadata": {
    "vulnerabilities": {
      "info": 0,
      "low": 0,
      "moderate": 2,
      "high": 1,
      "critical": 0,
      "total": 3
    },
    "dependencies": {
      "prod": 3,
      "dev": 480,
      "optional": 1,
      "peer": 0,
      "peerOptional": 0,
      "total": 482
    }
  }
}

--- end ---
Upgrading n:eslint-config-wikimedia from 0.24.0 -> 0.25.0
Upgrading n:grunt-eslint from 24.0.0 -> 24.0.1
$ /usr/bin/npm install
--- stdout ---

> oojs-router@0.4.0 prepare
> grunt build

Running "clean:dist" (clean) task
>> 0 paths cleaned.

Running "concat:router" (concat) task

Running "uglify:js" (uglify) task
>> 1 sourcemap created.
>> 1 file created 5.63 kB → 1.86 kB

Done.

added 482 packages, and audited 483 packages in 5s

59 packages are looking for funding
  run `npm fund` for details

3 vulnerabilities (2 moderate, 1 high)

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
$ /usr/bin/npm install grunt-eslint@24.0.1 --save-exact
--- stdout ---

up to date, audited 483 packages in 966ms

59 packages are looking for funding
  run `npm fund` for details

3 vulnerabilities (2 moderate, 1 high)

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
$ ./node_modules/.bin/eslint . --fix
--- stdout ---

/src/repo/src/index.js
   87:3  error    'hash' is never reassigned. Use 'const' instead       prefer-const
  116:4  warning  Found non-literal argument to RegExp Constructor      security/detect-non-literal-regexp
  172:6  error    'timeoutID' is never reassigned. Use 'const' instead  prefer-const
  173:3  error    'router' is never reassigned. Use 'const' instead     prefer-const
  174:3  error    'deferred' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/oojs-router.test.js
   3:3  error  'docTitle' is never reassigned. Use 'const' instead  prefer-const
  53:4  error  'spy' is never reassigned. Use 'const' instead       prefer-const
  54:4  error  'done' is never reassigned. Use 'const' instead      prefer-const

✖ 8 problems (7 errors, 1 warning)


--- end ---
$ ./node_modules/.bin/eslint . -f json
--- stdout ---
[{"filePath":"/src/repo/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/Gruntfile.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/jsduck.categories.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/jsduck.external.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/jsduck.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/package-lock.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/package.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"no-process-exit","replacedBy":[]}]},{"filePath":"/src/repo/src/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]}]},{"filePath":"/src/repo/src/index.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'hash' is never reassigned. Use 'const' instead.","line":87,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":87,"endColumn":7},{"ruleId":"security/detect-non-literal-regexp","severity":1,"message":"Found non-literal argument to RegExp Constructor","line":116,"column":4,"nodeType":"NewExpression","endLine":116,"endColumn":75},{"ruleId":"prefer-const","severity":2,"message":"'timeoutID' is never reassigned. Use 'const' instead.","line":172,"column":6,"nodeType":"Identifier","messageId":"useConst","endLine":172,"endColumn":15},{"ruleId":"prefer-const","severity":2,"message":"'router' is never reassigned. Use 'const' instead.","line":173,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":173,"endColumn":9},{"ruleId":"prefer-const","severity":2,"message":"'deferred' is never reassigned. Use 'const' instead.","line":174,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":174,"endColumn":11}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Provides navigation routing and location information\n *\n * @class OO.Router\n * @extends OO.Registry\n */\nOO.Router = function OoRouter() {\n\tconst router = this;\n\n\t// Parent constructor\n\tOO.Router.parent.call( this );\n\n\tthis.enabled = true;\n\tthis.oldHash = this.getPath();\n\n\twindow.addEventListener( 'popstate', function () {\n\t\trouter.emit( 'popstate' );\n\t} );\n\n\twindow.addEventListener( 'hashchange', function () {\n\t\trouter.emit( 'hashchange' );\n\t} );\n\n\tthis.on( 'hashchange', function () {\n\t\t// event.originalEvent.newURL is undefined on Android 2.x\n\t\tlet routeEvent;\n\n\t\tif ( router.enabled ) {\n\t\t\trouteEvent = $.Event( 'route', {\n\t\t\t\tpath: router.getPath()\n\t\t\t} );\n\t\t\trouter.emit( 'route', routeEvent );\n\n\t\t\tif ( !routeEvent.isDefaultPrevented() ) {\n\t\t\t\trouter.checkRoute();\n\t\t\t} else {\n\t\t\t\t// if route was prevented, ignore the next hash change and revert the\n\t\t\t\t// hash to its old value\n\t\t\t\trouter.enabled = false;\n\t\t\t\trouter.navigate( router.oldHash );\n\t\t\t}\n\t\t} else {\n\t\t\trouter.enabled = true;\n\t\t}\n\n\t\trouter.oldHash = router.getPath();\n\t} );\n};\n\n/* Inheritance */\n\nOO.inheritClass( OO.Router, OO.Registry );\n\n/* Events */\n\n/**\n * @event popstate\n */\n\n/**\n * @event hashchange\n */\n\n/**\n * @event route\n * @param {jQuery.Event} routeEvent\n */\n\n/* Static Methods */\n\n/**\n * Determine if current browser supports this router\n *\n * @return {boolean} The browser is supported\n */\nOO.Router.static.isSupported = function () {\n\treturn 'onhashchange' in window;\n};\n\n/* Methods */\n\n/**\n * Check the current route and run appropriate callback if it matches.\n */\nOO.Router.prototype.checkRoute = function () {\n\tlet id, entry, match,\n\t\thash = this.getPath();\n\n\tfor ( id in this.registry ) {\n\t\tentry = this.registry[ id ];\n\t\tmatch = hash.match( entry.path );\n\t\tif ( match ) {\n\t\t\tentry.callback.apply( this, match.slice( 1 ) );\n\t\t\treturn;\n\t\t}\n\t}\n};\n\n/**\n * Bind a specific callback to a hash-based route, e.g.\n *\n *     @example\n *     addRoute( 'alert', function () { alert( 'something' ); } );\n *     addRoute( /hi-(.*)/, function ( name ) { alert( 'Hi ' + name ) } );\n *\n * Note that after defining all available routes it is up to the caller\n * to check the existing route via the checkRoute method.\n *\n * @param {string|RegExp} path Path to match, string or regular expression\n * @param {Function} callback Callback to be run when hash changes to one\n * that matches.\n */\nOO.Router.prototype.addRoute = function ( path, callback ) {\n\tconst entry = {\n\t\tpath: typeof path === 'string' ?\n\t\t\tnew RegExp( '^' + path.replace( /[\\\\^$*+?.()|[\\]{}]/g, '\\\\$&' ) + '$' ) :\n\t\t\tpath,\n\t\tcallback: callback\n\t};\n\tthis.register( entry.path.toString(), entry );\n};\n\n/**\n * @deprecated Use #addRoute\n */\nOO.Router.prototype.route = OO.Router.prototype.addRoute;\n\n/**\n * Navigate to a specific route.\n *\n * @param {string} title of new page\n * @param {Object} options\n * @param {string} options.path e.g. '/path/' or '/path/#foo'\n * @param {boolean} options.useReplaceState Set replaceStateState to use pushState when you want to\n *   avoid long history queues.\n */\nOO.Router.prototype.navigateTo = function ( title, options ) {\n\tif ( options.useReplaceState ) {\n\t\thistory.replaceState( null, title, options.path );\n\t} else {\n\t\thistory.pushState( null, title, options.path );\n\t}\n};\n\n/**\n * Navigate to a specific ''hash fragment'' route.\n *\n * @param {string} path String with a route (hash without #).\n * @deprecated use navigateTo instead\n */\nOO.Router.prototype.navigate = function ( path ) {\n\t// Take advantage of `pushState` when available, to clear the hash and\n\t// not leave `#` in the history. An entry with `#` in the history has\n\t// the side-effect of resetting the scroll position when navigating the\n\t// history.\n\tif ( path === '' ) {\n\t\t// To clear the hash we need to cut the hash from the URL.\n\t\tpath = window.location.href.replace( /#.*$/, '' );\n\t\thistory.pushState( null, document.title, path );\n\t\tthis.checkRoute();\n\t} else {\n\t\twindow.location.hash = path;\n\t}\n};\n\n/**\n * Navigate to the previous route. This is a wrapper for window.history.back\n *\n * @return {jQuery.Promise} Promise which resolves when the back navigation is complete\n */\nOO.Router.prototype.back = function () {\n\tlet timeoutID,\n\t\trouter = this,\n\t\tdeferred = $.Deferred();\n\n\tthis.once( 'popstate', function () {\n\t\tclearTimeout( timeoutID );\n\t\tdeferred.resolve();\n\t} );\n\n\twindow.history.back();\n\n\t// If for some reason (old browser, bug in IE/windows 8.1, etc) popstate doesn't fire,\n\t// resolve manually. Since we don't know for sure which browsers besides IE10/11 have\n\t// this problem, it's better to fall back this way rather than singling out browsers\n\t// and resolving the deferred request for them individually.\n\t// See https://connect.microsoft.com/IE/feedback/details/793618/history-back-popstate-not-working-as-expected-in-webview-control\n\t// Give browser a few ms to update its history.\n\ttimeoutID = setTimeout( function () {\n\t\trouter.off( 'popstate' );\n\t\tdeferred.resolve();\n\t}, 50 );\n\n\treturn deferred.promise();\n};\n\n/**\n * Get current path (hash).\n *\n * @return {string} Current path.\n */\nOO.Router.prototype.getPath = function () {\n\treturn window.location.hash.slice( 1 );\n};\n\n/**\n * @deprecated Use static method\n */\nOO.Router.prototype.isSupported = OO.Router.static.isSupported;\n\nif ( typeof module !== 'undefined' && module.exports ) {\n\tmodule.exports = OO.Router;\n}\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]}]},{"filePath":"/src/repo/tests/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]}]},{"filePath":"/src/repo/tests/oojs-router.test.js","messages":[{"ruleId":"prefer-const","severity":2,"message":"'docTitle' is never reassigned. Use 'const' instead.","line":3,"column":3,"nodeType":"Identifier","messageId":"useConst","endLine":3,"endColumn":11},{"ruleId":"prefer-const","severity":2,"message":"'spy' is never reassigned. Use 'const' instead.","line":53,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":53,"endColumn":7},{"ruleId":"prefer-const","severity":2,"message":"'done' is never reassigned. Use 'const' instead.","line":54,"column":4,"nodeType":"Identifier","messageId":"useConst","endLine":54,"endColumn":8}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\tlet router,\n\t\tdocTitle = 'Hello world';\n\n\tQUnit.module( 'Router', {\n\t\tbeforeEach: function () {\n\t\t\trouter = new OO.Router();\n\t\t\tthis.sandbox = sinon.createSandbox();\n\t\t\tthis.sandbox.stub( router, 'getPath' ).callsFake( function () {\n\t\t\t\treturn router.testHash.slice( 1 );\n\t\t\t} );\n\t\t\tthis.sandbox.stub( router, 'navigate' ).callsFake( function ( path ) {\n\t\t\t\trouter.testHash = path;\n\t\t\t} );\n\t\t},\n\t\tafterEach: function () {\n\t\t\tthis.sandbox.verifyAndRestore();\n\t\t\trouter.testHash = '';\n\t\t}\n\t} );\n\n\tQUnit.test( '#route, string', function ( assert ) {\n\t\trouter.testHash = '';\n\t\trouter.route( 'teststring', function () {\n\t\t\tassert.true( true, 'run callback for route' );\n\t\t} );\n\t\trouter.testHash = '#teststring';\n\t\trouter.emit( 'hashchange' );\n\t} );\n\n\tQUnit.test( '#route, string with reg ex characters', function ( assert ) {\n\t\trouter.testHash = '';\n\t\trouter.route( '/$+foo/.*/(x-y)', function () {\n\t\t\tassert.true( true, 'run callback for route' );\n\t\t} );\n\t\trouter.testHash = '#/$+foo/.*/(x-y)';\n\t\trouter.emit( 'hashchange' );\n\t} );\n\n\tQUnit.test( '#route, RegExp', function ( assert ) {\n\t\trouter.testHash = '';\n\t\trouter.route( /^testre-(\\d+)$/, function ( param ) {\n\t\t\tassert.strictEqual( param, '123', 'run callback for route with correct params' );\n\t\t} );\n\t\trouter.testHash = '#testre-abc';\n\t\trouter.emit( 'hashchange' );\n\t\trouter.testHash = '#testre-123';\n\t\trouter.emit( 'hashchange' );\n\t} );\n\n\tQUnit.test( 'on route', function ( assert ) {\n\t\tlet count = 0,\n\t\t\tspy = this.sandbox.spy(),\n\t\t\tdone = assert.async();\n\n\t\trouter.testHash = '';\n\t\trouter.route( 'testprevent', spy );\n\n\t\t// try preventing second route (#testprevent)\n\t\trouter.once( 'route', function () {\n\t\t\trouter.testHash = '#testprevent';\n\t\t\trouter.once( 'route', function ( ev ) {\n\t\t\t\tev.preventDefault();\n\t\t\t} );\n\t\t} );\n\t\trouter.testHash = '#initial';\n\n\t\trouter.on( 'hashchange.test', function () {\n\t\t\t++count;\n\t\t\tif ( count === 3 ) {\n\t\t\t\tassert.strictEqual( router.testHash, '#initial', 'reset hash' );\n\t\t\t\tassert.false( spy.called, 'don\\'t run callback for prevented route' );\n\t\t\t\tdone();\n\t\t\t}\n\t\t} );\n\t\t// emit a hashchange thrice to check if the hash has changed or not\n\t\trouter.emit( 'hashchange.test' );\n\t\trouter.emit( 'hashchange.test' );\n\t\trouter.emit( 'hashchange.test' );\n\t} );\n\n\tQUnit.test( 'on back', function ( assert ) {\n\t\tconst done1 = assert.async(),\n\t\t\tdone2 = assert.async();\n\t\tthis.sandbox.stub( window.history, 'back' );\n\t\trouter.back().done( function () {\n\t\t\tassert.true( true, 'back 1 complete' );\n\t\t\tdone1();\n\t\t} );\n\t\trouter.back().done( function () {\n\t\t\tassert.true( true, 'back 2 complete' );\n\t\t\tdone2();\n\t\t} );\n\t\trouter.emit( 'popstate' );\n\t} );\n\n\tQUnit.test( 'on back without popstate', function ( assert ) {\n\t\tconst historyStub = this.sandbox.stub( window.history, 'back' ),\n\t\t\tdone = assert.async();\n\t\trouter.on( 'popstate', function () {\n\t\t\tassert.true( false, 'this assertion is not supposed to get called' );\n\t\t} );\n\n\t\trouter.back().done( function () {\n\t\t\tassert.true( historyStub.called, 'history back has been called' );\n\t\t\tassert.true( true, 'back without popstate complete' );\n\t\t\tdone();\n\t\t} );\n\t} );\n\n\tQUnit.module( 'Router#navigate', {\n\t\tbeforeEach: function () {\n\t\t\tthis.sandbox = sinon.createSandbox();\n\t\t\tthis.sandbox.stub( document, 'title' ).value( docTitle );\n\t\t\tthis.pushState = this.sandbox.stub( window.history, 'pushState' );\n\t\t\tthis.replaceState = this.sandbox.stub( window.history, 'replaceState' );\n\t\t\trouter = new OO.Router();\n\t\t},\n\t\tafterEach: function () {\n\t\t\tthis.sandbox.verifyAndRestore();\n\t\t}\n\t} );\n\n\tQUnit.test( '#navigate(\"\")', function ( assert ) {\n\t\trouter.navigate( '' );\n\t\tassert.true( this.pushState.called, 'uses pushState to clear hash' );\n\t} );\n\tQUnit.test( '#navigate(\"foo\")', function ( assert ) {\n\t\trouter.navigate( 'foo' );\n\t\tassert.strictEqual( window.location.hash, '#foo',\n\t\t\t'Path is treated as the hash and pushState is called'\n\t\t);\n\t} );\n\tQUnit.test( '#navigateTo(\"/foo\", { useReplaceState: true } )', function ( assert ) {\n\t\trouter.navigateTo( 'Hello', { path: '/foo/bar#hash', useReplaceState: true } );\n\t\tassert.true(\n\t\t\tthis.replaceState.calledWith( null, 'Hello', '/foo/bar#hash' ),\n\t\t\t'Path is treated as the hash and replaceState is called'\n\t\t);\n\t} );\n\tQUnit.test( '#navigateTo(\"#bar\" )', function ( assert ) {\n\t\trouter.navigateTo( 'Hello', { path: '#bar' } );\n\t\tassert.true(\n\t\t\tthis.pushState.calledWith( null, 'Hello', '#bar' ),\n\t\t\t'Path is treated as the hash and pushState is called'\n\t\t);\n\t} );\n}() );\n","usedDeprecatedRules":[{"ruleId":"no-new-require","replacedBy":[]}]}]

--- end ---
$ /usr/bin/npm ci --legacy-peer-deps
--- stdout ---

> oojs-router@0.4.0 prepare
> grunt build

Running "clean:dist" (clean) task
>> 3 paths cleaned.

Running "concat:router" (concat) task

Running "uglify:js" (uglify) task
>> 1 sourcemap created.
>> 1 file created 5.64 kB → 1.87 kB

Done.

added 482 packages, and audited 483 packages in 6s

59 packages are looking for funding
  run `npm fund` for details

3 vulnerabilities (2 moderate, 1 high)

To address all issues, run:
  npm audit fix

Run `npm audit` for details.

--- end ---
$ /usr/bin/npm test
--- stdout ---

> oojs-router@0.4.0 test
> grunt test

Running "eslint:all" (eslint) task

/src/repo/src/index.js
   87:3  error    'hash' is never reassigned. Use 'const' instead       prefer-const
  116:4  warning  Found non-literal argument to RegExp Constructor      security/detect-non-literal-regexp
  172:6  error    'timeoutID' is never reassigned. Use 'const' instead  prefer-const
  173:3  error    'router' is never reassigned. Use 'const' instead     prefer-const
  174:3  error    'deferred' is never reassigned. Use 'const' instead   prefer-const

/src/repo/tests/oojs-router.test.js
   3:3  error  'docTitle' is never reassigned. Use 'const' instead  prefer-const
  53:4  error  'spy' is never reassigned. Use 'const' instead       prefer-const
  54:4  error  'done' is never reassigned. Use 'const' instead      prefer-const

✖ 8 problems (7 errors, 1 warning)

Warning: Task "eslint:all" failed. Use --force to continue.

Aborted due to warnings.

--- end ---
Traceback (most recent call last):
  File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 1400, in main
    libup.run(args.repo, args.output, args.branch)
  File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 1338, in run
    self.npm_upgrade(plan)
  File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 1049, in npm_upgrade
    self.npm_test()
  File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/__init__.py", line 287, in npm_test
    self.check_call(['npm', 'test'])
  File "/venv/lib/python3.9/site-packages/runner-0.1.0-py3.9.egg/runner/shell2.py", line 54, in check_call
    res.check_returncode()
  File "/usr/lib/python3.9/subprocess.py", line 460, in check_returncode
    raise CalledProcessError(self.returncode, self.args, self.stdout,
subprocess.CalledProcessError: Command '['/usr/bin/npm', 'test']' returned non-zero exit status 3.
Source code is licensed under the AGPL.