From e5dab2781ec705f696b0396687b757437ba430d6 Mon Sep 17 00:00:00 2001 From: audric Date: Fri, 13 Aug 2021 14:47:00 +1000 Subject: [PATCH] remove spectron dependency --- .prettierignore | 4 - CONTRIBUTING.md | 30 +- Gruntfile.js | 210 - app/sql_channel.js | 4 - js/background.js | 2 +- main.js | 38 +- package.json | 7 +- preload.js | 35 - test/.eslintrc.js | 39 - test/_test.js | 89 - test/app/.eslintrc.js | 12 - test/app/fixtures/menu-mac-os-setup.json | 170 - test/app/fixtures/menu-mac-os.json | 167 - .../fixtures/menu-windows-linux-setup.json | 134 - test/app/fixtures/menu-windows-linux.json | 131 - test/app/logging_test.js | 287 - test/app/menu_test.js | 73 - test/app/protocol_filter_test.js | 85 - test/blanket_mocha.js | 6055 ----------------- test/crypto_test.js | 112 - test/database_test.js | 36 - test/fixtures.js | 2719 -------- test/fixtures_test.js | 34 - test/i18n_test.js | 27 - test/index.html | 63 - test/manual.txt | 51 - test/models/conversations_test.js | 129 - test/models/messages_test.js | 154 - test/modules/.eslintrc.js | 30 - test/modules/privacy_test.js | 161 - test/modules/types/attachment_test.js | 226 - test/modules/types/errors_test.js | 37 - test/modules/types/message_test.js | 581 -- test/modules/types/mime_test.js | 28 - test/modules/types/schema_version_test.js | 20 - test/views/whisper_view_test.js | 38 - ts/opengroup/opengroupV2/OpenGroupAPIV2.ts | 2 +- ts/session/onions/onionPath.ts | 7 +- ts/session/snode_api/SNodeAPI.ts | 3 - ts/session/snode_api/lokiRpc.ts | 9 +- ts/session/snode_api/onions.ts | 4 +- ts/session/snode_api/swarmPolling.ts | 8 +- ts/session/types/PubKey.ts | 3 + ts/test/test-utils/utils/stubbing.ts | 16 - ts/util/lint/linter.ts | 1 - ts/window.d.ts | 4 +- yarn.lock | 1020 ++- 47 files changed, 702 insertions(+), 12393 deletions(-) delete mode 100644 test/.eslintrc.js delete mode 100644 test/_test.js delete mode 100644 test/app/.eslintrc.js delete mode 100644 test/app/fixtures/menu-mac-os-setup.json delete mode 100644 test/app/fixtures/menu-mac-os.json delete mode 100644 test/app/fixtures/menu-windows-linux-setup.json delete mode 100644 test/app/fixtures/menu-windows-linux.json delete mode 100644 test/app/logging_test.js delete mode 100644 test/app/menu_test.js delete mode 100644 test/app/protocol_filter_test.js delete mode 100644 test/blanket_mocha.js delete mode 100644 test/crypto_test.js delete mode 100644 test/database_test.js delete mode 100644 test/fixtures.js delete mode 100644 test/fixtures_test.js delete mode 100644 test/i18n_test.js delete mode 100644 test/index.html delete mode 100644 test/manual.txt delete mode 100644 test/models/conversations_test.js delete mode 100644 test/models/messages_test.js delete mode 100644 test/modules/.eslintrc.js delete mode 100644 test/modules/privacy_test.js delete mode 100644 test/modules/types/attachment_test.js delete mode 100644 test/modules/types/errors_test.js delete mode 100644 test/modules/types/message_test.js delete mode 100644 test/modules/types/mime_test.js delete mode 100644 test/modules/types/schema_version_test.js delete mode 100644 test/views/whisper_view_test.js diff --git a/.prettierignore b/.prettierignore index b0d3085c9..fbbd36871 100644 --- a/.prettierignore +++ b/.prettierignore @@ -30,12 +30,8 @@ js/WebAudioRecorderMp3.js libtextsecure/libsignal-protocol.js js/util_worker.js libtextsecure/test/blanket_mocha.js -test/blanket_mocha.js mnemonic_languages/** -# Test fixtures -test/fixtures.js - # Managed by package manager (`bower` and `yarn`/`npm`): /bower.json /package.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b38167e2b..94d3a1055 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,9 +36,9 @@ Then you need `git`, if you don't have that yet: https://git-scm.com/ ### Windows 1. **Windows 7 only:** - * Install Microsoft .NET Framework 4.5.1: + - Install Microsoft .NET Framework 4.5.1: https://www.microsoft.com/en-us/download/details.aspx?id=40773 - * Install Windows SDK version 8.1: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive + - Install Windows SDK version 8.1: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive 1. Install _Windows Build Tools_: Open the [Command Prompt (`cmd.exe`) as Administrator]() and run: `npm install --vs2015 --global --production --add-python-to-path windows-build-tools` @@ -136,16 +136,6 @@ Please write tests! Our testing framework is The easiest way to run all tests at once is `yarn test`. -You can browse tests from the command line with `grunt unit-tests` or in an -interactive session with `NODE_ENV=test yarn run start`. The `libtextsecure` tests are run -similarly: `grunt lib-unit-tests` and `NODE_ENV=test-lib yarn run start`. You can tweak -the appropriate `test.html` for both of these runs to get code coverage numbers via -`blanket.js` (it's shown at the bottom of the web page when the run is complete). - -To run Node.js tests, you can run `yarn test-server` from the command line. You can get -code coverage numbers for this kind of run via `yarn test-server-coverage`, then display -the report with `yarn open-coverage`. - ## Pull requests So you wanna make a pull request? Please observe the following guidelines. @@ -156,29 +146,29 @@ So you wanna make a pull request? Please observe the following guidelines. [Transifex](https://www.transifex.com/projects/p/signal-desktop). --> -* First, make sure that your `yarn ready` run passes - it's very similar to what our +- First, make sure that your `yarn ready` run passes - it's very similar to what our Continuous Integration servers do to test the app. -* Never use plain strings right in the source code - pull them from `messages.json`! +- Never use plain strings right in the source code - pull them from `messages.json`! You **only** need to modify the default locale [`_locales/en/messages.json`](_locales/en/messages.json). -* [Rebase](https://nathanleclaire.com/blog/2014/09/14/dont-be-scared-of-git-rebase/) your +- [Rebase](https://nathanleclaire.com/blog/2014/09/14/dont-be-scared-of-git-rebase/) your changes on the latest `development` branch, resolving any conflicts. This ensures that your changes will merge cleanly when you open your PR. -* Be sure to add and run tests! -* Make sure the diff between our master and your branch contains only the +- Be sure to add and run tests! +- Make sure the diff between our master and your branch contains only the minimal set of changes needed to implement your feature or bugfix. This will make it easier for the person reviewing your code to approve the changes. Please do not submit a PR with commented out code or unfinished features. -* Avoid meaningless or too-granular commits. If your branch contains commits like +- Avoid meaningless or too-granular commits. If your branch contains commits like the lines of "Oops, reverted this change" or "Just experimenting, will delete this later", please [squash or rebase those changes away](https://robots.thoughtbot.com/git-interactive-rebase-squash-amend-rewriting-history). -* Don't have too few commits. If you have a complicated or long lived feature +- Don't have too few commits. If you have a complicated or long lived feature branch, it may make sense to break the changes up into logical atomic chunks to aid in the review process. -* Provide a well written and nicely formatted commit message. See [this +- Provide a well written and nicely formatted commit message. See [this link](http://chris.beams.io/posts/git-commit/) for some tips on formatting. As far as content, try to include in your summary diff --git a/Gruntfile.js b/Gruntfile.js index a90f4a447..b421552bf 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,12 +1,6 @@ -const path = require('path'); -const packageJson = require('./package.json'); const importOnce = require('node-sass-import-once'); const rimraf = require('rimraf'); const mkdirp = require('mkdirp'); -const spectron = require('spectron'); -const asar = require('asar'); -const fs = require('fs'); -const assert = require('assert'); const sass = require('node-sass'); /* eslint-disable more/no-then, no-console */ @@ -53,10 +47,6 @@ module.exports = grunt => { src: libtextsecurecomponents, dest: 'libtextsecure/components.js', }, - test: { - src: ['node_modules/mocha/mocha.js', 'node_modules/chai/chai.js', 'test/_test.js'], - dest: 'test/test.js', - }, libtextsecure: { options: { banner: ';(function() {\n', @@ -130,27 +120,6 @@ module.exports = grunt => { cmd: 'yarn build-protobuf', }, }, - 'test-release': { - osx: { - archive: `mac/${packageJson.productName}.app/Contents/Resources/app.asar`, - appUpdateYML: `mac/${packageJson.productName}.app/Contents/Resources/app-update.yml`, - exe: `mac/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`, - }, - mas: { - archive: 'mas/Signal.app/Contents/Resources/app.asar', - appUpdateYML: 'mac/Signal.app/Contents/Resources/app-update.yml', - exe: `mas/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`, - }, - linux: { - archive: 'linux-unpacked/resources/app.asar', - exe: `linux-unpacked/${packageJson.name}`, - }, - win: { - archive: 'win-unpacked/resources/app.asar', - appUpdateYML: 'win-unpacked/resources/app-update.yml', - exe: `win-unpacked/${packageJson.productName}.exe`, - }, - }, gitinfo: {}, // to be populated by grunt gitinfo }); @@ -197,186 +166,7 @@ module.exports = grunt => { mkdirp.sync('release'); }); - function runTests(environment, cb) { - let failure; - const { Application } = spectron; - const electronBinary = process.platform === 'win32' ? 'electron.cmd' : 'electron'; - const app = new Application({ - path: path.join(__dirname, 'node_modules', '.bin', electronBinary), - args: [path.join(__dirname, 'main.js')], - env: { - NODE_ENV: environment, - }, - requireName: 'unused', - chromeDriverArgs: [ - `remote-debugging-port=${Math.floor(Math.random() * (9999 - 9000) + 9000)}`, - ], - }); - - function getMochaResults() { - // eslint-disable-next-line no-undef - return window.mochaResults; - } - - app - .start() - .then(() => - app.client.waitUntil( - () => app.client.execute(getMochaResults).then(data => Boolean(data.value)), - 25000, - 'Expected to find window.mochaResults set!' - ) - ) - .then(() => app.client.execute(getMochaResults)) - .then(data => { - const results = data.value; - if (results.failures > 0) { - console.error(results.reports); - failure = () => grunt.fail.fatal(`Found ${results.failures} failing unit tests.`); - return app.client.log('browser'); - } - grunt.log.ok(`${results.passes} tests passed.`); - return null; - }) - .then(logs => { - if (logs) { - console.error(); - console.error('Because tests failed, printing browser logs:'); - console.error(logs); - } - }) - .catch(error => { - failure = () => grunt.fail.fatal(`Something went wrong: ${error.message} ${error.stack}`); - }) - .then(() => { - // We need to use the failure variable and this early stop to clean up before - // shutting down. Grunt's fail methods are the only way to set the return value, - // but they shut the process down immediately! - if (failure) { - console.log(); - console.log('Main process logs:'); - return app.client.getMainProcessLogs().then(logs => { - logs.forEach(log => { - console.log(log); - }); - try { - return app.stop(); - } catch (err) { - return Promise.resolve(); - } - }); - } - try { - return app.stop(); - } catch (err) { - return Promise.resolve(); - } - }) - .then(() => { - if (failure) { - failure(); - } - cb(); - }) - .catch(error => { - console.error('Second-level error:', error.message, error.stack); - if (failure) { - failure(); - } - cb(); - }); - } - - grunt.registerTask('unit-tests', 'Run unit tests w/Electron', function thisNeeded() { - const environment = grunt.option('env') || 'test'; - const done = this.async(); - - runTests(environment, done); - }); - - grunt.registerMultiTask('test-release', 'Test packaged releases', function thisNeeded() { - const dir = grunt.option('dir') || 'release'; - const environment = grunt.option('env') || 'production'; - const config = this.data; - const archive = [dir, config.archive].join('/'); - const files = [ - 'config/default.json', - `config/${environment}.json`, - `config/local-${environment}.json`, - ]; - - console.log(this.target, archive); - const releaseFiles = files.concat(config.files || []); - releaseFiles.forEach(fileName => { - console.log(fileName); - try { - asar.statFile(archive, fileName); - return true; - } catch (e) { - console.log(e); - throw new Error(`Missing file ${fileName}`); - } - }); - - if (config.appUpdateYML) { - const appUpdateYML = [dir, config.appUpdateYML].join('/'); - if (fs.existsSync(appUpdateYML)) { - console.log('auto update ok'); - } else { - throw new Error(`Missing auto update config ${appUpdateYML}`); - } - } - - const done = this.async(); - // A simple test to verify a visible window is opened with a title - const { Application } = spectron; - - const app = new Application({ - path: [dir, config.exe].join('/'), - requireName: 'unused', - chromeDriverArgs: [ - `remote-debugging-port=${Math.floor(Math.random() * (9999 - 9000) + 9000)}`, - ], - }); - - app - .start() - .then(() => app.client.getWindowCount()) - .then(count => { - assert.equal(count, 1); - console.log('window opened'); - }) - .then(() => - // Get the window's title - app.client.getTitle() - ) - .then(title => { - // TODO: restore once fixed on win - if (this.target !== 'win') { - // Verify the window's title - assert.equal(title, packageJson.productName); - console.log('title ok'); - } - }) - .then(() => { - assert(app.chromeDriver.logLines.indexOf(`NODE_ENV ${environment}`) > -1); - console.log('environment ok'); - }) - .then( - () => - // Successfully completed test - app.stop(), - error => - // Test failed! - app.stop().then(() => { - grunt.fail.fatal(`Test failed: ${error.message} ${error.stack}`); - }) - ) - .then(done); - }); - grunt.registerTask('dev', ['default', 'watch']); - grunt.registerTask('test', ['unit-tests']); grunt.registerTask('date', ['gitinfo', 'getExpireTime']); grunt.registerTask('default', [ 'exec:build-protobuf', diff --git a/app/sql_channel.js b/app/sql_channel.js index 3ae0b4ee3..b0f765618 100644 --- a/app/sql_channel.js +++ b/app/sql_channel.js @@ -33,10 +33,6 @@ function initialize() { } catch (error) { const errorForDisplay = error && error.stack ? error.stack : error; console.log(`sql channel error with call ${callName}: ${errorForDisplay}`); - // FIXME this line cause the test-integration to fail and we probably don't need it during test - if (!process.env.NODE_ENV.includes('test-integration')) { - event.sender.send(`${SQL_CHANNEL_KEY}-done`, jobId, errorForDisplay); - } } }); diff --git a/js/background.js b/js/background.js index 465a57872..db3c4d3ab 100644 --- a/js/background.js +++ b/js/background.js @@ -63,7 +63,7 @@ // of preload.js processing window.setImmediate = window.nodeSetImmediate; window.globalOnlineStatus = true; // default to true as we don't get an event on app start - + window.getGlobalOnlineStatus = () => window.globalOnlineStatus; const { Views } = window.Signal; // Implicitly used in `indexeddb-backbonejs-adapter`: diff --git a/main.js b/main.js index dd7e28231..3c3f8393d 100644 --- a/main.js +++ b/main.js @@ -344,13 +344,7 @@ async function createWindow() { } }); - if (config.environment === 'test') { - mainWindow.loadURL(prepareURL([__dirname, 'test', 'index.html'])); - } else if (config.environment.includes('test-integration')) { - mainWindow.loadURL(prepareURL([__dirname, 'background_test.html'])); - } else { - mainWindow.loadURL(prepareURL([__dirname, 'background.html'])); - } + mainWindow.loadURL(prepareURL([__dirname, 'background.html'])); if (config.get('openDevTools')) { // Open the DevTools. @@ -368,11 +362,7 @@ async function createWindow() { shouldQuit: windowState.shouldQuit(), }); // If the application is terminating, just do the default - if ( - config.environment === 'test' || - config.environment.includes('test-integration') || - (mainWindow.readyForShutdown && windowState.shouldQuit()) - ) { + if (mainWindow.readyForShutdown && windowState.shouldQuit()) { return; } @@ -492,7 +482,7 @@ function showPasswordWindow() { passwordWindow.on('close', e => { // If the application is terminating, just do the default - if (config.environment === 'test' || windowState.shouldQuit()) { + if (windowState.shouldQuit()) { return; } @@ -620,14 +610,12 @@ app.on('ready', async () => { const userDataPath = await getRealPath(app.getPath('userData')); const installPath = await getRealPath(app.getAppPath()); - if (process.env.NODE_ENV !== 'test' && !process.env.NODE_ENV.includes('test-integration')) { - installFileHandler({ - protocol: electronProtocol, - userDataPath, - installPath, - isWindows: process.platform === 'win32', - }); - } + installFileHandler({ + protocol: electronProtocol, + userDataPath, + installPath, + isWindows: process.platform === 'win32', + }); installWebHandler({ protocol: electronProtocol, @@ -640,7 +628,7 @@ app.on('ready', async () => { logger.info('app ready'); logger.info(`starting version ${packageJson.version}`); if (!locale) { - const appLocale = process.env.NODE_ENV === 'test' ? 'en' : app.getLocale(); + const appLocale = app.getLocale() || 'en'; locale = loadLocale({ appLocale, logger }); } @@ -785,11 +773,7 @@ app.on('before-quit', () => { app.on('window-all-closed', () => { // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q - if ( - process.platform !== 'darwin' || - config.environment === 'test' || - config.environment.includes('test-integration') - ) { + if (process.platform !== 'darwin') { app.quit(); } }); diff --git a/package.json b/package.json index 68457d476..f98052d7d 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "start": "cross-env NODE_APP_INSTANCE=$MULTI electron .", "start-prod": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod$MULTI electron .", "start-prod2": "cross-env NODE_ENV=production NODE_APP_INSTANCE=devprod2 electron .", - "start-swarm-test": "cross-env NODE_ENV=swarm-testing NODE_APP_INSTANCE=$MULTI electron .", "grunt": "grunt", "grunt:dev": "yarn clean-transpile; yarn grunt dev --force", "generate": "yarn grunt --force", @@ -36,10 +35,7 @@ "clean-module-protobuf": "rimraf ts/protobuf/compiled.d.ts ts/protobuf/compiled.js", "build-protobuf": "yarn build-module-protobuf", "clean-protobuf": "yarn clean-module-protobuf", - "test": "yarn test-node && yarn test-electron", - "test-view": "NODE_ENV=test yarn run start", - "test-lib-view": "NODE_ENV=test-lib yarn run start", - "test-electron": "yarn grunt test", + "test": "yarn test-node", "test-node": "mocha --recursive --exit --timeout 10000 test/app test/modules \"./ts/test/**/*_test.js\" ", "eslint-full": "eslint .", "lint-full": "yarn format-full && yarn lint-files-full", @@ -213,7 +209,6 @@ "qs": "6.5.1", "run-script-os": "^1.1.6", "sinon": "9.0.2", - "spectron": "^10.0.0", "ts-loader": "4.1.0", "ts-mock-imports": "^1.3.0", "tslint": "5.19.0", diff --git a/preload.js b/preload.js index 9fcb9173b..c1d31f23b 100644 --- a/preload.js +++ b/preload.js @@ -46,8 +46,6 @@ window.getServerTrustRoot = () => config.serverTrustRoot; window.JobQueue = JobQueue; window.isBehindProxy = () => Boolean(config.proxyUrl); -window.getStoragePubKey = key => (window.isDev() ? key.substring(2) : key); - window.lokiFeatureFlags = { useOnionRequests: true, useFileOnionRequests: true, @@ -56,10 +54,6 @@ window.lokiFeatureFlags = { enablePinConversations: true, }; -if (typeof process.env.NODE_ENV === 'string' && process.env.NODE_ENV.includes('test-integration')) { - window.electronRequire = require; -} - window.isBeforeVersion = (toCheck, baseVersion) => { try { return semver.lt(toCheck, baseVersion); @@ -353,35 +347,6 @@ Promise.prototype.ignore = function() { this.then(() => {}); }; -if ( - config.environment.includes('test') && - !config.environment.includes('swarm-testing') && - !config.environment.includes('test-integration') -) { - const isWindows = process.platform === 'win32'; - /* eslint-disable global-require, import/no-extraneous-dependencies */ - window.test = { - glob: require('glob'), - fse: require('fs-extra'), - tmp: require('tmp'), - path: require('path'), - basePath: __dirname, - attachmentsPath: window.Signal.Migrations.attachmentsPath, - isWindows, - }; - /* eslint-enable global-require, import/no-extraneous-dependencies */ - window.lokiFeatureFlags = {}; -} -if (config.environment.includes('test-integration')) { - window.lokiFeatureFlags = { - useOnionRequests: false, - useFileOnionRequests: false, - }; - /* eslint-disable global-require, import/no-extraneous-dependencies */ - window.sinon = require('sinon'); - /* eslint-enable global-require, import/no-extraneous-dependencies */ -} - // Blocking const { BlockedNumberController } = require('./ts/util/blockedNumberController'); diff --git a/test/.eslintrc.js b/test/.eslintrc.js deleted file mode 100644 index 206699c84..000000000 --- a/test/.eslintrc.js +++ /dev/null @@ -1,39 +0,0 @@ -// For reference: https://github.com/airbnb/javascript - -module.exports = { - env: { - mocha: true, - browser: true, - }, - - globals: { - assert: true, - assertEqualArrayBuffers: true, - clearDatabase: true, - dcodeIO: true, - getString: true, - hexToArrayBuffer: true, - PROTO_ROOT: true, - stringToArrayBuffer: true, - }, - - parserOptions: { - sourceType: 'script', - }, - - rules: { - // We still get the value of this rule, it just allows for dev deps - 'import/no-extraneous-dependencies': [ - 'error', - { - devDependencies: true, - }, - ], - - // We want to keep each test structured the same, even if its contents are tiny - 'arrow-body-style': 'off', - - strict: 'off', - 'more/no-then': 'off', - }, -}; diff --git a/test/_test.js b/test/_test.js deleted file mode 100644 index 2f9a3a30b..000000000 --- a/test/_test.js +++ /dev/null @@ -1,89 +0,0 @@ -/* global chai, Whisper, _, Backbone */ - -mocha - .setup('bdd') - .fullTrace() - .timeout(10000); -window.assert = chai.assert; -window.PROTO_ROOT = '../protos'; - -const OriginalReporter = mocha._reporter; - -const SauceReporter = function Constructor(runner) { - const failedTests = []; - - runner.on('end', () => { - window.mochaResults = runner.stats; - window.mochaResults.reports = failedTests; - }); - - runner.on('fail', (test, err) => { - const flattenTitles = item => { - const titles = []; - while (item.parent.title) { - titles.push(item.parent.title); - // eslint-disable-next-line no-param-reassign - item = item.parent; - } - return titles.reverse(); - }; - failedTests.push({ - name: test.title, - result: false, - message: err.message, - stack: err.stack, - titles: flattenTitles(test), - }); - }); - - // eslint-disable-next-line no-new - new OriginalReporter(runner); -}; - -SauceReporter.prototype = OriginalReporter.prototype; - -mocha.reporter(SauceReporter); - -// Override the database id. -window.Whisper = window.Whisper || {}; -window.Whisper.Database = window.Whisper.Database || {}; -Whisper.Database.id = 'test'; - -/* - * global helpers for tests - */ -window.assertEqualArrayBuffers = (ab1, ab2) => { - assert.deepEqual(new Uint8Array(ab1), new Uint8Array(ab2)); -}; - -window.hexToArrayBuffer = str => { - const ret = new ArrayBuffer(str.length / 2); - const array = new Uint8Array(ret); - for (let i = 0; i < str.length / 2; i += 1) { - array[i] = parseInt(str.substr(i * 2, 2), 16); - } - return ret; -}; - -function deleteIndexedDB() { - return new Promise((resolve, reject) => { - const idbReq = indexedDB.deleteDatabase('test'); - idbReq.onsuccess = resolve; - idbReq.error = reject; - }); -} - -/* Delete the database before running any tests */ -before(async () => { - await deleteIndexedDB(); - await window.Signal.Data.removeAll(); - await window.storage.fetch(); -}); - -window.clearDatabase = async () => { - await window.Signal.Data.removeAll(); - await window.storage.fetch(); -}; - -window.Whisper = window.Whisper || {}; -window.Whisper.events = _.clone(Backbone.Events); diff --git a/test/app/.eslintrc.js b/test/app/.eslintrc.js deleted file mode 100644 index 38ff2d117..000000000 --- a/test/app/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// For reference: https://github.com/airbnb/javascript - -module.exports = { - env: { - mocha: true, - browser: false, - }, - - parserOptions: { - sourceType: 'module', - }, -}; diff --git a/test/app/fixtures/menu-mac-os-setup.json b/test/app/fixtures/menu-mac-os-setup.json deleted file mode 100644 index 51ca2e0ae..000000000 --- a/test/app/fixtures/menu-mac-os-setup.json +++ /dev/null @@ -1,170 +0,0 @@ -[ - { - "label": "Session", - "submenu": [ - { - "label": "About", - "click": null - }, - { - "type": "separator" - }, - { - "type": "separator" - }, - { - "label": "Hide", - "role": "hide" - }, - { - "label": "Hide Others", - "role": "hideothers" - }, - { - "label": "Show All", - "role": "unhide" - }, - { - "type": "separator" - }, - { - "label": "Quit Session", - "role": "quit" - } - ] - }, - { - "label": "&File" - }, - { - "label": "&Edit", - "submenu": [ - { - "label": "Undo", - "role": "undo" - }, - { - "label": "Redo", - "role": "redo" - }, - { - "type": "separator" - }, - { - "label": "Cut", - "role": "cut" - }, - { - "label": "Copy", - "role": "copy" - }, - { - "label": "Paste", - "role": "paste" - }, - { - "label": "Paste and Match Style", - "role": "pasteandmatchstyle" - }, - { - "label": "Delete", - "role": "delete" - }, - { - "label": "Select all", - "role": "selectall" - } - ] - }, - { - "label": "&View", - "submenu": [ - { - "label": "Actual Size", - "role": "resetzoom" - }, - { - "accelerator": "Command+=", - "label": "Zoom In", - "role": "zoomin" - }, - { - "label": "Zoom Out", - "role": "zoomout" - }, - { - "type": "separator" - }, - { - "label": "Toggle Full Screen", - "role": "togglefullscreen" - }, - { - "type": "separator" - }, - { - "label": "Debug Log", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Toggle Developer Tools", - "role": "toggledevtools" - } - ] - }, - { - "label": "&Window", - "role": "window", - "submenu": [ - { - "label": "Close Window", - "accelerator": "CmdOrCtrl+W", - "role": "close" - }, - { - "label": "Minimize", - "accelerator": "CmdOrCtrl+M", - "role": "minimize" - }, - { - "label": "Zoom", - "role": "zoom" - }, - { - "label": "Show", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Bring All to Front", - "role": "front" - } - ] - }, - { - "label": "&Help", - "role": "help", - "submenu": [ - { - "label": "Go to Release Notes", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Go to Support Page", - "click": null - }, - { - "label": "Report an Issue", - "click": null - } - ] - } -] diff --git a/test/app/fixtures/menu-mac-os.json b/test/app/fixtures/menu-mac-os.json deleted file mode 100644 index c8fd44637..000000000 --- a/test/app/fixtures/menu-mac-os.json +++ /dev/null @@ -1,167 +0,0 @@ -[ - { - "label": "Session", - "submenu": [ - { - "label": "About", - "click": null - }, - { - "type": "separator" - }, - { - "type": "separator" - }, - { - "label": "Hide", - "role": "hide" - }, - { - "label": "Hide Others", - "role": "hideothers" - }, - { - "label": "Show All", - "role": "unhide" - }, - { - "type": "separator" - }, - { - "label": "Quit Session", - "role": "quit" - } - ] - }, - { - "label": "&Edit", - "submenu": [ - { - "label": "Undo", - "role": "undo" - }, - { - "label": "Redo", - "role": "redo" - }, - { - "type": "separator" - }, - { - "label": "Cut", - "role": "cut" - }, - { - "label": "Copy", - "role": "copy" - }, - { - "label": "Paste", - "role": "paste" - }, - { - "label": "Paste and Match Style", - "role": "pasteandmatchstyle" - }, - { - "label": "Delete", - "role": "delete" - }, - { - "label": "Select all", - "role": "selectall" - } - ] - }, - { - "label": "&View", - "submenu": [ - { - "label": "Actual Size", - "role": "resetzoom" - }, - { - "accelerator": "Command+=", - "label": "Zoom In", - "role": "zoomin" - }, - { - "label": "Zoom Out", - "role": "zoomout" - }, - { - "type": "separator" - }, - { - "label": "Toggle Full Screen", - "role": "togglefullscreen" - }, - { - "type": "separator" - }, - { - "label": "Debug Log", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Toggle Developer Tools", - "role": "toggledevtools" - } - ] - }, - { - "label": "&Window", - "role": "window", - "submenu": [ - { - "label": "Close Window", - "accelerator": "CmdOrCtrl+W", - "role": "close" - }, - { - "label": "Minimize", - "accelerator": "CmdOrCtrl+M", - "role": "minimize" - }, - { - "label": "Zoom", - "role": "zoom" - }, - { - "label": "Show", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Bring All to Front", - "role": "front" - } - ] - }, - { - "label": "&Help", - "role": "help", - "submenu": [ - { - "label": "Go to Release Notes", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Go to Support Page", - "click": null - }, - { - "label": "Report an Issue", - "click": null - } - ] - } -] diff --git a/test/app/fixtures/menu-windows-linux-setup.json b/test/app/fixtures/menu-windows-linux-setup.json deleted file mode 100644 index 25d0eff82..000000000 --- a/test/app/fixtures/menu-windows-linux-setup.json +++ /dev/null @@ -1,134 +0,0 @@ -[ - { - "label": "&File", - "submenu": [ - { - "type": "separator" - }, - { - "type": "separator" - }, - { - "label": "Quit Session", - "role": "quit" - } - ] - }, - { - "label": "&Edit", - "submenu": [ - { - "label": "Undo", - "role": "undo" - }, - { - "label": "Redo", - "role": "redo" - }, - { - "type": "separator" - }, - { - "label": "Cut", - "role": "cut" - }, - { - "label": "Copy", - "role": "copy" - }, - { - "label": "Paste", - "role": "paste" - }, - { - "label": "Paste and Match Style", - "role": "pasteandmatchstyle" - }, - { - "label": "Delete", - "role": "delete" - }, - { - "label": "Select all", - "role": "selectall" - } - ] - }, - { - "label": "&View", - "submenu": [ - { - "label": "Actual Size", - "role": "resetzoom" - }, - { - "accelerator": "Control+Plus", - "label": "Zoom In", - "role": "zoomin" - }, - { - "label": "Zoom Out", - "role": "zoomout" - }, - { - "type": "separator" - }, - { - "label": "Toggle Full Screen", - "role": "togglefullscreen" - }, - { - "type": "separator" - }, - { - "label": "Debug Log", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Toggle Developer Tools", - "role": "toggledevtools" - } - ] - }, - { - "label": "&Window", - "role": "window", - "submenu": [ - { - "label": "Minimize", - "role": "minimize" - } - ] - }, - { - "label": "&Help", - "role": "help", - "submenu": [ - { - "label": "Go to Release Notes", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Go to Support Page", - "click": null - }, - { - "label": "Report an Issue", - "click": null - }, - { - "type": "separator" - }, - { - "label": "About", - "click": null - } - ] - } -] diff --git a/test/app/fixtures/menu-windows-linux.json b/test/app/fixtures/menu-windows-linux.json deleted file mode 100644 index 30a6301d0..000000000 --- a/test/app/fixtures/menu-windows-linux.json +++ /dev/null @@ -1,131 +0,0 @@ -[ - { - "label": "&File", - "submenu": [ - { - "type": "separator" - }, - { - "label": "Quit Session", - "role": "quit" - } - ] - }, - { - "label": "&Edit", - "submenu": [ - { - "label": "Undo", - "role": "undo" - }, - { - "label": "Redo", - "role": "redo" - }, - { - "type": "separator" - }, - { - "label": "Cut", - "role": "cut" - }, - { - "label": "Copy", - "role": "copy" - }, - { - "label": "Paste", - "role": "paste" - }, - { - "label": "Paste and Match Style", - "role": "pasteandmatchstyle" - }, - { - "label": "Delete", - "role": "delete" - }, - { - "label": "Select all", - "role": "selectall" - } - ] - }, - { - "label": "&View", - "submenu": [ - { - "label": "Actual Size", - "role": "resetzoom" - }, - { - "accelerator": "Control+Plus", - "label": "Zoom In", - "role": "zoomin" - }, - { - "label": "Zoom Out", - "role": "zoomout" - }, - { - "type": "separator" - }, - { - "label": "Toggle Full Screen", - "role": "togglefullscreen" - }, - { - "type": "separator" - }, - { - "label": "Debug Log", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Toggle Developer Tools", - "role": "toggledevtools" - } - ] - }, - { - "label": "&Window", - "role": "window", - "submenu": [ - { - "label": "Minimize", - "role": "minimize" - } - ] - }, - { - "label": "&Help", - "role": "help", - "submenu": [ - { - "label": "Go to Release Notes", - "click": null - }, - { - "type": "separator" - }, - { - "label": "Go to Support Page", - "click": null - }, - { - "label": "Report an Issue", - "click": null - }, - { - "type": "separator" - }, - { - "label": "About", - "click": null - } - ] - } -] diff --git a/test/app/logging_test.js b/test/app/logging_test.js deleted file mode 100644 index c51a4cc72..000000000 --- a/test/app/logging_test.js +++ /dev/null @@ -1,287 +0,0 @@ -// NOTE: Temporarily allow `then` until we convert the entire file to `async` / `await`: -/* eslint-disable more/no-then */ - -const fs = require('fs'); -const path = require('path'); - -const tmp = require('tmp'); -const { expect } = require('chai'); - -const { - eliminateOutOfDateFiles, - eliminateOldEntries, - isLineAfterDate, - fetchLog, - fetch, -} = require('../../app/logging'); - -describe('app/logging', () => { - let basePath; - let tmpDir; - - beforeEach(() => { - tmpDir = tmp.dirSync({ - unsafeCleanup: true, - }); - basePath = tmpDir.name; - }); - - afterEach(done => { - // we need the unsafe option to recursively remove the directory - try { - tmpDir.removeCallback(done); - } catch (e) { - // eslint-disable-next-line no-console - console.error('removeCallback failed with ', e); - done(); - } - }); - - describe('#isLineAfterDate', () => { - it('returns false if falsy', () => { - const actual = isLineAfterDate('', new Date()); - expect(actual).to.equal(false); - }); - it('returns false if invalid JSON', () => { - const actual = isLineAfterDate('{{}', new Date()); - expect(actual).to.equal(false); - }); - it('returns false if date is invalid', () => { - const line = JSON.stringify({ time: '2018-01-04T19:17:05.014Z' }); - const actual = isLineAfterDate(line, new Date('try6')); - expect(actual).to.equal(false); - }); - it('returns false if log time is invalid', () => { - const line = JSON.stringify({ time: 'try7' }); - const date = new Date('2018-01-04T19:17:00.000Z'); - const actual = isLineAfterDate(line, date); - expect(actual).to.equal(false); - }); - it('returns false if date before provided date', () => { - const line = JSON.stringify({ time: '2018-01-04T19:17:00.000Z' }); - const date = new Date('2018-01-04T19:17:05.014Z'); - const actual = isLineAfterDate(line, date); - expect(actual).to.equal(false); - }); - it('returns true if date is after provided date', () => { - const line = JSON.stringify({ time: '2018-01-04T19:17:05.014Z' }); - const date = new Date('2018-01-04T19:17:00.000Z'); - const actual = isLineAfterDate(line, date); - expect(actual).to.equal(true); - }); - }); - - describe('#eliminateOutOfDateFiles', () => { - it('deletes an empty file', () => { - const date = new Date(); - const log = '\n'; - const target = path.join(basePath, 'log.log'); - fs.writeFileSync(target, log); - - return eliminateOutOfDateFiles(basePath, date).then(() => { - expect(fs.existsSync(target)).to.equal(false); - }); - }); - it('deletes a file with invalid JSON lines', () => { - const date = new Date(); - const log = '{{}\n'; - const target = path.join(basePath, 'log.log'); - fs.writeFileSync(target, log); - - return eliminateOutOfDateFiles(basePath, date).then(() => { - expect(fs.existsSync(target)).to.equal(false); - }); - }); - it('deletes a file with all dates before provided date', () => { - const date = new Date('2018-01-04T19:17:05.014Z'); - const contents = [ - JSON.stringify({ time: '2018-01-04T19:17:00.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); - const target = path.join(basePath, 'log.log'); - fs.writeFileSync(target, contents); - - return eliminateOutOfDateFiles(basePath, date).then(() => { - expect(fs.existsSync(target)).to.equal(false); - }); - }); - it('keeps a file with first line date before provided date', () => { - const date = new Date('2018-01-04T19:16:00.000Z'); - const contents = [ - JSON.stringify({ time: '2018-01-04T19:17:00.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); - const target = path.join(basePath, 'log.log'); - fs.writeFileSync(target, contents); - - return eliminateOutOfDateFiles(basePath, date).then(() => { - expect(fs.existsSync(target)).to.equal(true); - }); - }); - it('keeps a file with last line date before provided date', () => { - const date = new Date('2018-01-04T19:17:01.000Z'); - const contents = [ - JSON.stringify({ time: '2018-01-04T19:17:00.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); - const target = path.join(basePath, 'log.log'); - fs.writeFileSync(target, contents); - - return eliminateOutOfDateFiles(basePath, date).then(() => { - expect(fs.existsSync(target)).to.equal(true); - }); - }); - }); - - describe('#eliminateOldEntries', () => { - it('eliminates all non-parsing entries', () => { - const date = new Date('2018-01-04T19:17:01.000Z'); - const contents = [ - 'random line', - JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); - const expected = [ - JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); - - const target = path.join(basePath, 'log.log'); - const files = [ - { - path: target, - }, - ]; - - fs.writeFileSync(target, contents); - - return eliminateOldEntries(files, date).then(() => { - expect(fs.readFileSync(target, 'utf8')).to.equal(`${expected}\n`); - }); - }); - it('preserves all lines if before target date', () => { - const date = new Date('2018-01-04T19:17:03.000Z'); - const contents = [ - 'random line', - JSON.stringify({ time: '2018-01-04T19:17:01.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:02.014Z' }), - JSON.stringify({ time: '2018-01-04T19:17:03.014Z' }), - ].join('\n'); - const expected = [JSON.stringify({ time: '2018-01-04T19:17:03.014Z' })].join('\n'); - - const target = path.join(basePath, 'log.log'); - const files = [ - { - path: target, - }, - ]; - - fs.writeFileSync(target, contents); - - return eliminateOldEntries(files, date).then(() => { - expect(fs.readFileSync(target, 'utf8')).to.equal(`${expected}\n`); - }); - }); - }); - - describe('#fetchLog', () => { - it('returns error if file does not exist', () => { - const target = 'random_file'; - return fetchLog(target).then( - () => { - throw new Error('Expected an error!'); - }, - error => { - expect(error) - .to.have.property('message') - .that.match(/random_file/); - } - ); - }); - it('returns empty array if file has no valid JSON lines', () => { - const contents = 'line 1\nline2\n'; - const expected = []; - const target = path.join(basePath, 'test.log'); - - fs.writeFileSync(target, contents); - - return fetchLog(target).then(result => { - expect(result).to.deep.equal(expected); - }); - }); - it('returns just three fields in each returned line', () => { - const contents = [ - JSON.stringify({ - one: 1, - two: 2, - level: 1, - time: 2, - msg: 3, - }), - JSON.stringify({ - one: 1, - two: 2, - level: 2, - time: 3, - msg: 4, - }), - '', - ].join('\n'); - const expected = [ - { - level: 1, - time: 2, - msg: 3, - }, - { - level: 2, - time: 3, - msg: 4, - }, - ]; - - const target = path.join(basePath, 'test.log'); - - fs.writeFileSync(target, contents); - - return fetchLog(target).then(result => { - expect(result).to.deep.equal(expected); - }); - }); - }); - - describe('#fetch', () => { - it('returns single entry if no files', () => { - return fetch(basePath).then(results => { - expect(results).to.have.length(1); - expect(results[0].msg).to.match(/Loaded this list/); - }); - }); - it('returns sorted entries from all files', () => { - const first = [JSON.stringify({ msg: 2, time: '2018-01-04T19:17:05.014Z' }), ''].join('\n'); - const second = [ - JSON.stringify({ msg: 1, time: '2018-01-04T19:17:00.014Z' }), - JSON.stringify({ msg: 3, time: '2018-01-04T19:18:00.014Z' }), - '', - ].join('\n'); - - fs.writeFileSync(path.join(basePath, 'first.log'), first); - fs.writeFileSync(path.join(basePath, 'second.log'), second); - - return fetch(basePath).then(results => { - expect(results).to.have.length(4); - expect(results[0].msg).to.equal(1); - expect(results[1].msg).to.equal(2); - expect(results[2].msg).to.equal(3); - }); - }); - }); -}); diff --git a/test/app/menu_test.js b/test/app/menu_test.js deleted file mode 100644 index c93e32000..000000000 --- a/test/app/menu_test.js +++ /dev/null @@ -1,73 +0,0 @@ -const { assert } = require('chai'); - -const SignalMenu = require('../../app/menu'); -const { load: loadLocale } = require('../../app/locale'); - -const PLATFORMS = [ - { - label: 'macOS', - platform: 'darwin', - fixtures: { - default: './fixtures/menu-mac-os', - setup: './fixtures/menu-mac-os-setup', - }, - }, - { - label: 'Windows', - platform: 'win32', - fixtures: { - default: './fixtures/menu-windows-linux', - setup: './fixtures/menu-windows-linux-setup', - }, - }, - { - label: 'Linux', - platform: 'linux', - fixtures: { - default: './fixtures/menu-windows-linux', - setup: './fixtures/menu-windows-linux-setup', - }, - }, -]; - -const INCLUDE_SETUP_OPTIONS = [false, true]; - -describe('SignalMenu', () => { - describe('createTemplate', () => { - PLATFORMS.forEach(({ label, platform, fixtures }) => { - context(label, () => { - INCLUDE_SETUP_OPTIONS.forEach(includeSetup => { - const prefix = includeSetup ? 'with' : 'without'; - context(`${prefix} setup options`, () => { - it('should return correct template', () => { - const logger = { - error(message) { - throw new Error(message); - }, - }; - const options = { - openNewBugForm: null, - openReleaseNotes: null, - openSupportPage: null, - platform, - includeSetup, - showAbout: null, - showDebugLog: null, - showSettings: null, - showWindow: null, - }; - const appLocale = 'en'; - const { messages } = loadLocale({ appLocale, logger }); - - const actual = SignalMenu.createTemplate(options, messages); - const fixturePath = includeSetup ? fixtures.setup : fixtures.default; - // eslint-disable-next-line global-require, import/no-dynamic-require - const fixture = require(fixturePath); - assert.deepEqual(actual, fixture); - }); - }); - }); - }); - }); - }); -}); diff --git a/test/app/protocol_filter_test.js b/test/app/protocol_filter_test.js deleted file mode 100644 index da2b1fee3..000000000 --- a/test/app/protocol_filter_test.js +++ /dev/null @@ -1,85 +0,0 @@ -const { expect } = require('chai'); - -const { _urlToPath } = require('../../app/protocol_filter'); - -describe('Protocol Filter', () => { - describe('_urlToPath', () => { - it('returns proper file path for unix style file URI with hash', () => { - const path = 'file:///Users/someone/Development/signal/electron/background.html#first-page'; - const expected = '/Users/someone/Development/signal/electron/background.html'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - - it('returns proper file path for unix style file URI with querystring', () => { - const path = - 'file:///Users/someone/Development/signal/electron/background.html?name=Signal&locale=en&version=2.4.0'; - const expected = '/Users/someone/Development/signal/electron/background.html'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - - it('returns proper file path for unix style file URI with hash and querystring', () => { - const path = - 'file:///Users/someone/Development/signal/electron/background.html#somewhere?name=Signal'; - const expected = '/Users/someone/Development/signal/electron/background.html'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - - it('returns proper file path for file URI on windows', () => { - const path = - 'file:///C:/Users/Someone/dev/desktop/background.html?name=Signal&locale=en&version=2.4.0'; - const expected = 'C:/Users/Someone/dev/desktop/background.html'; - const isWindows = true; - - const actual = _urlToPath(path, { isWindows }); - expect(actual).to.equal(expected); - }); - - it('translates from URL format to filesystem format', () => { - const path = 'file:///Users/someone/Development%20Files/signal/electron/background.html'; - const expected = '/Users/someone/Development Files/signal/electron/background.html'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - - it('translates from URL format to filesystem format', () => { - const path = 'file:///Users/someone/Development%20Files/signal/electron/background.html'; - const expected = '/Users/someone/Development Files/signal/electron/background.html'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - - // this seems to be the only way to get a relative path through Electron - it('handles SMB share path', () => { - const path = 'file://relative/path'; - const expected = 'relative/path'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - - it('handles SMB share path on windows', () => { - const path = 'file://relative/path'; - const expected = 'elative/path'; - const isWindows = true; - - const actual = _urlToPath(path, { isWindows }); - expect(actual).to.equal(expected); - }); - - it('hands back a path with .. in it', () => { - const path = 'file://../../..'; - const expected = '../../..'; - - const actual = _urlToPath(path); - expect(actual).to.equal(expected); - }); - }); -}); diff --git a/test/blanket_mocha.js b/test/blanket_mocha.js deleted file mode 100644 index c10e5eb0c..000000000 --- a/test/blanket_mocha.js +++ /dev/null @@ -1,6055 +0,0 @@ -/*! blanket - v1.1.5 */ - -(function(define) { - /* - Copyright (C) 2013 Ariya Hidayat - Copyright (C) 2013 Thaddee Tyl - Copyright (C) 2013 Mathias Bynens - Copyright (C) 2012 Ariya Hidayat - Copyright (C) 2012 Mathias Bynens - Copyright (C) 2012 Joost-Wim Boekesteijn - Copyright (C) 2012 Kris Kowal - Copyright (C) 2012 Yusuke Suzuki - Copyright (C) 2012 Arpad Borsos - Copyright (C) 2011 Ariya Hidayat - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - - /*jslint bitwise:true plusplus:true */ - /*global esprima:true, define:true, exports:true, window: true, -throwErrorTolerant: true, -throwError: true, generateStatement: true, peek: true, -parseAssignmentExpression: true, parseBlock: true, parseExpression: true, -parseFunctionDeclaration: true, parseFunctionExpression: true, -parseFunctionSourceElements: true, parseVariableIdentifier: true, -parseLeftHandSideExpression: true, -parseUnaryExpression: true, -parseStatement: true, parseSourceElement: true */ - - (function(root, factory) { - 'use strict'; - - // Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, - // Rhino, and plain browser loading. - - /* istanbul ignore next */ - if (typeof define === 'function' && define.amd) { - define(['exports'], factory); - } else if (typeof exports !== 'undefined') { - factory(exports); - } else { - factory((root.esprima = {})); - } - })(this, function(exports) { - 'use strict'; - - var Token, - TokenName, - FnExprTokens, - Syntax, - PropertyKind, - Messages, - Regex, - SyntaxTreeDelegate, - source, - strict, - index, - lineNumber, - lineStart, - length, - delegate, - lookahead, - state, - extra; - - Token = { - BooleanLiteral: 1, - EOF: 2, - Identifier: 3, - Keyword: 4, - NullLiteral: 5, - NumericLiteral: 6, - Punctuator: 7, - StringLiteral: 8, - RegularExpression: 9, - }; - - TokenName = {}; - TokenName[Token.BooleanLiteral] = 'Boolean'; - TokenName[Token.EOF] = ''; - TokenName[Token.Identifier] = 'Identifier'; - TokenName[Token.Keyword] = 'Keyword'; - TokenName[Token.NullLiteral] = 'Null'; - TokenName[Token.NumericLiteral] = 'Numeric'; - TokenName[Token.Punctuator] = 'Punctuator'; - TokenName[Token.StringLiteral] = 'String'; - TokenName[Token.RegularExpression] = 'RegularExpression'; - - // A function following one of those tokens is an expression. - FnExprTokens = [ - '(', - '{', - '[', - 'in', - 'typeof', - 'instanceof', - 'new', - 'return', - 'case', - 'delete', - 'throw', - 'void', - // assignment operators - '=', - '+=', - '-=', - '*=', - '/=', - '%=', - '<<=', - '>>=', - '>>>=', - '&=', - '|=', - '^=', - ',', - // binary/unary operators - '+', - '-', - '*', - '/', - '%', - '++', - '--', - '<<', - '>>', - '>>>', - '&', - '|', - '^', - '!', - '~', - '&&', - '||', - '?', - ':', - '===', - '==', - '>=', - '<=', - '<', - '>', - '!=', - '!==', - ]; - - Syntax = { - AssignmentExpression: 'AssignmentExpression', - ArrayExpression: 'ArrayExpression', - BlockStatement: 'BlockStatement', - BinaryExpression: 'BinaryExpression', - BreakStatement: 'BreakStatement', - CallExpression: 'CallExpression', - CatchClause: 'CatchClause', - ConditionalExpression: 'ConditionalExpression', - ContinueStatement: 'ContinueStatement', - DoWhileStatement: 'DoWhileStatement', - DebuggerStatement: 'DebuggerStatement', - EmptyStatement: 'EmptyStatement', - ExpressionStatement: 'ExpressionStatement', - ForStatement: 'ForStatement', - ForInStatement: 'ForInStatement', - FunctionDeclaration: 'FunctionDeclaration', - FunctionExpression: 'FunctionExpression', - Identifier: 'Identifier', - IfStatement: 'IfStatement', - Literal: 'Literal', - LabeledStatement: 'LabeledStatement', - LogicalExpression: 'LogicalExpression', - MemberExpression: 'MemberExpression', - NewExpression: 'NewExpression', - ObjectExpression: 'ObjectExpression', - Program: 'Program', - Property: 'Property', - ReturnStatement: 'ReturnStatement', - SequenceExpression: 'SequenceExpression', - SwitchStatement: 'SwitchStatement', - SwitchCase: 'SwitchCase', - ThisExpression: 'ThisExpression', - ThrowStatement: 'ThrowStatement', - TryStatement: 'TryStatement', - UnaryExpression: 'UnaryExpression', - UpdateExpression: 'UpdateExpression', - VariableDeclaration: 'VariableDeclaration', - VariableDeclarator: 'VariableDeclarator', - WhileStatement: 'WhileStatement', - WithStatement: 'WithStatement', - }; - - PropertyKind = { - Data: 1, - Get: 2, - Set: 4, - }; - - // Error messages should be identical to V8. - Messages = { - UnexpectedToken: 'Unexpected token %0', - UnexpectedNumber: 'Unexpected number', - UnexpectedString: 'Unexpected string', - UnexpectedIdentifier: 'Unexpected identifier', - UnexpectedReserved: 'Unexpected reserved word', - UnexpectedEOS: 'Unexpected end of input', - NewlineAfterThrow: 'Illegal newline after throw', - InvalidRegExp: 'Invalid regular expression', - UnterminatedRegExp: 'Invalid regular expression: missing /', - InvalidLHSInAssignment: 'Invalid left-hand side in assignment', - InvalidLHSInForIn: 'Invalid left-hand side in for-in', - MultipleDefaultsInSwitch: - 'More than one default clause in switch statement', - NoCatchOrFinally: 'Missing catch or finally after try', - UnknownLabel: "Undefined label '%0'", - Redeclaration: "%0 '%1' has already been declared", - IllegalContinue: 'Illegal continue statement', - IllegalBreak: 'Illegal break statement', - IllegalReturn: 'Illegal return statement', - StrictModeWith: 'Strict mode code may not include a with statement', - StrictCatchVariable: - 'Catch variable may not be eval or arguments in strict mode', - StrictVarName: - 'Variable name may not be eval or arguments in strict mode', - StrictParamName: - 'Parameter name eval or arguments is not allowed in strict mode', - StrictParamDupe: - 'Strict mode function may not have duplicate parameter names', - StrictFunctionName: - 'Function name may not be eval or arguments in strict mode', - StrictOctalLiteral: 'Octal literals are not allowed in strict mode.', - StrictDelete: 'Delete of an unqualified identifier in strict mode.', - StrictDuplicateProperty: - 'Duplicate data property in object literal not allowed in strict mode', - AccessorDataProperty: - 'Object literal may not have data and accessor property with the same name', - AccessorGetSet: - 'Object literal may not have multiple get/set accessors with the same name', - StrictLHSAssignment: - 'Assignment to eval or arguments is not allowed in strict mode', - StrictLHSPostfix: - 'Postfix increment/decrement may not have eval or arguments operand in strict mode', - StrictLHSPrefix: - 'Prefix increment/decrement may not have eval or arguments operand in strict mode', - StrictReservedWord: 'Use of future reserved word in strict mode', - }; - - // See also tools/generate-unicode-regex.py. - Regex = { - NonAsciiIdentifierStart: new RegExp( - '[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]' - ), - NonAsciiIdentifierPart: new RegExp( - '[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0\u08A2-\u08AC\u08E4-\u08FE\u0900-\u0963\u0966-\u096F\u0971-\u0977\u0979-\u097F\u0981-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C01-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C82\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D02\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F0\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191C\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1D00-\u1DE6\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA697\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7B\uAA80-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE26\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]' - ), - }; - - // Ensure the condition is true, otherwise throw an error. - // This is only to have a better contract semantic, i.e. another safety net - // to catch a logic error. The condition shall be fulfilled in normal case. - // Do NOT use this to enforce a certain condition on any user input. - - function assert(condition, message) { - /* istanbul ignore if */ - if (!condition) { - throw new Error('ASSERT: ' + message); - } - } - - function isDecimalDigit(ch) { - return ch >= 48 && ch <= 57; // 0..9 - } - - function isHexDigit(ch) { - return '0123456789abcdefABCDEF'.indexOf(ch) >= 0; - } - - function isOctalDigit(ch) { - return '01234567'.indexOf(ch) >= 0; - } - - // 7.2 White Space - - function isWhiteSpace(ch) { - return ( - ch === 0x20 || - ch === 0x09 || - ch === 0x0b || - ch === 0x0c || - ch === 0xa0 || - (ch >= 0x1680 && - [ - 0x1680, - 0x180e, - 0x2000, - 0x2001, - 0x2002, - 0x2003, - 0x2004, - 0x2005, - 0x2006, - 0x2007, - 0x2008, - 0x2009, - 0x200a, - 0x202f, - 0x205f, - 0x3000, - 0xfeff, - ].indexOf(ch) >= 0) - ); - } - - // 7.3 Line Terminators - - function isLineTerminator(ch) { - return ch === 0x0a || ch === 0x0d || ch === 0x2028 || ch === 0x2029; - } - - // 7.6 Identifier Names and Identifiers - - function isIdentifierStart(ch) { - return ( - ch === 0x24 || - ch === 0x5f || // $ (dollar) and _ (underscore) - (ch >= 0x41 && ch <= 0x5a) || // A..Z - (ch >= 0x61 && ch <= 0x7a) || // a..z - ch === 0x5c || // \ (backslash) - (ch >= 0x80 && - Regex.NonAsciiIdentifierStart.test(String.fromCharCode(ch))) - ); - } - - function isIdentifierPart(ch) { - return ( - ch === 0x24 || - ch === 0x5f || // $ (dollar) and _ (underscore) - (ch >= 0x41 && ch <= 0x5a) || // A..Z - (ch >= 0x61 && ch <= 0x7a) || // a..z - (ch >= 0x30 && ch <= 0x39) || // 0..9 - ch === 0x5c || // \ (backslash) - (ch >= 0x80 && - Regex.NonAsciiIdentifierPart.test(String.fromCharCode(ch))) - ); - } - - // 7.6.1.2 Future Reserved Words - - function isFutureReservedWord(id) { - switch (id) { - case 'class': - case 'enum': - case 'export': - case 'extends': - case 'import': - case 'super': - return true; - default: - return false; - } - } - - function isStrictModeReservedWord(id) { - switch (id) { - case 'implements': - case 'interface': - case 'package': - case 'private': - case 'protected': - case 'public': - case 'static': - case 'yield': - case 'let': - return true; - default: - return false; - } - } - - function isRestrictedWord(id) { - return id === 'eval' || id === 'arguments'; - } - - // 7.6.1.1 Keywords - - function isKeyword(id) { - if (strict && isStrictModeReservedWord(id)) { - return true; - } - - // 'const' is specialized as Keyword in V8. - // 'yield' and 'let' are for compatiblity with SpiderMonkey and ES.next. - // Some others are from future reserved words. - - switch (id.length) { - case 2: - return id === 'if' || id === 'in' || id === 'do'; - case 3: - return ( - id === 'var' || - id === 'for' || - id === 'new' || - id === 'try' || - id === 'let' - ); - case 4: - return ( - id === 'this' || - id === 'else' || - id === 'case' || - id === 'void' || - id === 'with' || - id === 'enum' - ); - case 5: - return ( - id === 'while' || - id === 'break' || - id === 'catch' || - id === 'throw' || - id === 'const' || - id === 'yield' || - id === 'class' || - id === 'super' - ); - case 6: - return ( - id === 'return' || - id === 'typeof' || - id === 'delete' || - id === 'switch' || - id === 'export' || - id === 'import' - ); - case 7: - return id === 'default' || id === 'finally' || id === 'extends'; - case 8: - return id === 'function' || id === 'continue' || id === 'debugger'; - case 10: - return id === 'instanceof'; - default: - return false; - } - } - - // 7.4 Comments - - function addComment(type, value, start, end, loc) { - var comment, attacher; - - assert(typeof start === 'number', 'Comment must have valid position'); - - // Because the way the actual token is scanned, often the comments - // (if any) are skipped twice during the lexical analysis. - // Thus, we need to skip adding a comment if the comment array already - // handled it. - if (state.lastCommentStart >= start) { - return; - } - state.lastCommentStart = start; - - comment = { - type: type, - value: value, - }; - if (extra.range) { - comment.range = [start, end]; - } - if (extra.loc) { - comment.loc = loc; - } - extra.comments.push(comment); - if (extra.attachComment) { - extra.leadingComments.push(comment); - extra.trailingComments.push(comment); - } - } - - function skipSingleLineComment(offset) { - var start, loc, ch, comment; - - start = index - offset; - loc = { - start: { - line: lineNumber, - column: index - lineStart - offset, - }, - }; - - while (index < length) { - ch = source.charCodeAt(index); - ++index; - if (isLineTerminator(ch)) { - if (extra.comments) { - comment = source.slice(start + offset, index - 1); - loc.end = { - line: lineNumber, - column: index - lineStart - 1, - }; - addComment('Line', comment, start, index - 1, loc); - } - if (ch === 13 && source.charCodeAt(index) === 10) { - ++index; - } - ++lineNumber; - lineStart = index; - return; - } - } - - if (extra.comments) { - comment = source.slice(start + offset, index); - loc.end = { - line: lineNumber, - column: index - lineStart, - }; - addComment('Line', comment, start, index, loc); - } - } - - function skipMultiLineComment() { - var start, loc, ch, comment; - - if (extra.comments) { - start = index - 2; - loc = { - start: { - line: lineNumber, - column: index - lineStart - 2, - }, - }; - } - - while (index < length) { - ch = source.charCodeAt(index); - if (isLineTerminator(ch)) { - if (ch === 0x0d && source.charCodeAt(index + 1) === 0x0a) { - ++index; - } - ++lineNumber; - ++index; - lineStart = index; - if (index >= length) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else if (ch === 0x2a) { - // Block comment ends with '*/'. - if (source.charCodeAt(index + 1) === 0x2f) { - ++index; - ++index; - if (extra.comments) { - comment = source.slice(start + 2, index - 2); - loc.end = { - line: lineNumber, - column: index - lineStart, - }; - addComment('Block', comment, start, index, loc); - } - return; - } - ++index; - } else { - ++index; - } - } - - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - function skipComment() { - var ch, start; - - start = index === 0; - while (index < length) { - ch = source.charCodeAt(index); - - if (isWhiteSpace(ch)) { - ++index; - } else if (isLineTerminator(ch)) { - ++index; - if (ch === 0x0d && source.charCodeAt(index) === 0x0a) { - ++index; - } - ++lineNumber; - lineStart = index; - start = true; - } else if (ch === 0x2f) { - // U+002F is '/' - ch = source.charCodeAt(index + 1); - if (ch === 0x2f) { - ++index; - ++index; - skipSingleLineComment(2); - start = true; - } else if (ch === 0x2a) { - // U+002A is '*' - ++index; - ++index; - skipMultiLineComment(); - } else { - break; - } - } else if (start && ch === 0x2d) { - // U+002D is '-' - // U+003E is '>' - if ( - source.charCodeAt(index + 1) === 0x2d && - source.charCodeAt(index + 2) === 0x3e - ) { - // '-->' is a single-line comment - index += 3; - skipSingleLineComment(3); - } else { - break; - } - } else if (ch === 0x3c) { - // U+003C is '<' - if (source.slice(index + 1, index + 4) === '!--') { - ++index; // `<` - ++index; // `!` - ++index; // `-` - ++index; // `-` - skipSingleLineComment(4); - } else { - break; - } - } else { - break; - } - } - } - - function scanHexEscape(prefix) { - var i, - len, - ch, - code = 0; - - len = prefix === 'u' ? 4 : 2; - for (i = 0; i < len; ++i) { - if (index < length && isHexDigit(source[index])) { - ch = source[index++]; - code = code * 16 + '0123456789abcdef'.indexOf(ch.toLowerCase()); - } else { - return ''; - } - } - return String.fromCharCode(code); - } - - function getEscapedIdentifier() { - var ch, id; - - ch = source.charCodeAt(index++); - id = String.fromCharCode(ch); - - // '\u' (U+005C, U+0075) denotes an escaped character. - if (ch === 0x5c) { - if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - ++index; - ch = scanHexEscape('u'); - if (!ch || ch === '\\' || !isIdentifierStart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - id = ch; - } - - while (index < length) { - ch = source.charCodeAt(index); - if (!isIdentifierPart(ch)) { - break; - } - ++index; - id += String.fromCharCode(ch); - - // '\u' (U+005C, U+0075) denotes an escaped character. - if (ch === 0x5c) { - id = id.substr(0, id.length - 1); - if (source.charCodeAt(index) !== 0x75) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - ++index; - ch = scanHexEscape('u'); - if (!ch || ch === '\\' || !isIdentifierPart(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - id += ch; - } - } - - return id; - } - - function getIdentifier() { - var start, ch; - - start = index++; - while (index < length) { - ch = source.charCodeAt(index); - if (ch === 0x5c) { - // Blackslash (U+005C) marks Unicode escape sequence. - index = start; - return getEscapedIdentifier(); - } - if (isIdentifierPart(ch)) { - ++index; - } else { - break; - } - } - - return source.slice(start, index); - } - - function scanIdentifier() { - var start, id, type; - - start = index; - - // Backslash (U+005C) starts an escaped character. - id = - source.charCodeAt(index) === 0x5c - ? getEscapedIdentifier() - : getIdentifier(); - - // There is no keyword or literal with only one character. - // Thus, it must be an identifier. - if (id.length === 1) { - type = Token.Identifier; - } else if (isKeyword(id)) { - type = Token.Keyword; - } else if (id === 'null') { - type = Token.NullLiteral; - } else if (id === 'true' || id === 'false') { - type = Token.BooleanLiteral; - } else { - type = Token.Identifier; - } - - return { - type: type, - value: id, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - // 7.7 Punctuators - - function scanPunctuator() { - var start = index, - code = source.charCodeAt(index), - code2, - ch1 = source[index], - ch2, - ch3, - ch4; - - switch (code) { - // Check for most common single-character punctuators. - case 0x2e: // . dot - case 0x28: // ( open bracket - case 0x29: // ) close bracket - case 0x3b: // ; semicolon - case 0x2c: // , comma - case 0x7b: // { open curly brace - case 0x7d: // } close curly brace - case 0x5b: // [ - case 0x5d: // ] - case 0x3a: // : - case 0x3f: // ? - case 0x7e: // ~ - ++index; - if (extra.tokenize) { - if (code === 0x28) { - extra.openParenToken = extra.tokens.length; - } else if (code === 0x7b) { - extra.openCurlyToken = extra.tokens.length; - } - } - return { - type: Token.Punctuator, - value: String.fromCharCode(code), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - - default: - code2 = source.charCodeAt(index + 1); - - // '=' (U+003D) marks an assignment or comparison operator. - if (code2 === 0x3d) { - switch (code) { - case 0x2b: // + - case 0x2d: // - - case 0x2f: // / - case 0x3c: // < - case 0x3e: // > - case 0x5e: // ^ - case 0x7c: // | - case 0x25: // % - case 0x26: // & - case 0x2a: // * - index += 2; - return { - type: Token.Punctuator, - value: String.fromCharCode(code) + String.fromCharCode(code2), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - - case 0x21: // ! - case 0x3d: // = - index += 2; - - // !== and === - if (source.charCodeAt(index) === 0x3d) { - ++index; - } - return { - type: Token.Punctuator, - value: source.slice(start, index), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - } - } - - // 4-character punctuator: >>>= - - ch4 = source.substr(index, 4); - - if (ch4 === '>>>=') { - index += 4; - return { - type: Token.Punctuator, - value: ch4, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - // 3-character punctuators: === !== >>> <<= >>= - - ch3 = ch4.substr(0, 3); - - if (ch3 === '>>>' || ch3 === '<<=' || ch3 === '>>=') { - index += 3; - return { - type: Token.Punctuator, - value: ch3, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - // Other 2-character punctuators: ++ -- << >> && || - ch2 = ch3.substr(0, 2); - - if ((ch1 === ch2[1] && '+-<>&|'.indexOf(ch1) >= 0) || ch2 === '=>') { - index += 2; - return { - type: Token.Punctuator, - value: ch2, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - // 1-character punctuators: < > = ! + - * % & | ^ / - if ('<>=!+-*%&|^/'.indexOf(ch1) >= 0) { - ++index; - return { - type: Token.Punctuator, - value: ch1, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - // 7.8.3 Numeric Literals - - function scanHexLiteral(start) { - var number = ''; - - while (index < length) { - if (!isHexDigit(source[index])) { - break; - } - number += source[index++]; - } - - if (number.length === 0) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.NumericLiteral, - value: parseInt('0x' + number, 16), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - function scanOctalLiteral(start) { - var number = '0' + source[index++]; - while (index < length) { - if (!isOctalDigit(source[index])) { - break; - } - number += source[index++]; - } - - if ( - isIdentifierStart(source.charCodeAt(index)) || - isDecimalDigit(source.charCodeAt(index)) - ) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.NumericLiteral, - value: parseInt(number, 8), - octal: true, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - function scanNumericLiteral() { - var number, start, ch; - - ch = source[index]; - assert( - isDecimalDigit(ch.charCodeAt(0)) || ch === '.', - 'Numeric literal must start with a decimal digit or a decimal point' - ); - - start = index; - number = ''; - if (ch !== '.') { - number = source[index++]; - ch = source[index]; - - // Hex number starts with '0x'. - // Octal number starts with '0'. - if (number === '0') { - if (ch === 'x' || ch === 'X') { - ++index; - return scanHexLiteral(start); - } - if (isOctalDigit(ch)) { - return scanOctalLiteral(start); - } - - // decimal number starts with '0' such as '09' is illegal. - if (ch && isDecimalDigit(ch.charCodeAt(0))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - ch = source[index]; - } - - if (ch === '.') { - number += source[index++]; - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - ch = source[index]; - } - - if (ch === 'e' || ch === 'E') { - number += source[index++]; - - ch = source[index]; - if (ch === '+' || ch === '-') { - number += source[index++]; - } - if (isDecimalDigit(source.charCodeAt(index))) { - while (isDecimalDigit(source.charCodeAt(index))) { - number += source[index++]; - } - } else { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } - - if (isIdentifierStart(source.charCodeAt(index))) { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.NumericLiteral, - value: parseFloat(number), - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - // 7.8.4 String Literals - - function scanStringLiteral() { - var str = '', - quote, - start, - ch, - code, - unescaped, - restore, - octal = false, - startLineNumber, - startLineStart; - startLineNumber = lineNumber; - startLineStart = lineStart; - - quote = source[index]; - assert( - quote === "'" || quote === '"', - 'String literal must starts with a quote' - ); - - start = index; - ++index; - - while (index < length) { - ch = source[index++]; - - if (ch === quote) { - quote = ''; - break; - } else if (ch === '\\') { - ch = source[index++]; - if (!ch || !isLineTerminator(ch.charCodeAt(0))) { - switch (ch) { - case 'u': - case 'x': - restore = index; - unescaped = scanHexEscape(ch); - if (unescaped) { - str += unescaped; - } else { - index = restore; - str += ch; - } - break; - case 'n': - str += '\n'; - break; - case 'r': - str += '\r'; - break; - case 't': - str += '\t'; - break; - case 'b': - str += '\b'; - break; - case 'f': - str += '\f'; - break; - case 'v': - str += '\x0B'; - break; - - default: - if (isOctalDigit(ch)) { - code = '01234567'.indexOf(ch); - - // \0 is not octal escape sequence - if (code !== 0) { - octal = true; - } - - if (index < length && isOctalDigit(source[index])) { - octal = true; - code = code * 8 + '01234567'.indexOf(source[index++]); - - // 3 digits are only allowed when string starts - // with 0, 1, 2, 3 - if ( - '0123'.indexOf(ch) >= 0 && - index < length && - isOctalDigit(source[index]) - ) { - code = code * 8 + '01234567'.indexOf(source[index++]); - } - } - str += String.fromCharCode(code); - } else { - str += ch; - } - break; - } - } else { - ++lineNumber; - if (ch === '\r' && source[index] === '\n') { - ++index; - } - lineStart = index; - } - } else if (isLineTerminator(ch.charCodeAt(0))) { - break; - } else { - str += ch; - } - } - - if (quote !== '') { - throwError({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - - return { - type: Token.StringLiteral, - value: str, - octal: octal, - startLineNumber: startLineNumber, - startLineStart: startLineStart, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - function testRegExp(pattern, flags) { - var value; - try { - value = new RegExp(pattern, flags); - } catch (e) { - throwError({}, Messages.InvalidRegExp); - } - return value; - } - - function scanRegExpBody() { - var ch, str, classMarker, terminated, body; - - ch = source[index]; - assert(ch === '/', 'Regular expression literal must start with a slash'); - str = source[index++]; - - classMarker = false; - terminated = false; - while (index < length) { - ch = source[index++]; - str += ch; - if (ch === '\\') { - ch = source[index++]; - // ECMA-262 7.8.5 - if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); - } - str += ch; - } else if (isLineTerminator(ch.charCodeAt(0))) { - throwError({}, Messages.UnterminatedRegExp); - } else if (classMarker) { - if (ch === ']') { - classMarker = false; - } - } else { - if (ch === '/') { - terminated = true; - break; - } else if (ch === '[') { - classMarker = true; - } - } - } - - if (!terminated) { - throwError({}, Messages.UnterminatedRegExp); - } - - // Exclude leading and trailing slash. - body = str.substr(1, str.length - 2); - return { - value: body, - literal: str, - }; - } - - function scanRegExpFlags() { - var ch, str, flags, restore; - - str = ''; - flags = ''; - while (index < length) { - ch = source[index]; - if (!isIdentifierPart(ch.charCodeAt(0))) { - break; - } - - ++index; - if (ch === '\\' && index < length) { - ch = source[index]; - if (ch === 'u') { - ++index; - restore = index; - ch = scanHexEscape('u'); - if (ch) { - flags += ch; - for (str += '\\u'; restore < index; ++restore) { - str += source[restore]; - } - } else { - index = restore; - flags += 'u'; - str += '\\u'; - } - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); - } else { - str += '\\'; - throwErrorTolerant({}, Messages.UnexpectedToken, 'ILLEGAL'); - } - } else { - flags += ch; - str += ch; - } - } - - return { - value: flags, - literal: str, - }; - } - - function scanRegExp() { - var start, body, flags, pattern, value; - - lookahead = null; - skipComment(); - start = index; - - body = scanRegExpBody(); - flags = scanRegExpFlags(); - value = testRegExp(body.value, flags.value); - - if (extra.tokenize) { - return { - type: Token.RegularExpression, - value: value, - lineNumber: lineNumber, - lineStart: lineStart, - start: start, - end: index, - }; - } - - return { - literal: body.literal + flags.literal, - value: value, - start: start, - end: index, - }; - } - - function collectRegex() { - var pos, loc, regex, token; - - skipComment(); - - pos = index; - loc = { - start: { - line: lineNumber, - column: index - lineStart, - }, - }; - - regex = scanRegExp(); - loc.end = { - line: lineNumber, - column: index - lineStart, - }; - - /* istanbul ignore next */ - if (!extra.tokenize) { - // Pop the previous token, which is likely '/' or '/=' - if (extra.tokens.length > 0) { - token = extra.tokens[extra.tokens.length - 1]; - if (token.range[0] === pos && token.type === 'Punctuator') { - if (token.value === '/' || token.value === '/=') { - extra.tokens.pop(); - } - } - } - - extra.tokens.push({ - type: 'RegularExpression', - value: regex.literal, - range: [pos, index], - loc: loc, - }); - } - - return regex; - } - - function isIdentifierName(token) { - return ( - token.type === Token.Identifier || - token.type === Token.Keyword || - token.type === Token.BooleanLiteral || - token.type === Token.NullLiteral - ); - } - - function advanceSlash() { - var prevToken, checkToken; - // Using the following algorithm: - // https://github.com/mozilla/sweet.js/wiki/design - prevToken = extra.tokens[extra.tokens.length - 1]; - if (!prevToken) { - // Nothing before that: it cannot be a division. - return collectRegex(); - } - if (prevToken.type === 'Punctuator') { - if (prevToken.value === ']') { - return scanPunctuator(); - } - if (prevToken.value === ')') { - checkToken = extra.tokens[extra.openParenToken - 1]; - if ( - checkToken && - checkToken.type === 'Keyword' && - (checkToken.value === 'if' || - checkToken.value === 'while' || - checkToken.value === 'for' || - checkToken.value === 'with') - ) { - return collectRegex(); - } - return scanPunctuator(); - } - if (prevToken.value === '}') { - // Dividing a function by anything makes little sense, - // but we have to check for that. - if ( - extra.tokens[extra.openCurlyToken - 3] && - extra.tokens[extra.openCurlyToken - 3].type === 'Keyword' - ) { - // Anonymous function. - checkToken = extra.tokens[extra.openCurlyToken - 4]; - if (!checkToken) { - return scanPunctuator(); - } - } else if ( - extra.tokens[extra.openCurlyToken - 4] && - extra.tokens[extra.openCurlyToken - 4].type === 'Keyword' - ) { - // Named function. - checkToken = extra.tokens[extra.openCurlyToken - 5]; - if (!checkToken) { - return collectRegex(); - } - } else { - return scanPunctuator(); - } - // checkToken determines whether the function is - // a declaration or an expression. - if (FnExprTokens.indexOf(checkToken.value) >= 0) { - // It is an expression. - return scanPunctuator(); - } - // It is a declaration. - return collectRegex(); - } - return collectRegex(); - } - if (prevToken.type === 'Keyword') { - return collectRegex(); - } - return scanPunctuator(); - } - - function advance() { - var ch; - - skipComment(); - - if (index >= length) { - return { - type: Token.EOF, - lineNumber: lineNumber, - lineStart: lineStart, - start: index, - end: index, - }; - } - - ch = source.charCodeAt(index); - - if (isIdentifierStart(ch)) { - return scanIdentifier(); - } - - // Very common: ( and ) and ; - if (ch === 0x28 || ch === 0x29 || ch === 0x3b) { - return scanPunctuator(); - } - - // String literal starts with single quote (U+0027) or double quote (U+0022). - if (ch === 0x27 || ch === 0x22) { - return scanStringLiteral(); - } - - // Dot (.) U+002E can also start a floating-point number, hence the need - // to check the next character. - if (ch === 0x2e) { - if (isDecimalDigit(source.charCodeAt(index + 1))) { - return scanNumericLiteral(); - } - return scanPunctuator(); - } - - if (isDecimalDigit(ch)) { - return scanNumericLiteral(); - } - - // Slash (/) U+002F can also start a regex. - if (extra.tokenize && ch === 0x2f) { - return advanceSlash(); - } - - return scanPunctuator(); - } - - function collectToken() { - var loc, token, range, value; - - skipComment(); - loc = { - start: { - line: lineNumber, - column: index - lineStart, - }, - }; - - token = advance(); - loc.end = { - line: lineNumber, - column: index - lineStart, - }; - - if (token.type !== Token.EOF) { - value = source.slice(token.start, token.end); - extra.tokens.push({ - type: TokenName[token.type], - value: value, - range: [token.start, token.end], - loc: loc, - }); - } - - return token; - } - - function lex() { - var token; - - token = lookahead; - index = token.end; - lineNumber = token.lineNumber; - lineStart = token.lineStart; - - lookahead = - typeof extra.tokens !== 'undefined' ? collectToken() : advance(); - - index = token.end; - lineNumber = token.lineNumber; - lineStart = token.lineStart; - - return token; - } - - function peek() { - var pos, line, start; - - pos = index; - line = lineNumber; - start = lineStart; - lookahead = - typeof extra.tokens !== 'undefined' ? collectToken() : advance(); - index = pos; - lineNumber = line; - lineStart = start; - } - - function Position(line, column) { - this.line = line; - this.column = column; - } - - function SourceLocation(startLine, startColumn, line, column) { - this.start = new Position(startLine, startColumn); - this.end = new Position(line, column); - } - - SyntaxTreeDelegate = { - name: 'SyntaxTree', - - processComment: function(node) { - var lastChild, trailingComments; - - if (node.type === Syntax.Program) { - if (node.body.length > 0) { - return; - } - } - - if (extra.trailingComments.length > 0) { - if (extra.trailingComments[0].range[0] >= node.range[1]) { - trailingComments = extra.trailingComments; - extra.trailingComments = []; - } else { - extra.trailingComments.length = 0; - } - } else { - if ( - extra.bottomRightStack.length > 0 && - extra.bottomRightStack[extra.bottomRightStack.length - 1] - .trailingComments && - extra.bottomRightStack[extra.bottomRightStack.length - 1] - .trailingComments[0].range[0] >= node.range[1] - ) { - trailingComments = - extra.bottomRightStack[extra.bottomRightStack.length - 1] - .trailingComments; - delete extra.bottomRightStack[extra.bottomRightStack.length - 1] - .trailingComments; - } - } - - // Eating the stack. - while ( - extra.bottomRightStack.length > 0 && - extra.bottomRightStack[extra.bottomRightStack.length - 1].range[0] >= - node.range[0] - ) { - lastChild = extra.bottomRightStack.pop(); - } - - if (lastChild) { - if ( - lastChild.leadingComments && - lastChild.leadingComments[lastChild.leadingComments.length - 1] - .range[1] <= node.range[0] - ) { - node.leadingComments = lastChild.leadingComments; - delete lastChild.leadingComments; - } - } else if ( - extra.leadingComments.length > 0 && - extra.leadingComments[extra.leadingComments.length - 1].range[1] <= - node.range[0] - ) { - node.leadingComments = extra.leadingComments; - extra.leadingComments = []; - } - - if (trailingComments) { - node.trailingComments = trailingComments; - } - - extra.bottomRightStack.push(node); - }, - - markEnd: function(node, startToken) { - if (extra.range) { - node.range = [startToken.start, index]; - } - if (extra.loc) { - node.loc = new SourceLocation( - startToken.startLineNumber === undefined - ? startToken.lineNumber - : startToken.startLineNumber, - startToken.start - - (startToken.startLineStart === undefined - ? startToken.lineStart - : startToken.startLineStart), - lineNumber, - index - lineStart - ); - this.postProcess(node); - } - - if (extra.attachComment) { - this.processComment(node); - } - return node; - }, - - postProcess: function(node) { - if (extra.source) { - node.loc.source = extra.source; - } - return node; - }, - - createArrayExpression: function(elements) { - return { - type: Syntax.ArrayExpression, - elements: elements, - }; - }, - - createAssignmentExpression: function(operator, left, right) { - return { - type: Syntax.AssignmentExpression, - operator: operator, - left: left, - right: right, - }; - }, - - createBinaryExpression: function(operator, left, right) { - var type = - operator === '||' || operator === '&&' - ? Syntax.LogicalExpression - : Syntax.BinaryExpression; - return { - type: type, - operator: operator, - left: left, - right: right, - }; - }, - - createBlockStatement: function(body) { - return { - type: Syntax.BlockStatement, - body: body, - }; - }, - - createBreakStatement: function(label) { - return { - type: Syntax.BreakStatement, - label: label, - }; - }, - - createCallExpression: function(callee, args) { - return { - type: Syntax.CallExpression, - callee: callee, - arguments: args, - }; - }, - - createCatchClause: function(param, body) { - return { - type: Syntax.CatchClause, - param: param, - body: body, - }; - }, - - createConditionalExpression: function(test, consequent, alternate) { - return { - type: Syntax.ConditionalExpression, - test: test, - consequent: consequent, - alternate: alternate, - }; - }, - - createContinueStatement: function(label) { - return { - type: Syntax.ContinueStatement, - label: label, - }; - }, - - createDebuggerStatement: function() { - return { - type: Syntax.DebuggerStatement, - }; - }, - - createDoWhileStatement: function(body, test) { - return { - type: Syntax.DoWhileStatement, - body: body, - test: test, - }; - }, - - createEmptyStatement: function() { - return { - type: Syntax.EmptyStatement, - }; - }, - - createExpressionStatement: function(expression) { - return { - type: Syntax.ExpressionStatement, - expression: expression, - }; - }, - - createForStatement: function(init, test, update, body) { - return { - type: Syntax.ForStatement, - init: init, - test: test, - update: update, - body: body, - }; - }, - - createForInStatement: function(left, right, body) { - return { - type: Syntax.ForInStatement, - left: left, - right: right, - body: body, - each: false, - }; - }, - - createFunctionDeclaration: function(id, params, defaults, body) { - return { - type: Syntax.FunctionDeclaration, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false, - }; - }, - - createFunctionExpression: function(id, params, defaults, body) { - return { - type: Syntax.FunctionExpression, - id: id, - params: params, - defaults: defaults, - body: body, - rest: null, - generator: false, - expression: false, - }; - }, - - createIdentifier: function(name) { - return { - type: Syntax.Identifier, - name: name, - }; - }, - - createIfStatement: function(test, consequent, alternate) { - return { - type: Syntax.IfStatement, - test: test, - consequent: consequent, - alternate: alternate, - }; - }, - - createLabeledStatement: function(label, body) { - return { - type: Syntax.LabeledStatement, - label: label, - body: body, - }; - }, - - createLiteral: function(token) { - return { - type: Syntax.Literal, - value: token.value, - raw: source.slice(token.start, token.end), - }; - }, - - createMemberExpression: function(accessor, object, property) { - return { - type: Syntax.MemberExpression, - computed: accessor === '[', - object: object, - property: property, - }; - }, - - createNewExpression: function(callee, args) { - return { - type: Syntax.NewExpression, - callee: callee, - arguments: args, - }; - }, - - createObjectExpression: function(properties) { - return { - type: Syntax.ObjectExpression, - properties: properties, - }; - }, - - createPostfixExpression: function(operator, argument) { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: false, - }; - }, - - createProgram: function(body) { - return { - type: Syntax.Program, - body: body, - }; - }, - - createProperty: function(kind, key, value) { - return { - type: Syntax.Property, - key: key, - value: value, - kind: kind, - }; - }, - - createReturnStatement: function(argument) { - return { - type: Syntax.ReturnStatement, - argument: argument, - }; - }, - - createSequenceExpression: function(expressions) { - return { - type: Syntax.SequenceExpression, - expressions: expressions, - }; - }, - - createSwitchCase: function(test, consequent) { - return { - type: Syntax.SwitchCase, - test: test, - consequent: consequent, - }; - }, - - createSwitchStatement: function(discriminant, cases) { - return { - type: Syntax.SwitchStatement, - discriminant: discriminant, - cases: cases, - }; - }, - - createThisExpression: function() { - return { - type: Syntax.ThisExpression, - }; - }, - - createThrowStatement: function(argument) { - return { - type: Syntax.ThrowStatement, - argument: argument, - }; - }, - - createTryStatement: function( - block, - guardedHandlers, - handlers, - finalizer - ) { - return { - type: Syntax.TryStatement, - block: block, - guardedHandlers: guardedHandlers, - handlers: handlers, - finalizer: finalizer, - }; - }, - - createUnaryExpression: function(operator, argument) { - if (operator === '++' || operator === '--') { - return { - type: Syntax.UpdateExpression, - operator: operator, - argument: argument, - prefix: true, - }; - } - return { - type: Syntax.UnaryExpression, - operator: operator, - argument: argument, - prefix: true, - }; - }, - - createVariableDeclaration: function(declarations, kind) { - return { - type: Syntax.VariableDeclaration, - declarations: declarations, - kind: kind, - }; - }, - - createVariableDeclarator: function(id, init) { - return { - type: Syntax.VariableDeclarator, - id: id, - init: init, - }; - }, - - createWhileStatement: function(test, body) { - return { - type: Syntax.WhileStatement, - test: test, - body: body, - }; - }, - - createWithStatement: function(object, body) { - return { - type: Syntax.WithStatement, - object: object, - body: body, - }; - }, - }; - - // Return true if there is a line terminator before the next token. - - function peekLineTerminator() { - var pos, line, start, found; - - pos = index; - line = lineNumber; - start = lineStart; - skipComment(); - found = lineNumber !== line; - index = pos; - lineNumber = line; - lineStart = start; - - return found; - } - - // Throw an exception - - function throwError(token, messageFormat) { - var error, - args = Array.prototype.slice.call(arguments, 2), - msg = messageFormat.replace(/%(\d)/g, function(whole, index) { - assert(index < args.length, 'Message reference must be in range'); - return args[index]; - }); - - if (typeof token.lineNumber === 'number') { - error = new Error('Line ' + token.lineNumber + ': ' + msg); - error.index = token.start; - error.lineNumber = token.lineNumber; - error.column = token.start - lineStart + 1; - } else { - error = new Error('Line ' + lineNumber + ': ' + msg); - error.index = index; - error.lineNumber = lineNumber; - error.column = index - lineStart + 1; - } - - error.description = msg; - throw error; - } - - function throwErrorTolerant() { - try { - throwError.apply(null, arguments); - } catch (e) { - if (extra.errors) { - extra.errors.push(e); - } else { - throw e; - } - } - } - - // Throw an exception because of the token. - - function throwUnexpected(token) { - if (token.type === Token.EOF) { - throwError(token, Messages.UnexpectedEOS); - } - - if (token.type === Token.NumericLiteral) { - throwError(token, Messages.UnexpectedNumber); - } - - if (token.type === Token.StringLiteral) { - throwError(token, Messages.UnexpectedString); - } - - if (token.type === Token.Identifier) { - throwError(token, Messages.UnexpectedIdentifier); - } - - if (token.type === Token.Keyword) { - if (isFutureReservedWord(token.value)) { - throwError(token, Messages.UnexpectedReserved); - } else if (strict && isStrictModeReservedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictReservedWord); - return; - } - throwError(token, Messages.UnexpectedToken, token.value); - } - - // BooleanLiteral, NullLiteral, or Punctuator. - throwError(token, Messages.UnexpectedToken, token.value); - } - - // Expect the next token to match the specified punctuator. - // If not, an exception will be thrown. - - function expect(value) { - var token = lex(); - if (token.type !== Token.Punctuator || token.value !== value) { - throwUnexpected(token); - } - } - - // Expect the next token to match the specified keyword. - // If not, an exception will be thrown. - - function expectKeyword(keyword) { - var token = lex(); - if (token.type !== Token.Keyword || token.value !== keyword) { - throwUnexpected(token); - } - } - - // Return true if the next token matches the specified punctuator. - - function match(value) { - return lookahead.type === Token.Punctuator && lookahead.value === value; - } - - // Return true if the next token matches the specified keyword - - function matchKeyword(keyword) { - return lookahead.type === Token.Keyword && lookahead.value === keyword; - } - - // Return true if the next token is an assignment operator - - function matchAssign() { - var op; - - if (lookahead.type !== Token.Punctuator) { - return false; - } - op = lookahead.value; - return ( - op === '=' || - op === '*=' || - op === '/=' || - op === '%=' || - op === '+=' || - op === '-=' || - op === '<<=' || - op === '>>=' || - op === '>>>=' || - op === '&=' || - op === '^=' || - op === '|=' - ); - } - - function consumeSemicolon() { - var line; - - // Catch the very common case first: immediately a semicolon (U+003B). - if (source.charCodeAt(index) === 0x3b || match(';')) { - lex(); - return; - } - - line = lineNumber; - skipComment(); - if (lineNumber !== line) { - return; - } - - if (lookahead.type !== Token.EOF && !match('}')) { - throwUnexpected(lookahead); - } - } - - // Return true if provided expression is LeftHandSideExpression - - function isLeftHandSide(expr) { - return ( - expr.type === Syntax.Identifier || expr.type === Syntax.MemberExpression - ); - } - - // 11.1.4 Array Initialiser - - function parseArrayInitialiser() { - var elements = [], - startToken; - - startToken = lookahead; - expect('['); - - while (!match(']')) { - if (match(',')) { - lex(); - elements.push(null); - } else { - elements.push(parseAssignmentExpression()); - - if (!match(']')) { - expect(','); - } - } - } - - lex(); - - return delegate.markEnd( - delegate.createArrayExpression(elements), - startToken - ); - } - - // 11.1.5 Object Initialiser - - function parsePropertyFunction(param, first) { - var previousStrict, body, startToken; - - previousStrict = strict; - startToken = lookahead; - body = parseFunctionSourceElements(); - if (first && strict && isRestrictedWord(param[0].name)) { - throwErrorTolerant(first, Messages.StrictParamName); - } - strict = previousStrict; - return delegate.markEnd( - delegate.createFunctionExpression(null, param, [], body), - startToken - ); - } - - function parseObjectPropertyKey() { - var token, startToken; - - startToken = lookahead; - token = lex(); - - // Note: This function is called only from parseObjectProperty(), where - // EOF and Punctuator tokens are already filtered out. - - if ( - token.type === Token.StringLiteral || - token.type === Token.NumericLiteral - ) { - if (strict && token.octal) { - throwErrorTolerant(token, Messages.StrictOctalLiteral); - } - return delegate.markEnd(delegate.createLiteral(token), startToken); - } - - return delegate.markEnd( - delegate.createIdentifier(token.value), - startToken - ); - } - - function parseObjectProperty() { - var token, key, id, value, param, startToken; - - token = lookahead; - startToken = lookahead; - - if (token.type === Token.Identifier) { - id = parseObjectPropertyKey(); - - // Property Assignment: Getter and Setter. - - if (token.value === 'get' && !match(':')) { - key = parseObjectPropertyKey(); - expect('('); - expect(')'); - value = parsePropertyFunction([]); - return delegate.markEnd( - delegate.createProperty('get', key, value), - startToken - ); - } - if (token.value === 'set' && !match(':')) { - key = parseObjectPropertyKey(); - expect('('); - token = lookahead; - if (token.type !== Token.Identifier) { - expect(')'); - throwErrorTolerant(token, Messages.UnexpectedToken, token.value); - value = parsePropertyFunction([]); - } else { - param = [parseVariableIdentifier()]; - expect(')'); - value = parsePropertyFunction(param, token); - } - return delegate.markEnd( - delegate.createProperty('set', key, value), - startToken - ); - } - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd( - delegate.createProperty('init', id, value), - startToken - ); - } - if (token.type === Token.EOF || token.type === Token.Punctuator) { - throwUnexpected(token); - } else { - key = parseObjectPropertyKey(); - expect(':'); - value = parseAssignmentExpression(); - return delegate.markEnd( - delegate.createProperty('init', key, value), - startToken - ); - } - } - - function parseObjectInitialiser() { - var properties = [], - property, - name, - key, - kind, - map = {}, - toString = String, - startToken; - - startToken = lookahead; - - expect('{'); - - while (!match('}')) { - property = parseObjectProperty(); - - if (property.key.type === Syntax.Identifier) { - name = property.key.name; - } else { - name = toString(property.key.value); - } - kind = - property.kind === 'init' - ? PropertyKind.Data - : property.kind === 'get' - ? PropertyKind.Get - : PropertyKind.Set; - - key = '$' + name; - if (Object.prototype.hasOwnProperty.call(map, key)) { - if (map[key] === PropertyKind.Data) { - if (strict && kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.StrictDuplicateProperty); - } else if (kind !== PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); - } - } else { - if (kind === PropertyKind.Data) { - throwErrorTolerant({}, Messages.AccessorDataProperty); - } else if (map[key] & kind) { - throwErrorTolerant({}, Messages.AccessorGetSet); - } - } - map[key] |= kind; - } else { - map[key] = kind; - } - - properties.push(property); - - if (!match('}')) { - expect(','); - } - } - - expect('}'); - - return delegate.markEnd( - delegate.createObjectExpression(properties), - startToken - ); - } - - // 11.1.6 The Grouping Operator - - function parseGroupExpression() { - var expr; - - expect('('); - - expr = parseExpression(); - - expect(')'); - - return expr; - } - - // 11.1 Primary Expressions - - function parsePrimaryExpression() { - var type, token, expr, startToken; - - if (match('(')) { - return parseGroupExpression(); - } - - if (match('[')) { - return parseArrayInitialiser(); - } - - if (match('{')) { - return parseObjectInitialiser(); - } - - type = lookahead.type; - startToken = lookahead; - - if (type === Token.Identifier) { - expr = delegate.createIdentifier(lex().value); - } else if ( - type === Token.StringLiteral || - type === Token.NumericLiteral - ) { - if (strict && lookahead.octal) { - throwErrorTolerant(lookahead, Messages.StrictOctalLiteral); - } - expr = delegate.createLiteral(lex()); - } else if (type === Token.Keyword) { - if (matchKeyword('function')) { - return parseFunctionExpression(); - } - if (matchKeyword('this')) { - lex(); - expr = delegate.createThisExpression(); - } else { - throwUnexpected(lex()); - } - } else if (type === Token.BooleanLiteral) { - token = lex(); - token.value = token.value === 'true'; - expr = delegate.createLiteral(token); - } else if (type === Token.NullLiteral) { - token = lex(); - token.value = null; - expr = delegate.createLiteral(token); - } else if (match('/') || match('/=')) { - if (typeof extra.tokens !== 'undefined') { - expr = delegate.createLiteral(collectRegex()); - } else { - expr = delegate.createLiteral(scanRegExp()); - } - peek(); - } else { - throwUnexpected(lex()); - } - - return delegate.markEnd(expr, startToken); - } - - // 11.2 Left-Hand-Side Expressions - - function parseArguments() { - var args = []; - - expect('('); - - if (!match(')')) { - while (index < length) { - args.push(parseAssignmentExpression()); - if (match(')')) { - break; - } - expect(','); - } - } - - expect(')'); - - return args; - } - - function parseNonComputedProperty() { - var token, startToken; - - startToken = lookahead; - token = lex(); - - if (!isIdentifierName(token)) { - throwUnexpected(token); - } - - return delegate.markEnd( - delegate.createIdentifier(token.value), - startToken - ); - } - - function parseNonComputedMember() { - expect('.'); - - return parseNonComputedProperty(); - } - - function parseComputedMember() { - var expr; - - expect('['); - - expr = parseExpression(); - - expect(']'); - - return expr; - } - - function parseNewExpression() { - var callee, args, startToken; - - startToken = lookahead; - expectKeyword('new'); - callee = parseLeftHandSideExpression(); - args = match('(') ? parseArguments() : []; - - return delegate.markEnd( - delegate.createNewExpression(callee, args), - startToken - ); - } - - function parseLeftHandSideExpressionAllowCall() { - var previousAllowIn, expr, args, property, startToken; - - startToken = lookahead; - - previousAllowIn = state.allowIn; - state.allowIn = true; - expr = matchKeyword('new') - ? parseNewExpression() - : parsePrimaryExpression(); - state.allowIn = previousAllowIn; - - for (;;) { - if (match('.')) { - property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); - } else if (match('(')) { - args = parseArguments(); - expr = delegate.createCallExpression(expr, args); - } else if (match('[')) { - property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); - } else { - break; - } - delegate.markEnd(expr, startToken); - } - - return expr; - } - - function parseLeftHandSideExpression() { - var previousAllowIn, expr, property, startToken; - - startToken = lookahead; - - previousAllowIn = state.allowIn; - expr = matchKeyword('new') - ? parseNewExpression() - : parsePrimaryExpression(); - state.allowIn = previousAllowIn; - - while (match('.') || match('[')) { - if (match('[')) { - property = parseComputedMember(); - expr = delegate.createMemberExpression('[', expr, property); - } else { - property = parseNonComputedMember(); - expr = delegate.createMemberExpression('.', expr, property); - } - delegate.markEnd(expr, startToken); - } - - return expr; - } - - // 11.3 Postfix Expressions - - function parsePostfixExpression() { - var expr, - token, - startToken = lookahead; - - expr = parseLeftHandSideExpressionAllowCall(); - - if (lookahead.type === Token.Punctuator) { - if ((match('++') || match('--')) && !peekLineTerminator()) { - // 11.3.1, 11.3.2 - if ( - strict && - expr.type === Syntax.Identifier && - isRestrictedWord(expr.name) - ) { - throwErrorTolerant({}, Messages.StrictLHSPostfix); - } - - if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } - - token = lex(); - expr = delegate.markEnd( - delegate.createPostfixExpression(token.value, expr), - startToken - ); - } - } - - return expr; - } - - // 11.4 Unary Operators - - function parseUnaryExpression() { - var token, expr, startToken; - - if ( - lookahead.type !== Token.Punctuator && - lookahead.type !== Token.Keyword - ) { - expr = parsePostfixExpression(); - } else if (match('++') || match('--')) { - startToken = lookahead; - token = lex(); - expr = parseUnaryExpression(); - // 11.4.4, 11.4.5 - if ( - strict && - expr.type === Syntax.Identifier && - isRestrictedWord(expr.name) - ) { - throwErrorTolerant({}, Messages.StrictLHSPrefix); - } - - if (!isLeftHandSide(expr)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } - - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); - } else if (match('+') || match('-') || match('~') || match('!')) { - startToken = lookahead; - token = lex(); - expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); - } else if ( - matchKeyword('delete') || - matchKeyword('void') || - matchKeyword('typeof') - ) { - startToken = lookahead; - token = lex(); - expr = parseUnaryExpression(); - expr = delegate.createUnaryExpression(token.value, expr); - expr = delegate.markEnd(expr, startToken); - if ( - strict && - expr.operator === 'delete' && - expr.argument.type === Syntax.Identifier - ) { - throwErrorTolerant({}, Messages.StrictDelete); - } - } else { - expr = parsePostfixExpression(); - } - - return expr; - } - - function binaryPrecedence(token, allowIn) { - var prec = 0; - - if (token.type !== Token.Punctuator && token.type !== Token.Keyword) { - return 0; - } - - switch (token.value) { - case '||': - prec = 1; - break; - - case '&&': - prec = 2; - break; - - case '|': - prec = 3; - break; - - case '^': - prec = 4; - break; - - case '&': - prec = 5; - break; - - case '==': - case '!=': - case '===': - case '!==': - prec = 6; - break; - - case '<': - case '>': - case '<=': - case '>=': - case 'instanceof': - prec = 7; - break; - - case 'in': - prec = allowIn ? 7 : 0; - break; - - case '<<': - case '>>': - case '>>>': - prec = 8; - break; - - case '+': - case '-': - prec = 9; - break; - - case '*': - case '/': - case '%': - prec = 11; - break; - - default: - break; - } - - return prec; - } - - // 11.5 Multiplicative Operators - // 11.6 Additive Operators - // 11.7 Bitwise Shift Operators - // 11.8 Relational Operators - // 11.9 Equality Operators - // 11.10 Binary Bitwise Operators - // 11.11 Binary Logical Operators - - function parseBinaryExpression() { - var marker, markers, expr, token, prec, stack, right, operator, left, i; - - marker = lookahead; - left = parseUnaryExpression(); - - token = lookahead; - prec = binaryPrecedence(token, state.allowIn); - if (prec === 0) { - return left; - } - token.prec = prec; - lex(); - - markers = [marker, lookahead]; - right = parseUnaryExpression(); - - stack = [left, token, right]; - - while ((prec = binaryPrecedence(lookahead, state.allowIn)) > 0) { - // Reduce: make a binary expression from the three topmost entries. - while (stack.length > 2 && prec <= stack[stack.length - 2].prec) { - right = stack.pop(); - operator = stack.pop().value; - left = stack.pop(); - expr = delegate.createBinaryExpression(operator, left, right); - markers.pop(); - marker = markers[markers.length - 1]; - delegate.markEnd(expr, marker); - stack.push(expr); - } - - // Shift. - token = lex(); - token.prec = prec; - stack.push(token); - markers.push(lookahead); - expr = parseUnaryExpression(); - stack.push(expr); - } - - // Final reduce to clean-up the stack. - i = stack.length - 1; - expr = stack[i]; - markers.pop(); - while (i > 1) { - expr = delegate.createBinaryExpression( - stack[i - 1].value, - stack[i - 2], - expr - ); - i -= 2; - marker = markers.pop(); - delegate.markEnd(expr, marker); - } - - return expr; - } - - // 11.12 Conditional Operator - - function parseConditionalExpression() { - var expr, previousAllowIn, consequent, alternate, startToken; - - startToken = lookahead; - - expr = parseBinaryExpression(); - - if (match('?')) { - lex(); - previousAllowIn = state.allowIn; - state.allowIn = true; - consequent = parseAssignmentExpression(); - state.allowIn = previousAllowIn; - expect(':'); - alternate = parseAssignmentExpression(); - - expr = delegate.createConditionalExpression( - expr, - consequent, - alternate - ); - delegate.markEnd(expr, startToken); - } - - return expr; - } - - // 11.13 Assignment Operators - - function parseAssignmentExpression() { - var token, left, right, node, startToken; - - token = lookahead; - startToken = lookahead; - - node = left = parseConditionalExpression(); - - if (matchAssign()) { - // LeftHandSideExpression - if (!isLeftHandSide(left)) { - throwErrorTolerant({}, Messages.InvalidLHSInAssignment); - } - - // 11.13.1 - if ( - strict && - left.type === Syntax.Identifier && - isRestrictedWord(left.name) - ) { - throwErrorTolerant(token, Messages.StrictLHSAssignment); - } - - token = lex(); - right = parseAssignmentExpression(); - node = delegate.markEnd( - delegate.createAssignmentExpression(token.value, left, right), - startToken - ); - } - - return node; - } - - // 11.14 Comma Operator - - function parseExpression() { - var expr, - startToken = lookahead; - - expr = parseAssignmentExpression(); - - if (match(',')) { - expr = delegate.createSequenceExpression([expr]); - - while (index < length) { - if (!match(',')) { - break; - } - lex(); - expr.expressions.push(parseAssignmentExpression()); - } - - delegate.markEnd(expr, startToken); - } - - return expr; - } - - // 12.1 Block - - function parseStatementList() { - var list = [], - statement; - - while (index < length) { - if (match('}')) { - break; - } - statement = parseSourceElement(); - if (typeof statement === 'undefined') { - break; - } - list.push(statement); - } - - return list; - } - - function parseBlock() { - var block, startToken; - - startToken = lookahead; - expect('{'); - - block = parseStatementList(); - - expect('}'); - - return delegate.markEnd(delegate.createBlockStatement(block), startToken); - } - - // 12.2 Variable Statement - - function parseVariableIdentifier() { - var token, startToken; - - startToken = lookahead; - token = lex(); - - if (token.type !== Token.Identifier) { - throwUnexpected(token); - } - - return delegate.markEnd( - delegate.createIdentifier(token.value), - startToken - ); - } - - function parseVariableDeclaration(kind) { - var init = null, - id, - startToken; - - startToken = lookahead; - id = parseVariableIdentifier(); - - // 12.2.1 - if (strict && isRestrictedWord(id.name)) { - throwErrorTolerant({}, Messages.StrictVarName); - } - - if (kind === 'const') { - expect('='); - init = parseAssignmentExpression(); - } else if (match('=')) { - lex(); - init = parseAssignmentExpression(); - } - - return delegate.markEnd( - delegate.createVariableDeclarator(id, init), - startToken - ); - } - - function parseVariableDeclarationList(kind) { - var list = []; - - do { - list.push(parseVariableDeclaration(kind)); - if (!match(',')) { - break; - } - lex(); - } while (index < length); - - return list; - } - - function parseVariableStatement() { - var declarations; - - expectKeyword('var'); - - declarations = parseVariableDeclarationList(); - - consumeSemicolon(); - - return delegate.createVariableDeclaration(declarations, 'var'); - } - - // kind may be `const` or `let` - // Both are experimental and not in the specification yet. - // see http://wiki.ecmascript.org/doku.php?id=harmony:const - // and http://wiki.ecmascript.org/doku.php?id=harmony:let - function parseConstLetDeclaration(kind) { - var declarations, startToken; - - startToken = lookahead; - - expectKeyword(kind); - - declarations = parseVariableDeclarationList(kind); - - consumeSemicolon(); - - return delegate.markEnd( - delegate.createVariableDeclaration(declarations, kind), - startToken - ); - } - - // 12.3 Empty Statement - - function parseEmptyStatement() { - expect(';'); - return delegate.createEmptyStatement(); - } - - // 12.4 Expression Statement - - function parseExpressionStatement() { - var expr = parseExpression(); - consumeSemicolon(); - return delegate.createExpressionStatement(expr); - } - - // 12.5 If statement - - function parseIfStatement() { - var test, consequent, alternate; - - expectKeyword('if'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - consequent = parseStatement(); - - if (matchKeyword('else')) { - lex(); - alternate = parseStatement(); - } else { - alternate = null; - } - - return delegate.createIfStatement(test, consequent, alternate); - } - - // 12.6 Iteration Statements - - function parseDoWhileStatement() { - var body, test, oldInIteration; - - expectKeyword('do'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - expectKeyword('while'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - if (match(';')) { - lex(); - } - - return delegate.createDoWhileStatement(body, test); - } - - function parseWhileStatement() { - var test, body, oldInIteration; - - expectKeyword('while'); - - expect('('); - - test = parseExpression(); - - expect(')'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - return delegate.createWhileStatement(test, body); - } - - function parseForVariableDeclaration() { - var token, declarations, startToken; - - startToken = lookahead; - token = lex(); - declarations = parseVariableDeclarationList(); - - return delegate.markEnd( - delegate.createVariableDeclaration(declarations, token.value), - startToken - ); - } - - function parseForStatement() { - var init, test, update, left, right, body, oldInIteration; - - init = test = update = null; - - expectKeyword('for'); - - expect('('); - - if (match(';')) { - lex(); - } else { - if (matchKeyword('var') || matchKeyword('let')) { - state.allowIn = false; - init = parseForVariableDeclaration(); - state.allowIn = true; - - if (init.declarations.length === 1 && matchKeyword('in')) { - lex(); - left = init; - right = parseExpression(); - init = null; - } - } else { - state.allowIn = false; - init = parseExpression(); - state.allowIn = true; - - if (matchKeyword('in')) { - // LeftHandSideExpression - if (!isLeftHandSide(init)) { - throwErrorTolerant({}, Messages.InvalidLHSInForIn); - } - - lex(); - left = init; - right = parseExpression(); - init = null; - } - } - - if (typeof left === 'undefined') { - expect(';'); - } - } - - if (typeof left === 'undefined') { - if (!match(';')) { - test = parseExpression(); - } - expect(';'); - - if (!match(')')) { - update = parseExpression(); - } - } - - expect(')'); - - oldInIteration = state.inIteration; - state.inIteration = true; - - body = parseStatement(); - - state.inIteration = oldInIteration; - - return typeof left === 'undefined' - ? delegate.createForStatement(init, test, update, body) - : delegate.createForInStatement(left, right, body); - } - - // 12.7 The continue statement - - function parseContinueStatement() { - var label = null, - key; - - expectKeyword('continue'); - - // Optimize the most common form: 'continue;'. - if (source.charCodeAt(index) === 0x3b) { - lex(); - - if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); - } - - return delegate.createContinueStatement(null); - } - - if (peekLineTerminator()) { - if (!state.inIteration) { - throwError({}, Messages.IllegalContinue); - } - - return delegate.createContinueStatement(null); - } - - if (lookahead.type === Token.Identifier) { - label = parseVariableIdentifier(); - - key = '$' + label.name; - if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); - } - } - - consumeSemicolon(); - - if (label === null && !state.inIteration) { - throwError({}, Messages.IllegalContinue); - } - - return delegate.createContinueStatement(label); - } - - // 12.8 The break statement - - function parseBreakStatement() { - var label = null, - key; - - expectKeyword('break'); - - // Catch the very common case first: immediately a semicolon (U+003B). - if (source.charCodeAt(index) === 0x3b) { - lex(); - - if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); - } - - return delegate.createBreakStatement(null); - } - - if (peekLineTerminator()) { - if (!(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); - } - - return delegate.createBreakStatement(null); - } - - if (lookahead.type === Token.Identifier) { - label = parseVariableIdentifier(); - - key = '$' + label.name; - if (!Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.UnknownLabel, label.name); - } - } - - consumeSemicolon(); - - if (label === null && !(state.inIteration || state.inSwitch)) { - throwError({}, Messages.IllegalBreak); - } - - return delegate.createBreakStatement(label); - } - - // 12.9 The return statement - - function parseReturnStatement() { - var argument = null; - - expectKeyword('return'); - - if (!state.inFunctionBody) { - throwErrorTolerant({}, Messages.IllegalReturn); - } - - // 'return' followed by a space and an identifier is very common. - if (source.charCodeAt(index) === 0x20) { - if (isIdentifierStart(source.charCodeAt(index + 1))) { - argument = parseExpression(); - consumeSemicolon(); - return delegate.createReturnStatement(argument); - } - } - - if (peekLineTerminator()) { - return delegate.createReturnStatement(null); - } - - if (!match(';')) { - if (!match('}') && lookahead.type !== Token.EOF) { - argument = parseExpression(); - } - } - - consumeSemicolon(); - - return delegate.createReturnStatement(argument); - } - - // 12.10 The with statement - - function parseWithStatement() { - var object, body; - - if (strict) { - // TODO(ikarienator): Should we update the test cases instead? - skipComment(); - throwErrorTolerant({}, Messages.StrictModeWith); - } - - expectKeyword('with'); - - expect('('); - - object = parseExpression(); - - expect(')'); - - body = parseStatement(); - - return delegate.createWithStatement(object, body); - } - - // 12.10 The swith statement - - function parseSwitchCase() { - var test, - consequent = [], - statement, - startToken; - - startToken = lookahead; - if (matchKeyword('default')) { - lex(); - test = null; - } else { - expectKeyword('case'); - test = parseExpression(); - } - expect(':'); - - while (index < length) { - if (match('}') || matchKeyword('default') || matchKeyword('case')) { - break; - } - statement = parseStatement(); - consequent.push(statement); - } - - return delegate.markEnd( - delegate.createSwitchCase(test, consequent), - startToken - ); - } - - function parseSwitchStatement() { - var discriminant, cases, clause, oldInSwitch, defaultFound; - - expectKeyword('switch'); - - expect('('); - - discriminant = parseExpression(); - - expect(')'); - - expect('{'); - - cases = []; - - if (match('}')) { - lex(); - return delegate.createSwitchStatement(discriminant, cases); - } - - oldInSwitch = state.inSwitch; - state.inSwitch = true; - defaultFound = false; - - while (index < length) { - if (match('}')) { - break; - } - clause = parseSwitchCase(); - if (clause.test === null) { - if (defaultFound) { - throwError({}, Messages.MultipleDefaultsInSwitch); - } - defaultFound = true; - } - cases.push(clause); - } - - state.inSwitch = oldInSwitch; - - expect('}'); - - return delegate.createSwitchStatement(discriminant, cases); - } - - // 12.13 The throw statement - - function parseThrowStatement() { - var argument; - - expectKeyword('throw'); - - if (peekLineTerminator()) { - throwError({}, Messages.NewlineAfterThrow); - } - - argument = parseExpression(); - - consumeSemicolon(); - - return delegate.createThrowStatement(argument); - } - - // 12.14 The try statement - - function parseCatchClause() { - var param, body, startToken; - - startToken = lookahead; - expectKeyword('catch'); - - expect('('); - if (match(')')) { - throwUnexpected(lookahead); - } - - param = parseVariableIdentifier(); - // 12.14.1 - if (strict && isRestrictedWord(param.name)) { - throwErrorTolerant({}, Messages.StrictCatchVariable); - } - - expect(')'); - body = parseBlock(); - return delegate.markEnd( - delegate.createCatchClause(param, body), - startToken - ); - } - - function parseTryStatement() { - var block, - handlers = [], - finalizer = null; - - expectKeyword('try'); - - block = parseBlock(); - - if (matchKeyword('catch')) { - handlers.push(parseCatchClause()); - } - - if (matchKeyword('finally')) { - lex(); - finalizer = parseBlock(); - } - - if (handlers.length === 0 && !finalizer) { - throwError({}, Messages.NoCatchOrFinally); - } - - return delegate.createTryStatement(block, [], handlers, finalizer); - } - - // 12.15 The debugger statement - - function parseDebuggerStatement() { - expectKeyword('debugger'); - - consumeSemicolon(); - - return delegate.createDebuggerStatement(); - } - - // 12 Statements - - function parseStatement() { - var type = lookahead.type, - expr, - labeledBody, - key, - startToken; - - if (type === Token.EOF) { - throwUnexpected(lookahead); - } - - if (type === Token.Punctuator && lookahead.value === '{') { - return parseBlock(); - } - - startToken = lookahead; - - if (type === Token.Punctuator) { - switch (lookahead.value) { - case ';': - return delegate.markEnd(parseEmptyStatement(), startToken); - case '(': - return delegate.markEnd(parseExpressionStatement(), startToken); - default: - break; - } - } - - if (type === Token.Keyword) { - switch (lookahead.value) { - case 'break': - return delegate.markEnd(parseBreakStatement(), startToken); - case 'continue': - return delegate.markEnd(parseContinueStatement(), startToken); - case 'debugger': - return delegate.markEnd(parseDebuggerStatement(), startToken); - case 'do': - return delegate.markEnd(parseDoWhileStatement(), startToken); - case 'for': - return delegate.markEnd(parseForStatement(), startToken); - case 'function': - return delegate.markEnd(parseFunctionDeclaration(), startToken); - case 'if': - return delegate.markEnd(parseIfStatement(), startToken); - case 'return': - return delegate.markEnd(parseReturnStatement(), startToken); - case 'switch': - return delegate.markEnd(parseSwitchStatement(), startToken); - case 'throw': - return delegate.markEnd(parseThrowStatement(), startToken); - case 'try': - return delegate.markEnd(parseTryStatement(), startToken); - case 'var': - return delegate.markEnd(parseVariableStatement(), startToken); - case 'while': - return delegate.markEnd(parseWhileStatement(), startToken); - case 'with': - return delegate.markEnd(parseWithStatement(), startToken); - default: - break; - } - } - - expr = parseExpression(); - - // 12.12 Labelled Statements - if (expr.type === Syntax.Identifier && match(':')) { - lex(); - - key = '$' + expr.name; - if (Object.prototype.hasOwnProperty.call(state.labelSet, key)) { - throwError({}, Messages.Redeclaration, 'Label', expr.name); - } - - state.labelSet[key] = true; - labeledBody = parseStatement(); - delete state.labelSet[key]; - return delegate.markEnd( - delegate.createLabeledStatement(expr, labeledBody), - startToken - ); - } - - consumeSemicolon(); - - return delegate.markEnd( - delegate.createExpressionStatement(expr), - startToken - ); - } - - // 13 Function Definition - - function parseFunctionSourceElements() { - var sourceElement, - sourceElements = [], - token, - directive, - firstRestricted, - oldLabelSet, - oldInIteration, - oldInSwitch, - oldInFunctionBody, - startToken; - - startToken = lookahead; - expect('{'); - - while (index < length) { - if (lookahead.type !== Token.StringLiteral) { - break; - } - token = lookahead; - - sourceElement = parseSourceElement(); - sourceElements.push(sourceElement); - if (sourceElement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = source.slice(token.start + 1, token.end - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - oldLabelSet = state.labelSet; - oldInIteration = state.inIteration; - oldInSwitch = state.inSwitch; - oldInFunctionBody = state.inFunctionBody; - - state.labelSet = {}; - state.inIteration = false; - state.inSwitch = false; - state.inFunctionBody = true; - - while (index < length) { - if (match('}')) { - break; - } - sourceElement = parseSourceElement(); - if (typeof sourceElement === 'undefined') { - break; - } - sourceElements.push(sourceElement); - } - - expect('}'); - - state.labelSet = oldLabelSet; - state.inIteration = oldInIteration; - state.inSwitch = oldInSwitch; - state.inFunctionBody = oldInFunctionBody; - - return delegate.markEnd( - delegate.createBlockStatement(sourceElements), - startToken - ); - } - - function parseParams(firstRestricted) { - var param, - params = [], - token, - stricted, - paramSet, - key, - message; - expect('('); - - if (!match(')')) { - paramSet = {}; - while (index < length) { - token = lookahead; - param = parseVariableIdentifier(); - key = '$' + token.value; - if (strict) { - if (isRestrictedWord(token.value)) { - stricted = token; - message = Messages.StrictParamName; - } - if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - stricted = token; - message = Messages.StrictParamDupe; - } - } else if (!firstRestricted) { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictParamName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } else if (Object.prototype.hasOwnProperty.call(paramSet, key)) { - firstRestricted = token; - message = Messages.StrictParamDupe; - } - } - params.push(param); - paramSet[key] = true; - if (match(')')) { - break; - } - expect(','); - } - } - - expect(')'); - - return { - params: params, - stricted: stricted, - firstRestricted: firstRestricted, - message: message, - }; - } - - function parseFunctionDeclaration() { - var id, - params = [], - body, - token, - stricted, - tmp, - firstRestricted, - message, - previousStrict, - startToken; - - startToken = lookahead; - - expectKeyword('function'); - token = lookahead; - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - - tmp = parseParams(firstRestricted); - params = tmp.params; - stricted = tmp.stricted; - firstRestricted = tmp.firstRestricted; - if (tmp.message) { - message = tmp.message; - } - - previousStrict = strict; - body = parseFunctionSourceElements(); - if (strict && firstRestricted) { - throwError(firstRestricted, message); - } - if (strict && stricted) { - throwErrorTolerant(stricted, message); - } - strict = previousStrict; - - return delegate.markEnd( - delegate.createFunctionDeclaration(id, params, [], body), - startToken - ); - } - - function parseFunctionExpression() { - var token, - id = null, - stricted, - firstRestricted, - message, - tmp, - params = [], - body, - previousStrict, - startToken; - - startToken = lookahead; - expectKeyword('function'); - - if (!match('(')) { - token = lookahead; - id = parseVariableIdentifier(); - if (strict) { - if (isRestrictedWord(token.value)) { - throwErrorTolerant(token, Messages.StrictFunctionName); - } - } else { - if (isRestrictedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictFunctionName; - } else if (isStrictModeReservedWord(token.value)) { - firstRestricted = token; - message = Messages.StrictReservedWord; - } - } - } - - tmp = parseParams(firstRestricted); - params = tmp.params; - stricted = tmp.stricted; - firstRestricted = tmp.firstRestricted; - if (tmp.message) { - message = tmp.message; - } - - previousStrict = strict; - body = parseFunctionSourceElements(); - if (strict && firstRestricted) { - throwError(firstRestricted, message); - } - if (strict && stricted) { - throwErrorTolerant(stricted, message); - } - strict = previousStrict; - - return delegate.markEnd( - delegate.createFunctionExpression(id, params, [], body), - startToken - ); - } - - // 14 Program - - function parseSourceElement() { - if (lookahead.type === Token.Keyword) { - switch (lookahead.value) { - case 'const': - case 'let': - return parseConstLetDeclaration(lookahead.value); - case 'function': - return parseFunctionDeclaration(); - default: - return parseStatement(); - } - } - - if (lookahead.type !== Token.EOF) { - return parseStatement(); - } - } - - function parseSourceElements() { - var sourceElement, - sourceElements = [], - token, - directive, - firstRestricted; - - while (index < length) { - token = lookahead; - if (token.type !== Token.StringLiteral) { - break; - } - - sourceElement = parseSourceElement(); - sourceElements.push(sourceElement); - if (sourceElement.expression.type !== Syntax.Literal) { - // this is not directive - break; - } - directive = source.slice(token.start + 1, token.end - 1); - if (directive === 'use strict') { - strict = true; - if (firstRestricted) { - throwErrorTolerant(firstRestricted, Messages.StrictOctalLiteral); - } - } else { - if (!firstRestricted && token.octal) { - firstRestricted = token; - } - } - } - - while (index < length) { - sourceElement = parseSourceElement(); - /* istanbul ignore if */ - if (typeof sourceElement === 'undefined') { - break; - } - sourceElements.push(sourceElement); - } - return sourceElements; - } - - function parseProgram() { - var body, startToken; - - skipComment(); - peek(); - startToken = lookahead; - strict = false; - - body = parseSourceElements(); - return delegate.markEnd(delegate.createProgram(body), startToken); - } - - function filterTokenLocation() { - var i, - entry, - token, - tokens = []; - - for (i = 0; i < extra.tokens.length; ++i) { - entry = extra.tokens[i]; - token = { - type: entry.type, - value: entry.value, - }; - if (extra.range) { - token.range = entry.range; - } - if (extra.loc) { - token.loc = entry.loc; - } - tokens.push(token); - } - - extra.tokens = tokens; - } - - function tokenize(code, options) { - var toString, token, tokens; - - toString = String; - if (typeof code !== 'string' && !(code instanceof String)) { - code = toString(code); - } - - delegate = SyntaxTreeDelegate; - source = code; - index = 0; - lineNumber = source.length > 0 ? 1 : 0; - lineStart = 0; - length = source.length; - lookahead = null; - state = { - allowIn: true, - labelSet: {}, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - lastCommentStart: -1, - }; - - extra = {}; - - // Options matching. - options = options || {}; - - // Of course we collect tokens here. - options.tokens = true; - extra.tokens = []; - extra.tokenize = true; - // The following two fields are necessary to compute the Regex tokens. - extra.openParenToken = -1; - extra.openCurlyToken = -1; - - extra.range = typeof options.range === 'boolean' && options.range; - extra.loc = typeof options.loc === 'boolean' && options.loc; - - if (typeof options.comment === 'boolean' && options.comment) { - extra.comments = []; - } - if (typeof options.tolerant === 'boolean' && options.tolerant) { - extra.errors = []; - } - - try { - peek(); - if (lookahead.type === Token.EOF) { - return extra.tokens; - } - - token = lex(); - while (lookahead.type !== Token.EOF) { - try { - token = lex(); - } catch (lexError) { - token = lookahead; - if (extra.errors) { - extra.errors.push(lexError); - // We have to break on the first error - // to avoid infinite loops. - break; - } else { - throw lexError; - } - } - } - - filterTokenLocation(); - tokens = extra.tokens; - if (typeof extra.comments !== 'undefined') { - tokens.comments = extra.comments; - } - if (typeof extra.errors !== 'undefined') { - tokens.errors = extra.errors; - } - } catch (e) { - throw e; - } finally { - extra = {}; - } - return tokens; - } - - function parse(code, options) { - var program, toString; - - toString = String; - if (typeof code !== 'string' && !(code instanceof String)) { - code = toString(code); - } - - delegate = SyntaxTreeDelegate; - source = code; - index = 0; - lineNumber = source.length > 0 ? 1 : 0; - lineStart = 0; - length = source.length; - lookahead = null; - state = { - allowIn: true, - labelSet: {}, - inFunctionBody: false, - inIteration: false, - inSwitch: false, - lastCommentStart: -1, - }; - - extra = {}; - if (typeof options !== 'undefined') { - extra.range = typeof options.range === 'boolean' && options.range; - extra.loc = typeof options.loc === 'boolean' && options.loc; - extra.attachComment = - typeof options.attachComment === 'boolean' && options.attachComment; - - if ( - extra.loc && - options.source !== null && - options.source !== undefined - ) { - extra.source = toString(options.source); - } - - if (typeof options.tokens === 'boolean' && options.tokens) { - extra.tokens = []; - } - if (typeof options.comment === 'boolean' && options.comment) { - extra.comments = []; - } - if (typeof options.tolerant === 'boolean' && options.tolerant) { - extra.errors = []; - } - if (extra.attachComment) { - extra.range = true; - extra.comments = []; - extra.bottomRightStack = []; - extra.trailingComments = []; - extra.leadingComments = []; - } - } - - try { - program = parseProgram(); - if (typeof extra.comments !== 'undefined') { - program.comments = extra.comments; - } - if (typeof extra.tokens !== 'undefined') { - filterTokenLocation(); - program.tokens = extra.tokens; - } - if (typeof extra.errors !== 'undefined') { - program.errors = extra.errors; - } - } catch (e) { - throw e; - } finally { - extra = {}; - } - - return program; - } - - // Sync with *.json manifests. - exports.version = '1.2.2'; - - exports.tokenize = tokenize; - - exports.parse = parse; - - // Deep copy. - /* istanbul ignore next */ - exports.Syntax = (function() { - var name, - types = {}; - - if (typeof Object.create === 'function') { - types = Object.create(null); - } - - for (name in Syntax) { - if (Syntax.hasOwnProperty(name)) { - types[name] = Syntax[name]; - } - } - - if (typeof Object.freeze === 'function') { - Object.freeze(types); - } - - return types; - })(); - }); - /* vim: set sw=4 ts=4 et tw=80 : */ -})(null); -/*! - * falafel (c) James Halliday / MIT License - * https://github.com/substack/node-falafel - */ - -(function(require, module) { - var parse = require('esprima').parse; - var objectKeys = - Object.keys || - function(obj) { - var keys = []; - for (var key in obj) keys.push(key); - return keys; - }; - var forEach = function(xs, fn) { - if (xs.forEach) return xs.forEach(fn); - for (var i = 0; i < xs.length; i++) { - fn.call(xs, xs[i], i, xs); - } - }; - - var isArray = - Array.isArray || - function(xs) { - return Object.prototype.toString.call(xs) === '[object Array]'; - }; - - module.exports = function(src, opts, fn) { - if (typeof opts === 'function') { - fn = opts; - opts = {}; - } - if (typeof src === 'object') { - opts = src; - src = opts.source; - delete opts.source; - } - src = src === undefined ? opts.source : src; - opts.range = true; - if (typeof src !== 'string') src = String(src); - - var ast = parse(src, opts); - - var result = { - chunks: src.split(''), - toString: function() { - return result.chunks.join(''); - }, - inspect: function() { - return result.toString(); - }, - }; - var index = 0; - - (function walk(node, parent) { - insertHelpers(node, parent, result.chunks); - - forEach(objectKeys(node), function(key) { - if (key === 'parent') return; - - var child = node[key]; - if (isArray(child)) { - forEach(child, function(c) { - if (c && typeof c.type === 'string') { - walk(c, node); - } - }); - } else if (child && typeof child.type === 'string') { - insertHelpers(child, node, result.chunks); - walk(child, node); - } - }); - fn(node); - })(ast, undefined); - - return result; - }; - - function insertHelpers(node, parent, chunks) { - if (!node.range) return; - - node.parent = parent; - - node.source = function() { - return chunks.slice(node.range[0], node.range[1]).join(''); - }; - - if (node.update && typeof node.update === 'object') { - var prev = node.update; - forEach(objectKeys(prev), function(key) { - update[key] = prev[key]; - }); - node.update = update; - } else { - node.update = update; - } - - function update(s) { - chunks[node.range[0]] = s; - for (var i = node.range[0] + 1; i < node.range[1]; i++) { - chunks[i] = ''; - } - } - } - - window.falafel = module.exports; -})( - function() { - return { parse: esprima.parse }; - }, - { exports: {} } -); -var inBrowser = typeof window !== 'undefined' && this === window; -var parseAndModify = inBrowser ? window.falafel : require('falafel'); - -(inBrowser ? window : exports).blanket = (function() { - var linesToAddTracking = [ - 'ExpressionStatement', - 'BreakStatement', - 'ContinueStatement', - 'VariableDeclaration', - 'ReturnStatement', - 'ThrowStatement', - 'TryStatement', - 'FunctionDeclaration', - 'IfStatement', - 'WhileStatement', - 'DoWhileStatement', - 'ForStatement', - 'ForInStatement', - 'SwitchStatement', - 'WithStatement', - ], - linesToAddBrackets = [ - 'IfStatement', - 'WhileStatement', - 'DoWhileStatement', - 'ForStatement', - 'ForInStatement', - 'WithStatement', - ], - __blanket, - copynumber = Math.floor(Math.random() * 1000), - coverageInfo = {}, - options = { - reporter: null, - adapter: null, - filter: null, - customVariable: null, - loader: null, - ignoreScriptError: false, - existingRequireJS: false, - autoStart: false, - timeout: 180, - ignoreCors: false, - branchTracking: false, - sourceURL: false, - debug: false, - engineOnly: false, - testReadyCallback: null, - commonJS: false, - instrumentCache: false, - modulePattern: null, - }; - - if (inBrowser && typeof window.blanket !== 'undefined') { - __blanket = window.blanket.noConflict(); - } - - _blanket = { - noConflict: function() { - if (__blanket) { - return __blanket; - } - return _blanket; - }, - _getCopyNumber: function() { - //internal method - //for differentiating between instances - return copynumber; - }, - extend: function(obj) { - //borrowed from underscore - _blanket._extend(_blanket, obj); - }, - _extend: function(dest, source) { - if (source) { - for (var prop in source) { - if ( - dest[prop] instanceof Object && - typeof dest[prop] !== 'function' - ) { - _blanket._extend(dest[prop], source[prop]); - } else { - dest[prop] = source[prop]; - } - } - } - }, - getCovVar: function() { - var opt = _blanket.options('customVariable'); - if (opt) { - if (_blanket.options('debug')) { - console.log('BLANKET-Using custom tracking variable:', opt); - } - return inBrowser ? 'window.' + opt : opt; - } - return inBrowser ? 'window._$blanket' : '_$jscoverage'; - }, - options: function(key, value) { - if (typeof key !== 'string') { - _blanket._extend(options, key); - } else if (typeof value === 'undefined') { - return options[key]; - } else { - options[key] = value; - } - }, - instrument: function(config, next) { - //check instrumented hash table, - //return instrumented code if available. - var inFile = config.inputFile, - inFileName = config.inputFileName; - //check instrument cache - if ( - _blanket.options('instrumentCache') && - sessionStorage && - sessionStorage.getItem('blanket_instrument_store-' + inFileName) - ) { - if (_blanket.options('debug')) { - console.log( - 'BLANKET-Reading instrumentation from cache: ', - inFileName - ); - } - next(sessionStorage.getItem('blanket_instrument_store-' + inFileName)); - } else { - var sourceArray = _blanket._prepareSource(inFile); - _blanket._trackingArraySetup = []; - //remove shebang - inFile = inFile.replace(/^\#\!.*/, ''); - var instrumented = parseAndModify( - inFile, - { loc: true, comment: true }, - _blanket._addTracking(inFileName) - ); - instrumented = - _blanket._trackingSetup(inFileName, sourceArray) + instrumented; - if (_blanket.options('sourceURL')) { - instrumented += - '\n//@ sourceURL=' + inFileName.replace('http://', ''); - } - if (_blanket.options('debug')) { - console.log('BLANKET-Instrumented file: ', inFileName); - } - if (_blanket.options('instrumentCache') && sessionStorage) { - if (_blanket.options('debug')) { - console.log( - 'BLANKET-Saving instrumentation to cache: ', - inFileName - ); - } - sessionStorage.setItem( - 'blanket_instrument_store-' + inFileName, - instrumented - ); - } - next(instrumented); - } - }, - _trackingArraySetup: [], - _branchingArraySetup: [], - _prepareSource: function(source) { - return source - .replace(/\\/g, '\\\\') - .replace(/'/g, "\\'") - .replace(/(\r\n|\n|\r)/gm, '\n') - .split('\n'); - }, - _trackingSetup: function(filename, sourceArray) { - var branches = _blanket.options('branchTracking'); - var sourceString = sourceArray.join("',\n'"); - var intro = ''; - var covVar = _blanket.getCovVar(); - - intro += - 'if (typeof ' + covVar + " === 'undefined') " + covVar + ' = {};\n'; - if (branches) { - intro += 'var _$branchFcn=function(f,l,c,r){ '; - intro += 'if (!!r) { '; - intro += - covVar + - '[f].branchData[l][c][0] = ' + - covVar + - '[f].branchData[l][c][0] || [];'; - intro += covVar + '[f].branchData[l][c][0].push(r); }'; - intro += 'else { '; - intro += - covVar + - '[f].branchData[l][c][1] = ' + - covVar + - '[f].branchData[l][c][1] || [];'; - intro += covVar + '[f].branchData[l][c][1].push(r); }'; - intro += 'return r;};\n'; - } - intro += - 'if (typeof ' + covVar + "['" + filename + "'] === 'undefined'){"; - - intro += covVar + "['" + filename + "']=[];\n"; - if (branches) { - intro += covVar + "['" + filename + "'].branchData=[];\n"; - } - intro += - covVar + "['" + filename + "'].source=['" + sourceString + "'];\n"; - //initialize array values - _blanket._trackingArraySetup - .sort(function(a, b) { - return parseInt(a, 10) > parseInt(b, 10); - }) - .forEach(function(item) { - intro += covVar + "['" + filename + "'][" + item + ']=0;\n'; - }); - if (branches) { - _blanket._branchingArraySetup - .sort(function(a, b) { - return a.line > b.line; - }) - .sort(function(a, b) { - return a.column > b.column; - }) - .forEach(function(item) { - if (item.file === filename) { - intro += - 'if (typeof ' + - covVar + - "['" + - filename + - "'].branchData[" + - item.line + - "] === 'undefined'){\n"; - intro += - covVar + - "['" + - filename + - "'].branchData[" + - item.line + - ']=[];\n'; - intro += '}'; - intro += - covVar + - "['" + - filename + - "'].branchData[" + - item.line + - '][' + - item.column + - '] = [];\n'; - intro += - covVar + - "['" + - filename + - "'].branchData[" + - item.line + - '][' + - item.column + - '].consequent = ' + - JSON.stringify(item.consequent) + - ';\n'; - intro += - covVar + - "['" + - filename + - "'].branchData[" + - item.line + - '][' + - item.column + - '].alternate = ' + - JSON.stringify(item.alternate) + - ';\n'; - } - }); - } - intro += '}'; - - return intro; - }, - _blockifyIf: function(node) { - if (linesToAddBrackets.indexOf(node.type) > -1) { - var bracketsExistObject = node.consequent || node.body; - var bracketsExistAlt = node.alternate; - if (bracketsExistAlt && bracketsExistAlt.type !== 'BlockStatement') { - bracketsExistAlt.update('{\n' + bracketsExistAlt.source() + '}\n'); - } - if ( - bracketsExistObject && - bracketsExistObject.type !== 'BlockStatement' - ) { - bracketsExistObject.update( - '{\n' + bracketsExistObject.source() + '}\n' - ); - } - } - }, - _trackBranch: function(node, filename) { - //recursive on consequent and alternative - var line = node.loc.start.line; - var col = node.loc.start.column; - - _blanket._branchingArraySetup.push({ - line: line, - column: col, - file: filename, - consequent: node.consequent.loc, - alternate: node.alternate.loc, - }); - - var updated = - '_$branchFcn' + - "('" + - filename + - "'," + - line + - ',' + - col + - ',' + - node.test.source() + - ')?' + - node.consequent.source() + - ':' + - node.alternate.source(); - node.update(updated); - }, - _addTracking: function(filename) { - //falafel doesn't take a file name - //so we include the filename in a closure - //and return the function to falafel - var covVar = _blanket.getCovVar(); - - return function(node) { - _blanket._blockifyIf(node); - - if ( - linesToAddTracking.indexOf(node.type) > -1 && - node.parent.type !== 'LabeledStatement' - ) { - _blanket._checkDefs(node, filename); - if ( - node.type === 'VariableDeclaration' && - (node.parent.type === 'ForStatement' || - node.parent.type === 'ForInStatement') - ) { - return; - } - if (node.loc && node.loc.start) { - node.update( - covVar + - "['" + - filename + - "'][" + - node.loc.start.line + - ']++;\n' + - node.source() - ); - _blanket._trackingArraySetup.push(node.loc.start.line); - } else { - //I don't think we can handle a node with no location - throw new Error( - 'The instrumenter encountered a node with no location: ' + - Object.keys(node) - ); - } - } else if ( - _blanket.options('branchTracking') && - node.type === 'ConditionalExpression' - ) { - _blanket._trackBranch(node, filename); - } - }; - }, - _checkDefs: function(node, filename) { - // Make sure developers don't redefine window. if they do, inform them it is wrong. - if (inBrowser) { - if (node.type === 'VariableDeclaration' && node.declarations) { - node.declarations.forEach(function(declaration) { - if (declaration.id.name === 'window') { - throw new Error( - "Instrumentation error, you cannot redefine the 'window' variable in " + - filename + - ':' + - node.loc.start.line - ); - } - }); - } - if (node.type === 'FunctionDeclaration' && node.params) { - node.params.forEach(function(param) { - if (param.name === 'window') { - throw new Error( - "Instrumentation error, you cannot redefine the 'window' variable in " + - filename + - ':' + - node.loc.start.line - ); - } - }); - } - //Make sure developers don't redefine the coverage variable - if ( - node.type === 'ExpressionStatement' && - node.expression && - node.expression.left && - node.expression.left.object && - node.expression.left.property && - node.expression.left.object.name + - '.' + - node.expression.left.property.name === - _blanket.getCovVar() - ) { - throw new Error( - 'Instrumentation error, you cannot redefine the coverage variable in ' + - filename + - ':' + - node.loc.start.line - ); - } - } else { - //Make sure developers don't redefine the coverage variable in node - if ( - node.type === 'ExpressionStatement' && - node.expression && - node.expression.left && - !node.expression.left.object && - !node.expression.left.property && - node.expression.left.name === _blanket.getCovVar() - ) { - throw new Error( - 'Instrumentation error, you cannot redefine the coverage variable in ' + - filename + - ':' + - node.loc.start.line - ); - } - } - }, - setupCoverage: function() { - coverageInfo.instrumentation = 'blanket'; - coverageInfo.stats = { - suites: 0, - tests: 0, - passes: 0, - pending: 0, - failures: 0, - start: new Date(), - }; - }, - _checkIfSetup: function() { - if (!coverageInfo.stats) { - throw new Error('You must call blanket.setupCoverage() first.'); - } - }, - onTestStart: function() { - if (_blanket.options('debug')) { - console.log('BLANKET-Test event started'); - } - this._checkIfSetup(); - coverageInfo.stats.tests++; - coverageInfo.stats.pending++; - }, - onTestDone: function(total, passed) { - this._checkIfSetup(); - if (passed === total) { - coverageInfo.stats.passes++; - } else { - coverageInfo.stats.failures++; - } - coverageInfo.stats.pending--; - }, - onModuleStart: function() { - this._checkIfSetup(); - coverageInfo.stats.suites++; - }, - onTestsDone: function() { - if (_blanket.options('debug')) { - console.log('BLANKET-Test event done'); - } - this._checkIfSetup(); - coverageInfo.stats.end = new Date(); - - if (inBrowser) { - this.report(coverageInfo); - } else { - if (!_blanket.options('branchTracking')) { - delete (inBrowser ? window : global)[_blanket.getCovVar()].branchFcn; - } - this.options('reporter').call(this, coverageInfo); - } - }, - }; - return _blanket; -})(); - -(function(_blanket) { - var oldOptions = _blanket.options; - _blanket.extend({ - outstandingRequireFiles: [], - options: function(key, value) { - var newVal = {}; - - if (typeof key !== 'string') { - //key is key/value map - oldOptions(key); - newVal = key; - } else if (typeof value === 'undefined') { - //accessor - return oldOptions(key); - } else { - //setter - oldOptions(key, value); - newVal[key] = value; - } - - if (newVal.adapter) { - _blanket._loadFile(newVal.adapter); - } - if (newVal.loader) { - _blanket._loadFile(newVal.loader); - } - }, - requiringFile: function(filename, done) { - if (typeof filename === 'undefined') { - _blanket.outstandingRequireFiles = []; - } else if (typeof done === 'undefined') { - _blanket.outstandingRequireFiles.push(filename); - } else { - _blanket.outstandingRequireFiles.splice( - _blanket.outstandingRequireFiles.indexOf(filename), - 1 - ); - } - }, - requireFilesLoaded: function() { - return _blanket.outstandingRequireFiles.length === 0; - }, - showManualLoader: function() { - if (document.getElementById('blanketLoaderDialog')) { - return; - } - //copied from http://blog.avtex.com/2012/01/26/cross-browser-css-only-modal-box/ - var loader = "
"; - loader += ' 
'; - loader += "
"; - loader += "
"; - loader += - 'Error: Blanket.js encountered a cross origin request error while instrumenting the source files. '; - loader += - '

This is likely caused by the source files being referenced locally (using the file:// protocol). '; - loader += - "

Some solutions include starting Chrome with special flags, running a server locally, or using a browser without these CORS restrictions (Safari)."; - loader += '
'; - if (typeof FileReader !== 'undefined') { - loader += - '
Or, try the experimental loader. When prompted, simply click on the directory containing all the source files you want covered.'; - loader += - 'Start Loader'; - loader += - ""; - } - loader += - "
Close"; - loader += "
"; - loader += '
'; - - var css = '.blanketDialogWrapper {'; - css += 'display:block;'; - css += 'position:fixed;'; - css += 'z-index:40001; }'; - - css += '.blanketDialogOverlay {'; - css += 'position:fixed;'; - css += 'width:100%;'; - css += 'height:100%;'; - css += 'background-color:black;'; - css += 'opacity:.5; '; - css += - "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; "; - css += 'filter:alpha(opacity=50); '; - css += 'z-index:40001; }'; - - css += '.blanketDialogVerticalOffset { '; - css += 'position:fixed;'; - css += 'top:30%;'; - css += 'width:100%;'; - css += 'z-index:40002; }'; - - css += '.blanketDialogBox { '; - css += 'width:405px; '; - css += 'position:relative;'; - css += 'margin:0 auto;'; - css += 'background-color:white;'; - css += 'padding:10px;'; - css += 'border:1px solid black; }'; - - var dom = document.createElement('style'); - dom.innerHTML = css; - document.head.appendChild(dom); - - var div = document.createElement('div'); - div.id = 'blanketLoaderDialog'; - div.className = 'blanketDialogWrapper'; - div.innerHTML = loader; - document.body.insertBefore(div, document.body.firstChild); - }, - manualFileLoader: function(files) { - var toArray = Array.prototype.slice; - files = toArray.call(files).filter(function(item) { - return item.type !== ''; - }); - var sessionLength = files.length - 1; - var sessionIndx = 0; - var sessionArray = {}; - if (sessionStorage['blanketSessionLoader']) { - sessionArray = JSON.parse(sessionStorage['blanketSessionLoader']); - } - - var fileLoader = function(event) { - var fileContent = event.currentTarget.result; - var file = files[sessionIndx]; - var filename = - file.webkitRelativePath && file.webkitRelativePath !== '' - ? file.webkitRelativePath - : file.name; - sessionArray[filename] = fileContent; - sessionIndx++; - if (sessionIndx === sessionLength) { - sessionStorage.setItem( - 'blanketSessionLoader', - JSON.stringify(sessionArray) - ); - document.location.reload(); - } else { - readFile(files[sessionIndx]); - } - }; - function readFile(file) { - var reader = new FileReader(); - reader.onload = fileLoader; - reader.readAsText(file); - } - readFile(files[sessionIndx]); - }, - _loadFile: function(path) { - if (typeof path !== 'undefined') { - var request = new XMLHttpRequest(); - request.open('GET', path, false); - request.send(); - _blanket._addScript(request.responseText); - } - }, - _addScript: function(data) { - /*var script = document.createElement("script"); - script.type = "text/javascript"; - script.text = data; - (document.body || document.getElementsByTagName('head')[0]).appendChild(script);*/ - (1, eval)(data); - }, - hasAdapter: function(callback) { - return _blanket.options('adapter') !== null; - }, - report: function(coverage_data) { - if (!document.getElementById('blanketLoaderDialog')) { - //all found, clear it - _blanket.blanketSession = null; - } - coverage_data.files = window._$blanket; - var require = blanket.options('commonJS') - ? blanket._commonjs.require - : window.require; - - // Check if we have any covered files that requires reporting - // otherwise just exit gracefully. - if (!coverage_data.files || !Object.keys(coverage_data.files).length) { - if (_blanket.options('debug')) { - console.log('BLANKET-Reporting No files were instrumented.'); - } - return; - } - - if (typeof coverage_data.files.branchFcn !== 'undefined') { - delete coverage_data.files.branchFcn; - } - if (typeof _blanket.options('reporter') === 'string') { - _blanket._loadFile(_blanket.options('reporter')); - _blanket.customReporter( - coverage_data, - _blanket.options('reporter_options') - ); - } else if (typeof _blanket.options('reporter') === 'function') { - _blanket.options('reporter')( - coverage_data, - _blanket.options('reporter_options') - ); - } else if (typeof _blanket.defaultReporter === 'function') { - _blanket.defaultReporter( - coverage_data, - _blanket.options('reporter_options') - ); - } else { - throw new Error('no reporter defined.'); - } - }, - _bindStartTestRunner: function(bindEvent, startEvent) { - if (bindEvent) { - bindEvent(startEvent); - } else { - window.addEventListener('load', startEvent, false); - } - }, - _loadSourceFiles: function(callback) { - var require = blanket.options('commonJS') - ? blanket._commonjs.require - : window.require; - function copy(o) { - var _copy = Object.create(Object.getPrototypeOf(o)); - var propNames = Object.getOwnPropertyNames(o); - - propNames.forEach(function(name) { - var desc = Object.getOwnPropertyDescriptor(o, name); - Object.defineProperty(_copy, name, desc); - }); - - return _copy; - } - if (_blanket.options('debug')) { - console.log('BLANKET-Collecting page scripts'); - } - var scripts = _blanket.utils.collectPageScripts(); - //_blanket.options("filter",scripts); - if (scripts.length === 0) { - callback(); - } else { - //check session state - if (sessionStorage['blanketSessionLoader']) { - _blanket.blanketSession = JSON.parse( - sessionStorage['blanketSessionLoader'] - ); - } - - scripts.forEach(function(file, indx) { - _blanket.utils.cache[file] = { - loaded: false, - }; - }); - - var currScript = -1; - _blanket.utils.loadAll(function(test) { - if (test) { - return typeof scripts[currScript + 1] !== 'undefined'; - } - currScript++; - if (currScript >= scripts.length) { - return null; - } - return scripts[currScript]; - }, callback); - } - }, - beforeStartTestRunner: function(opts) { - opts = opts || {}; - opts.checkRequirejs = - typeof opts.checkRequirejs === 'undefined' ? true : opts.checkRequirejs; - opts.callback = opts.callback || function() {}; - opts.coverage = - typeof opts.coverage === 'undefined' ? true : opts.coverage; - if (opts.coverage) { - _blanket._bindStartTestRunner(opts.bindEvent, function() { - _blanket._loadSourceFiles(function() { - var allLoaded = function() { - return opts.condition - ? opts.condition() - : _blanket.requireFilesLoaded(); - }; - var check = function() { - if (allLoaded()) { - if (_blanket.options('debug')) { - console.log( - 'BLANKET-All files loaded, init start test runner callback.' - ); - } - var cb = _blanket.options('testReadyCallback'); - - if (cb) { - if (typeof cb === 'function') { - cb(opts.callback); - } else if (typeof cb === 'string') { - _blanket._addScript(cb); - opts.callback(); - } - } else { - opts.callback(); - } - } else { - setTimeout(check, 13); - } - }; - check(); - }); - }); - } else { - opts.callback(); - } - }, - utils: { - qualifyURL: function(url) { - //http://stackoverflow.com/questions/470832/getting-an-absolute-url-from-a-relative-one-ie6-issue - var a = document.createElement('a'); - a.href = url; - return a.href; - }, - }, - }); -})(blanket); - -blanket.defaultReporter = function(coverage) { - var cssSytle = - "#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;} #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-inline-start:50px; width:150px; float:right} .bl-nb {padding-inline-end:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:yellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}", - successRate = 60, - head = document.head, - fileNumber = 0, - body = document.body, - headerContent, - hasBranchTracking = Object.keys(coverage.files).some(function(elem) { - return typeof coverage.files[elem].branchData !== 'undefined'; - }), - bodyContent = - "
results
Coverage (%)
Covered/Total Smts.
" + - (hasBranchTracking - ? "
Covered/Total Branches
" - : '') + - "
", - fileTemplate = - "
{{fileNumber}}.{{file}}
{{percentage}} %
{{numberCovered}}/{{totalSmts}}
" + - (hasBranchTracking - ? "
{{passedBranches}}/{{totalBranches}}
" - : '') + - "
"; - grandTotalTemplate = - "
{{rowTitle}}
{{percentage}} %
{{numberCovered}}/{{totalSmts}}
" + - (hasBranchTracking - ? "
{{passedBranches}}/{{totalBranches}}
" - : '') + - "
"; - - function blanket_toggleSource(id) { - var element = document.getElementById(id); - if (element.style.display === 'block') { - element.style.display = 'none'; - } else { - element.style.display = 'block'; - } - } - - /*var script = document.createElement("script"); - script.type = "text/javascript"; - script.text = blanket_toggleSource.toString().replace('function ' + blanket_toggleSource.name, 'function blanket_toggleSource'); - body.appendChild(script);*/ - (1, eval)( - blanket_toggleSource - .toString() - .replace( - 'function ' + blanket_toggleSource.name, - 'function blanket_toggleSource' - ) - ); - - var percentage = function(number, total) { - return Math.round(number / total * 100 * 100) / 100; - }; - - var appendTag = function(type, el, str) { - var dom = document.createElement(type); - dom.innerHTML = str; - el.appendChild(dom); - }; - - function escapeInvalidXmlChars(str) { - return str - .replace(/\&/g, '&') - .replace(//g, '>') - .replace(/\"/g, '"') - .replace(/\'/g, '''); - } - - function isBranchFollowed(data, bool) { - var mode = bool ? 0 : 1; - if ( - typeof data === 'undefined' || - typeof data === null || - typeof data[mode] === 'undefined' - ) { - return false; - } - return data[mode].length > 0; - } - - var branchStack = []; - - function branchReport(colsIndex, src, cols, offset, lineNum) { - var newsrc = ''; - var postfix = ''; - if (branchStack.length > 0) { - newsrc += - ""; - if (branchStack[0][0].end.line === lineNum) { - newsrc += - escapeInvalidXmlChars(src.slice(0, branchStack[0][0].end.column)) + - ''; - src = src.slice(branchStack[0][0].end.column); - branchStack.shift(); - if (branchStack.length > 0) { - newsrc += - ""; - if (branchStack[0][0].end.line === lineNum) { - newsrc += - escapeInvalidXmlChars( - src.slice(0, branchStack[0][0].end.column) - ) + ''; - src = src.slice(branchStack[0][0].end.column); - branchStack.shift(); - if (!cols) { - return { src: newsrc + escapeInvalidXmlChars(src), cols: cols }; - } - } else if (!cols) { - return { - src: newsrc + escapeInvalidXmlChars(src) + '', - cols: cols, - }; - } else { - postfix = ''; - } - } else if (!cols) { - return { src: newsrc + escapeInvalidXmlChars(src), cols: cols }; - } - } else if (!cols) { - return { - src: newsrc + escapeInvalidXmlChars(src) + '', - cols: cols, - }; - } else { - postfix = ''; - } - } - var thisline = cols[colsIndex]; - //consequent - - var cons = thisline.consequent; - if (cons.start.line > lineNum) { - branchStack.unshift([thisline.alternate, thisline]); - branchStack.unshift([cons, thisline]); - src = escapeInvalidXmlChars(src); - } else { - var style = - ""; - newsrc += - escapeInvalidXmlChars(src.slice(0, cons.start.column - offset)) + style; - - if ( - cols.length > colsIndex + 1 && - cols[colsIndex + 1].consequent.start.line === lineNum && - cols[colsIndex + 1].consequent.start.column - offset < - cols[colsIndex].consequent.end.column - offset - ) { - var res = branchReport( - colsIndex + 1, - src.slice(cons.start.column - offset, cons.end.column - offset), - cols, - cons.start.column - offset, - lineNum - ); - newsrc += res.src; - cols = res.cols; - cols[colsIndex + 1] = cols[colsIndex + 2]; - cols.length--; - } else { - newsrc += escapeInvalidXmlChars( - src.slice(cons.start.column - offset, cons.end.column - offset) - ); - } - newsrc += ''; - - var alt = thisline.alternate; - if (alt.start.line > lineNum) { - newsrc += escapeInvalidXmlChars(src.slice(cons.end.column - offset)); - branchStack.unshift([alt, thisline]); - } else { - newsrc += escapeInvalidXmlChars( - src.slice(cons.end.column - offset, alt.start.column - offset) - ); - style = - ""; - newsrc += style; - if ( - cols.length > colsIndex + 1 && - cols[colsIndex + 1].consequent.start.line === lineNum && - cols[colsIndex + 1].consequent.start.column - offset < - cols[colsIndex].alternate.end.column - offset - ) { - var res2 = branchReport( - colsIndex + 1, - src.slice(alt.start.column - offset, alt.end.column - offset), - cols, - alt.start.column - offset, - lineNum - ); - newsrc += res2.src; - cols = res2.cols; - cols[colsIndex + 1] = cols[colsIndex + 2]; - cols.length--; - } else { - newsrc += escapeInvalidXmlChars( - src.slice(alt.start.column - offset, alt.end.column - offset) - ); - } - newsrc += ''; - newsrc += escapeInvalidXmlChars(src.slice(alt.end.column - offset)); - src = newsrc; - } - } - return { src: src + postfix, cols: cols }; - } - - var isUndefined = function(item) { - return typeof item !== 'undefined'; - }; - - var files = coverage.files; - var totals = { - totalSmts: 0, - numberOfFilesCovered: 0, - passedBranches: 0, - totalBranches: 0, - moduleTotalStatements: {}, - moduleTotalCoveredStatements: {}, - moduleTotalBranches: {}, - moduleTotalCoveredBranches: {}, - }; - - // check if a data-cover-modulepattern was provided for per-module coverage reporting - var modulePattern = _blanket.options('modulePattern'); - var modulePatternRegex = modulePattern ? new RegExp(modulePattern) : null; - - for (var file in files) { - if (!files.hasOwnProperty(file)) { - continue; - } - - fileNumber++; - - var statsForFile = files[file], - totalSmts = 0, - numberOfFilesCovered = 0, - code = [], - i; - - var end = []; - for (i = 0; i < statsForFile.source.length; i += 1) { - var src = statsForFile.source[i]; - - if ( - branchStack.length > 0 || - typeof statsForFile.branchData !== 'undefined' - ) { - if (typeof statsForFile.branchData[i + 1] !== 'undefined') { - var cols = statsForFile.branchData[i + 1].filter(isUndefined); - var colsIndex = 0; - - src = branchReport(colsIndex, src, cols, 0, i + 1).src; - } else if (branchStack.length) { - src = branchReport(0, src, null, 0, i + 1).src; - } else { - src = escapeInvalidXmlChars(src); - } - } else { - src = escapeInvalidXmlChars(src); - } - var lineClass = ''; - if (statsForFile[i + 1]) { - numberOfFilesCovered += 1; - totalSmts += 1; - lineClass = 'hit'; - } else { - if (statsForFile[i + 1] === 0) { - totalSmts++; - lineClass = 'miss'; - } - } - code[i + 1] = - "
" + - (i + 1) + - '' + - src + - '
'; - } - totals.totalSmts += totalSmts; - totals.numberOfFilesCovered += numberOfFilesCovered; - var totalBranches = 0; - var passedBranches = 0; - if (typeof statsForFile.branchData !== 'undefined') { - for (var j = 0; j < statsForFile.branchData.length; j++) { - if (typeof statsForFile.branchData[j] !== 'undefined') { - for (var k = 0; k < statsForFile.branchData[j].length; k++) { - if (typeof statsForFile.branchData[j][k] !== 'undefined') { - totalBranches++; - if ( - typeof statsForFile.branchData[j][k][0] !== 'undefined' && - statsForFile.branchData[j][k][0].length > 0 && - typeof statsForFile.branchData[j][k][1] !== 'undefined' && - statsForFile.branchData[j][k][1].length > 0 - ) { - passedBranches++; - } - } - } - } - } - } - totals.passedBranches += passedBranches; - totals.totalBranches += totalBranches; - - // if "data-cover-modulepattern" was provided, - // track totals per module name as well as globally - if (modulePatternRegex) { - var moduleName = file.match(modulePatternRegex)[1]; - - if (!totals.moduleTotalStatements.hasOwnProperty(moduleName)) { - totals.moduleTotalStatements[moduleName] = 0; - totals.moduleTotalCoveredStatements[moduleName] = 0; - } - - totals.moduleTotalStatements[moduleName] += totalSmts; - totals.moduleTotalCoveredStatements[moduleName] += numberOfFilesCovered; - - if (!totals.moduleTotalBranches.hasOwnProperty(moduleName)) { - totals.moduleTotalBranches[moduleName] = 0; - totals.moduleTotalCoveredBranches[moduleName] = 0; - } - - totals.moduleTotalBranches[moduleName] += totalBranches; - totals.moduleTotalCoveredBranches[moduleName] += passedBranches; - } - - var result = percentage(numberOfFilesCovered, totalSmts); - - var output = fileTemplate - .replace('{{file}}', file) - .replace('{{percentage}}', result) - .replace('{{numberCovered}}', numberOfFilesCovered) - .replace(/\{\{fileNumber\}\}/g, fileNumber) - .replace('{{totalSmts}}', totalSmts) - .replace('{{totalBranches}}', totalBranches) - .replace('{{passedBranches}}', passedBranches) - .replace('{{source}}', code.join(' ')); - if (result < successRate) { - output = output.replace('{{statusclass}}', 'bl-error'); - } else { - output = output.replace('{{statusclass}}', 'bl-success'); - } - bodyContent += output; - } - - // create temporary function for use by the global totals reporter, - // as well as the per-module totals reporter - var createAggregateTotal = function( - numSt, - numCov, - numBranch, - numCovBr, - moduleName - ) { - var totalPercent = percentage(numCov, numSt); - var statusClass = totalPercent < successRate ? 'bl-error' : 'bl-success'; - var rowTitle = moduleName - ? 'Total for module: ' + moduleName - : 'Global total'; - var totalsOutput = grandTotalTemplate - .replace('{{rowTitle}}', rowTitle) - .replace('{{percentage}}', totalPercent) - .replace('{{numberCovered}}', numCov) - .replace('{{totalSmts}}', numSt) - .replace('{{passedBranches}}', numCovBr) - .replace('{{totalBranches}}', numBranch) - .replace('{{statusclass}}', statusClass); - - bodyContent += totalsOutput; - }; - - // if "data-cover-modulepattern" was provided, - // output the per-module totals alongside the global totals - if (modulePatternRegex) { - for (var thisModuleName in totals.moduleTotalStatements) { - if (totals.moduleTotalStatements.hasOwnProperty(thisModuleName)) { - var moduleTotalSt = totals.moduleTotalStatements[thisModuleName]; - var moduleTotalCovSt = - totals.moduleTotalCoveredStatements[thisModuleName]; - - var moduleTotalBr = totals.moduleTotalBranches[thisModuleName]; - var moduleTotalCovBr = - totals.moduleTotalCoveredBranches[thisModuleName]; - - createAggregateTotal( - moduleTotalSt, - moduleTotalCovSt, - moduleTotalBr, - moduleTotalCovBr, - thisModuleName - ); - } - } - } - - createAggregateTotal( - totals.totalSmts, - totals.numberOfFilesCovered, - totals.totalBranches, - totals.passedBranches, - null - ); - bodyContent += '
'; //closing main - - appendTag('style', head, cssSytle); - //appendStyle(body, headerContent); - if (document.getElementById('blanket-main')) { - document.getElementById('blanket-main').innerHTML = bodyContent.slice( - 23, - -6 - ); - } else { - appendTag('div', body, bodyContent); - } - - fileNumber = 0; - for (var file in files) { - if (!files.hasOwnProperty(file)) { - continue; - } - - fileNumber++; - var _ = (function() { - var localFN = fileNumber; - $('#blanket-link-file-' + fileNumber).click(function() { - blanket_toggleSource('file-' + localFN); - }); - })(); - } - - //appendHtml(body, ''); -}; - -(function() { - var newOptions = {}; - //http://stackoverflow.com/a/2954896 - var toArray = Array.prototype.slice; - var scripts = toArray.call(document.scripts); - toArray.call(scripts[scripts.length - 1].attributes).forEach(function(es) { - if (es.nodeName === 'data-cover-only') { - newOptions.filter = es.nodeValue; - } - if (es.nodeName === 'data-cover-never') { - newOptions.antifilter = es.nodeValue; - } - if (es.nodeName === 'data-cover-reporter') { - newOptions.reporter = es.nodeValue; - } - if (es.nodeName === 'data-cover-adapter') { - newOptions.adapter = es.nodeValue; - } - if (es.nodeName === 'data-cover-loader') { - newOptions.loader = es.nodeValue; - } - if (es.nodeName === 'data-cover-timeout') { - newOptions.timeout = es.nodeValue; - } - if (es.nodeName === 'data-cover-modulepattern') { - newOptions.modulePattern = es.nodeValue; - } - if (es.nodeName === 'data-cover-reporter-options') { - try { - newOptions.reporter_options = JSON.parse(es.nodeValue); - } catch (e) { - if (blanket.options('debug')) { - throw new Error( - 'Invalid reporter options. Must be a valid stringified JSON object.' - ); - } - } - } - if (es.nodeName === 'data-cover-testReadyCallback') { - newOptions.testReadyCallback = es.nodeValue; - } - if (es.nodeName === 'data-cover-customVariable') { - newOptions.customVariable = es.nodeValue; - } - if (es.nodeName === 'data-cover-flags') { - var flags = ' ' + es.nodeValue + ' '; - if (flags.indexOf(' ignoreError ') > -1) { - newOptions.ignoreScriptError = true; - } - if (flags.indexOf(' autoStart ') > -1) { - newOptions.autoStart = true; - } - if (flags.indexOf(' ignoreCors ') > -1) { - newOptions.ignoreCors = true; - } - if (flags.indexOf(' branchTracking ') > -1) { - newOptions.branchTracking = true; - } - if (flags.indexOf(' sourceURL ') > -1) { - newOptions.sourceURL = true; - } - if (flags.indexOf(' debug ') > -1) { - newOptions.debug = true; - } - if (flags.indexOf(' engineOnly ') > -1) { - newOptions.engineOnly = true; - } - if (flags.indexOf(' commonJS ') > -1) { - newOptions.commonJS = true; - } - if (flags.indexOf(' instrumentCache ') > -1) { - newOptions.instrumentCache = true; - } - } - }); - blanket.options(newOptions); - - if (typeof requirejs !== 'undefined') { - blanket.options('existingRequireJS', true); - } - /* setup requirejs loader, if needed */ - - if (blanket.options('commonJS')) { - blanket._commonjs = {}; - } -})(); -(function(_blanket) { - _blanket.extend({ - utils: { - normalizeBackslashes: function(str) { - return str.replace(/\\/g, '/'); - }, - matchPatternAttribute: function(filename, pattern) { - if (typeof pattern === 'string') { - if (pattern.indexOf('[') === 0) { - //treat as array - var pattenArr = pattern.slice(1, pattern.length - 1).split(','); - return pattenArr.some(function(elem) { - return _blanket.utils.matchPatternAttribute( - filename, - _blanket.utils.normalizeBackslashes(elem.slice(1, -1)) - ); - //return filename.indexOf(_blanket.utils.normalizeBackslashes(elem.slice(1,-1))) > -1; - }); - } else if (pattern.indexOf('//') === 0) { - var ex = pattern.slice(2, pattern.lastIndexOf('/')); - var mods = pattern.slice(pattern.lastIndexOf('/') + 1); - var regex = new RegExp(ex, mods); - return regex.test(filename); - } else if (pattern.indexOf('#') === 0) { - return window[pattern.slice(1)].call(window, filename); - } else { - return ( - filename.indexOf(_blanket.utils.normalizeBackslashes(pattern)) > - -1 - ); - } - } else if (pattern instanceof Array) { - return pattern.some(function(elem) { - return _blanket.utils.matchPatternAttribute(filename, elem); - }); - } else if (pattern instanceof RegExp) { - return pattern.test(filename); - } else if (typeof pattern === 'function') { - return pattern.call(window, filename); - } - }, - blanketEval: function(data) { - _blanket._addScript(data); - }, - collectPageScripts: function() { - var toArray = Array.prototype.slice; - var scripts = toArray.call(document.scripts); - var selectedScripts = [], - scriptNames = []; - var filter = _blanket.options('filter'); - if (filter != null) { - //global filter in place, data-cover-only - var antimatch = _blanket.options('antifilter'); - selectedScripts = toArray.call(document.scripts).filter(function(s) { - return ( - toArray.call(s.attributes).filter(function(sn) { - return ( - sn.nodeName === 'src' && - _blanket.utils.matchPatternAttribute(sn.nodeValue, filter) && - (typeof antimatch === 'undefined' || - !_blanket.utils.matchPatternAttribute( - sn.nodeValue, - antimatch - )) - ); - }).length === 1 - ); - }); - } else { - selectedScripts = toArray.call( - document.querySelectorAll('script[data-cover]') - ); - } - scriptNames = selectedScripts.map(function(s) { - return _blanket.utils.qualifyURL( - toArray.call(s.attributes).filter(function(sn) { - return sn.nodeName === 'src'; - })[0].nodeValue - ); - }); - if (!filter) { - _blanket.options('filter', "['" + scriptNames.join("','") + "']"); - } - return scriptNames; - }, - loadAll: function(nextScript, cb, preprocessor) { - /** - * load dependencies - * @param {nextScript} factory for priority level - * @param {cb} the done callback - */ - var currScript = nextScript(); - var isLoaded = _blanket.utils.scriptIsLoaded( - currScript, - _blanket.utils.ifOrdered, - nextScript, - cb - ); - - if ( - !( - _blanket.utils.cache[currScript] && - _blanket.utils.cache[currScript].loaded - ) - ) { - var attach = function() { - if (_blanket.options('debug')) { - console.log( - 'BLANKET-Mark script:' + - currScript + - ', as loaded and move to next script.' - ); - } - isLoaded(); - }; - var whenDone = function(result) { - if (_blanket.options('debug')) { - console.log('BLANKET-File loading finished'); - } - if (typeof result !== 'undefined') { - if (_blanket.options('debug')) { - console.log('BLANKET-Add file to DOM.'); - } - _blanket._addScript(result); - } - attach(); - }; - - _blanket.utils.attachScript( - { - url: currScript, - }, - function(content) { - _blanket.utils.processFile( - content, - currScript, - whenDone, - whenDone - ); - } - ); - } else { - isLoaded(); - } - }, - attachScript: function(options, cb) { - var timeout = _blanket.options('timeout') || 3000; - setTimeout(function() { - if (!_blanket.utils.cache[options.url].loaded) { - throw new Error('error loading source script'); - } - }, timeout); - _blanket.utils.getFile(options.url, cb, function() { - throw new Error('error loading source script'); - }); - }, - ifOrdered: function(nextScript, cb) { - /** - * ordered loading callback - * @param {nextScript} factory for priority level - * @param {cb} the done callback - */ - var currScript = nextScript(true); - if (currScript) { - _blanket.utils.loadAll(nextScript, cb); - } else { - cb(new Error('Error in loading chain.')); - } - }, - scriptIsLoaded: function(url, orderedCb, nextScript, cb) { - /** - * returns a callback that checks a loading list to see if a script is loaded. - * @param {orderedCb} callback if ordered loading is being done - * @param {nextScript} factory for next priority level - * @param {cb} the done callback - */ - if (_blanket.options('debug')) { - console.log('BLANKET-Returning function'); - } - return function() { - if (_blanket.options('debug')) { - console.log('BLANKET-Marking file as loaded: ' + url); - } - - _blanket.utils.cache[url].loaded = true; - - if (_blanket.utils.allLoaded()) { - if (_blanket.options('debug')) { - console.log('BLANKET-All files loaded'); - } - cb(); - } else if (orderedCb) { - //if it's ordered we need to - //traverse down to the next - //priority level - if (_blanket.options('debug')) { - console.log('BLANKET-Load next file.'); - } - orderedCb(nextScript, cb); - } - }; - }, - cache: {}, - allLoaded: function() { - /** - * check if depdencies are loaded in cache - */ - var cached = Object.keys(_blanket.utils.cache); - for (var i = 0; i < cached.length; i++) { - if (!_blanket.utils.cache[cached[i]].loaded) { - return false; - } - } - return true; - }, - processFile: function(content, url, cb, oldCb) { - var match = _blanket.options('filter'); - //we check the never matches first - var antimatch = _blanket.options('antifilter'); - if ( - typeof antimatch !== 'undefined' && - _blanket.utils.matchPatternAttribute(url, antimatch) - ) { - oldCb(content); - if (_blanket.options('debug')) { - console.log('BLANKET-File will never be instrumented:' + url); - } - _blanket.requiringFile(url, true); - } else if (_blanket.utils.matchPatternAttribute(url, match)) { - if (_blanket.options('debug')) { - console.log('BLANKET-Attempting instrument of:' + url); - } - _blanket.instrument( - { - inputFile: content, - inputFileName: url, - }, - function(instrumented) { - try { - if (_blanket.options('debug')) { - console.log( - 'BLANKET-instrument of:' + url + ' was successfull.' - ); - } - _blanket.utils.blanketEval(instrumented); - cb(); - _blanket.requiringFile(url, true); - } catch (err) { - if (_blanket.options('ignoreScriptError')) { - //we can continue like normal if - //we're ignoring script errors, - //but otherwise we don't want - //to completeLoad or the error might be - //missed. - if (_blanket.options('debug')) { - console.log( - 'BLANKET-There was an error loading the file:' + url - ); - } - cb(content); - _blanket.requiringFile(url, true); - } else { - throw new Error('Error parsing instrumented code: ' + err); - } - } - } - ); - } else { - if (_blanket.options('debug')) { - console.log( - 'BLANKET-Loading (without instrumenting) the file:' + url - ); - } - oldCb(content); - _blanket.requiringFile(url, true); - } - }, - cacheXhrConstructor: function() { - var Constructor, createXhr, i, progId; - if (typeof XMLHttpRequest !== 'undefined') { - Constructor = XMLHttpRequest; - this.createXhr = function() { - return new Constructor(); - }; - } else if (typeof ActiveXObject !== 'undefined') { - Constructor = ActiveXObject; - for (i = 0; i < 3; i += 1) { - progId = progIds[i]; - try { - new ActiveXObject(progId); - break; - } catch (e) {} - } - this.createXhr = function() { - return new Constructor(progId); - }; - } - }, - craeteXhr: function() { - throw new Error( - 'cacheXhrConstructor is supposed to overwrite this function.' - ); - }, - getFile: function(url, callback, errback, onXhr) { - var foundInSession = false; - if (_blanket.blanketSession) { - var files = Object.keys(_blanket.blanketSession); - for (var i = 0; i < files.length; i++) { - var key = files[i]; - if (url.indexOf(key) > -1) { - callback(_blanket.blanketSession[key]); - foundInSession = true; - return; - } - } - } - if (!foundInSession) { - var xhr = _blanket.utils.createXhr(); - xhr.open('GET', url, true); - - //Allow overrides specified in config - if (onXhr) { - onXhr(xhr, url); - } - - xhr.onreadystatechange = function(evt) { - var status, err; - - //Do not explicitly handle errors, those should be - //visible via console output in the browser. - if (xhr.readyState === 4) { - status = xhr.status; - if ( - status > 399 && - status < - 600 /*|| - (status === 0 && - navigator.userAgent.toLowerCase().indexOf('firefox') > -1) - */ - ) { - //An http 4xx or 5xx error. Signal an error. - err = new Error(url + ' HTTP status: ' + status); - err.xhr = xhr; - errback(err); - } else { - callback(xhr.responseText); - } - } - }; - try { - xhr.send(null); - } catch (e) { - if ( - e.code && - (e.code === 101 || e.code === 1012) && - _blanket.options('ignoreCors') === false - ) { - //running locally and getting error from browser - _blanket.showManualLoader(); - } else { - throw e; - } - } - } - }, - }, - }); - - (function() { - var require = blanket.options('commonJS') - ? blanket._commonjs.require - : window.require; - var requirejs = blanket.options('commonJS') - ? blanket._commonjs.requirejs - : window.requirejs; - if ( - !_blanket.options('engineOnly') && - _blanket.options('existingRequireJS') - ) { - _blanket.utils.oldloader = requirejs.load; - - requirejs.load = function(context, moduleName, url) { - _blanket.requiringFile(url); - _blanket.utils.getFile( - url, - function(content) { - _blanket.utils.processFile( - content, - url, - function newLoader() { - context.completeLoad(moduleName); - }, - function oldLoader() { - _blanket.utils.oldloader(context, moduleName, url); - } - ); - }, - function(err) { - _blanket.requiringFile(); - throw err; - } - ); - }; - } - // Save the XHR constructor, just in case frameworks like Sinon would sandbox it. - _blanket.utils.cacheXhrConstructor(); - })(); -})(blanket); - -(function() { - if (!mocha) { - throw new Exception('mocha library does not exist in global namespace!'); - } - - /* - * Mocha Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - */ - - var OriginalReporter = mocha._reporter; - - var BlanketReporter = function(runner) { - runner.on('start', function() { - blanket.setupCoverage(); - }); - - runner.on('end', function() { - blanket.onTestsDone(); - }); - - runner.on('suite', function() { - blanket.onModuleStart(); - }); - - runner.on('test', function() { - blanket.onTestStart(); - }); - - runner.on('test end', function(test) { - blanket.onTestDone(test.parent.tests.length, test.state === 'passed'); - }); - - // NOTE: this is an instance of BlanketReporter - new OriginalReporter(runner); - }; - - BlanketReporter.prototype = OriginalReporter.prototype; - - mocha.reporter(BlanketReporter); - - var oldRun = mocha.run, - oldCallback = null; - - mocha.run = function(finishCallback) { - oldCallback = finishCallback; - console.log('waiting for blanket...'); - }; - blanket.beforeStartTestRunner({ - callback: function() { - if (!blanket.options('existingRequireJS')) { - oldRun(oldCallback); - } - mocha.run = oldRun; - }, - }); -})(); diff --git a/test/crypto_test.js b/test/crypto_test.js deleted file mode 100644 index 19b128c72..000000000 --- a/test/crypto_test.js +++ /dev/null @@ -1,112 +0,0 @@ -/* global Signal, textsecure, libsignal */ - -'use strict'; - -describe('Crypto', () => { - describe('symmetric encryption', () => { - it('roundtrips', async () => { - const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); - const key = textsecure.crypto.getRandomBytes(32); - - const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - const decrypted = await Signal.Crypto.decryptSymmetric(key, encrypted); - - const equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted); - if (!equal) { - throw new Error('The output and input did not match!'); - } - }); - - it('roundtrip fails if nonce is modified', async () => { - const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); - const key = textsecure.crypto.getRandomBytes(32); - - const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - const uintArray = new Uint8Array(encrypted); - uintArray[2] += 2; - - try { - await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); - } catch (error) { - assert.strictEqual( - error.message, - 'decryptSymmetric: Failed to decrypt; MAC verification failed' - ); - return; - } - - throw new Error('Expected error to be thrown'); - }); - - it('roundtrip fails if mac is modified', async () => { - const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); - const key = textsecure.crypto.getRandomBytes(32); - - const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - const uintArray = new Uint8Array(encrypted); - uintArray[uintArray.length - 3] += 2; - - try { - await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); - } catch (error) { - assert.strictEqual( - error.message, - 'decryptSymmetric: Failed to decrypt; MAC verification failed' - ); - return; - } - - throw new Error('Expected error to be thrown'); - }); - - it('roundtrip fails if encrypted contents are modified', async () => { - const message = 'this is my message'; - const plaintext = dcodeIO.ByteBuffer.wrap(message, 'binary').toArrayBuffer(); - const key = textsecure.crypto.getRandomBytes(32); - - const encrypted = await Signal.Crypto.encryptSymmetric(key, plaintext); - const uintArray = new Uint8Array(encrypted); - uintArray[35] += 9; - - try { - await Signal.Crypto.decryptSymmetric(key, uintArray.buffer); - } catch (error) { - assert.strictEqual( - error.message, - 'decryptSymmetric: Failed to decrypt; MAC verification failed' - ); - return; - } - - throw new Error('Expected error to be thrown'); - }); - }); - - describe('attachment encryption', () => { - it('roundtrips', async () => { - const staticKeyPair = await libsignal.KeyHelper.generateIdentityKeyPair(); - const message = 'this is my message'; - const plaintext = Signal.Crypto.bytesFromString(message); - const path = 'fa/facdf99c22945b1c9393345599a276f4b36ad7ccdc8c2467f5441b742c2d11fa'; - - const encrypted = await Signal.Crypto.encryptAttachment( - staticKeyPair.pubKey.slice(1), - path, - plaintext - ); - const decrypted = await Signal.Crypto.decryptAttachment( - staticKeyPair.privKey, - path, - encrypted - ); - - const equal = Signal.Crypto.constantTimeEqual(plaintext, decrypted); - if (!equal) { - throw new Error('The output and input did not match!'); - } - }); - }); -}); diff --git a/test/database_test.js b/test/database_test.js deleted file mode 100644 index bd75b7c0a..000000000 --- a/test/database_test.js +++ /dev/null @@ -1,36 +0,0 @@ -/* global Whisper */ - -'use strict'; - -describe('Database', () => { - describe('handleDOMException', () => { - it('handles null, still calls reject', () => { - let called = 0; - const reject = () => { - called += 1; - }; - const error = null; - const prefix = 'something'; - - Whisper.Database.handleDOMException(prefix, error, reject); - - assert.strictEqual(called, 1); - }); - - it('handles object code and message', () => { - let called = 0; - const reject = () => { - called += 1; - }; - const error = { - code: 4, - message: 'some cryptic error', - }; - const prefix = 'something'; - - Whisper.Database.handleDOMException(prefix, error, reject); - - assert.strictEqual(called, 1); - }); - }); -}); diff --git a/test/fixtures.js b/test/fixtures.js deleted file mode 100644 index 28bf135e5..000000000 --- a/test/fixtures.js +++ /dev/null @@ -1,2719 +0,0 @@ -/* global Whisper */ - -Whisper.Fixtures = () => { - const VERA_ID = '0501cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // nsa - const NESTOR_ID = '0502cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // cia - const MASHA_ID = '0503cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // gchq - const FRED_ID = '0504cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // fbi sf - const MICHEL_ID = '0505cd123456789abcdef05123456789abcdef05123456789abcdef05123456789'; // twh - - const now = Date.now(); - const conversationCollection = new window.models.Conversation.ConversationCollection([ - { - name: 'Vera Zasulich', - id: VERA_ID, - type: 'private', - active_at: now - 10000000, - timestamp: now - 10000000, - lastMessage: 'My piece for Iskra is ready!', - }, - { - name: 'Nestor Mahkno', - type: 'private', - active_at: now - 1000000000, - timestamp: now - 1000000000, - id: NESTOR_ID, - lastMessage: 'Need a ride?', - }, - { - name: 'Friedrich Nietzsche', - type: 'private', - active_at: now - 500000000, - timestamp: now - 500000000, - id: FRED_ID, - lastMessage: - 'It is my ambition to say in ten sentences what everyone else says in a whole book — what everyone else does not say in a whole book.', - }, - { - name: 'Masha Kolenkina', - type: 'private', - active_at: now - 1, - timestamp: now - 1, - id: MASHA_ID, // gchq - lastMessage: "I can't wait to try it!", - unreadCount: 1, - }, - { - id: MICHEL_ID, - name: 'Michel Foucault', - type: 'private', - active_at: now - 1000000, - timestamp: now - 1000000, - lastMessage: 'The soul is the prison of the body.', - }, - ]); - - const Vera = conversationCollection.get(VERA_ID); - Vera.addSingleMessage( - { - conversationId: VERA_ID, - type: 'incoming', - sent_at: now - 10000000, - received_at: now - 10000000, - body: 'My piece for Iskra is ready!', - } - ); - - const Nestor = conversationCollection.get(NESTOR_ID); - Nestor.addSingleMessage( - { - conversationId: NESTOR_ID, - type: 'incoming', - sent_at: now - 1000000000, - received_at: now - 1000000000, - body: 'Need a ride?', - } - ); - - const Fred = conversationCollection.get(FRED_ID); - Fred.addSingleMessage( - { - conversationId: FRED_ID, - type: 'incoming', - sent_at: now - 500000000, - received_at: now - 500000000, - body: - 'It is my ambition to say in ten sentences what everyone else says in a whole book — what everyone else does not say in a whole book.', - } - ); - - const Michel = conversationCollection.get(MICHEL_ID); - Michel.addSingleMessage( - { - conversationId: MICHEL_ID, - type: 'outgoing', - sent_at: now - 3000000, - received_at: now - 3000000, - attachments: [ - { - contentType: 'image/jpeg', - data: dataURItoBlob(getImage1()), - }, - ], - }); - Michel.addSingleMessage({ - conversationId: MICHEL_ID, - type: 'incoming', - body: 'The soul is the prison of the body.', - sent_at: now - 1000000, - received_at: now - 1000000, - source: MICHEL_ID, - }); - Michel.addSingleMessage( - { - conversationId: MICHEL_ID, - type: 'incoming', - sent_at: now - 2000000, - body: - 'In their opinion I am a dangerous man, since I am a crypto-Marxist.', - received_at: now - 2000000, - source: MICHEL_ID, - }); - - const Masha = conversationCollection.get(MASHA_ID); - Masha.addSingleMessage( - { - date: now - 60000, - type: 'incoming', - source: MASHA_ID, - attachments: [ - { - contentType: 'image/jpeg', - data: dataURItoBlob(getImage2()), - }, - ], - conversationId: MASHA_ID, - sent_at: now - 60000, - received_at: now - 60000, - timestamp: now - 60000, - }); - Masha.addSingleMessage( - { - date: now - 5000, - type: 'outgoing', - body: 'I just installed Signal Desktop!', - conversationId: MASHA_ID, - sent_at: now - 5000, - received_at: now - 5000, - timestamp: now - 5000, - }); - Masha.addSingleMessage({ - date: now - 4000, - type: 'outgoing', - body: - 'Now I can use Signal on my computer, even when my phone is off. 😄 ', - conversationId: MASHA_ID, - sent_at: now - 4000, - received_at: now - 4000, - timestamp: now - 4000, - }); - Masha.addSingleMessage({ - date: now, - type: 'incoming', - source: MASHA_ID, - body: "I can't wait to try it!", - unread: 1, - conversationId: MASHA_ID, - sent_at: now, - received_at: now, - timestamp: now, - }); - - - const group = conversationCollection.add({ - name: '📖 Book Club', - type: 'group', - active_at: now - 100000, - timestamp: now - 100000, - id: '05abcd123456789abcdef05123456789abcdef05123456789abcdef05123456789', - lastMessage: 'See you all there!', - members: [MICHEL_ID, FRED_ID, NESTOR_ID], - }); - group.addSingleMessage( - { - sent_at: now - 60 * 1000 * 30, - received_at: now - 60 * 1000 * 30, - timestamp: now - 60 * 1000 * 30, - type: 'incoming', - body: - 'If you knew when you began a book what you would say at the end, do you think that you would have the courage to write it?', - source: MICHEL_ID, - conversationId: group.id, - }); - group.addSingleMessage( - { - sent_at: now - 60 * 1000 * 20, - received_at: now - 60 * 1000 * 20, - timestamp: now - 60 * 1000 * 20, - type: 'incoming', - body: - 'A book which has a strange knack of seeking out its fellow-revellers and enticing them on to new secret paths and dancing-places.', - source: FRED_ID, - conversationId: group.id, - }); - group.addSingleMessage( - { - sent_at: now - 60 * 1000 * 4, - received_at: now - 60 * 1000 * 4, - timestamp: now - 60 * 1000 * 4, - type: 'incoming', - body: "Let's meet in the library.", - source: NESTOR_ID, - conversationId: group.id, - }); - group.addSingleMessage( - { - sent_at: now - 60 * 1000, - received_at: now - 60 * 1000, - timestamp: now - 60 * 1000, - type: 'incoming', - body: "I'll be a little late.", - source: NESTOR_ID, - conversationId: group.id, - }); - group.addSingleMessage( - { - sent_at: now, - received_at: now, - timestamp: now, - type: 'outgoing', - body: 'See you all there!', - recipients: [MICHEL_ID, FRED_ID, NESTOR_ID], - sent_to: [NESTOR_ID], - conversationId: group.id, - }); - - function dataURItoBlob(dataURI) { - const binary = atob(dataURI.split(',')[1]); - const array = []; - for (let i = 0; i < binary.length; i += 1) { - array.push(binary.charCodeAt(i)); - } - return new Uint8Array(array).buffer; - } - - conversationCollection.saveAll = function thisNeeded() { - Promise.all( - this.map(async (convo) => { - await window.Signal.Data.saveConversation(convo.attributes); - - await Promise.all( - convo.messageCollection.map(async (message) => { - const id = await message.commit(); - message.set({ id }); - }) - ); - }) - ); - } - - function getImage1() { - return ( - 'data:image/jpeg;base64,' + - '/9j/4QAqRXhpZgAASUkqAAgAAAABAJiCAgAFAAAAGgAAAAAAAAAgICAgAAAAAP/sABFEdWNreQAB' + - 'AAQAAAA8AAD/4QOdaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49' + - 'Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9' + - 'ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2' + - 'NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0' + - 'cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRp' + - 'b24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAv' + - 'bW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291' + - 'cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpk' + - 'Yz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtcE1NOkRvY3VtZW50SUQ9Inht' + - 'cC5kaWQ6NEEzMzkwN0E5OUQzMTFFNEIzRDI4QTFBM0M2Mzk4MzIiIHhtcE1NOkluc3RhbmNlSUQ9' + - 'InhtcC5paWQ6NEEzMzkwNzk5OUQzMTFFNEIzRDI4QTFBM0M2Mzk4MzIiIHhtcDpDcmVhdG9yVG9v' + - 'bD0iRGlnaXRhbCBDYW1lcmEgWDIwIFZlcjEuMDIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6' + - 'aW5zdGFuY2VJRD0iNzM3N0Y3RjI0MTU4RDg0M0M1QUIzMzY2QzcwOTM0NTQiIHN0UmVmOmRvY3Vt' + - 'ZW50SUQ9IjczNzdGN0YyNDE1OEQ4NDNDNUFCMzM2NkM3MDkzNDU0Ii8+IDxkYzpyaWdodHM+IDxy' + - 'ZGY6QWx0PiA8cmRmOmxpIHhtbDpsYW5nPSJ4LWRlZmF1bHQiPiAgICA8L3JkZjpsaT4gPC9yZGY6' + - 'QWx0PiA8L2RjOnJpZ2h0cz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1l' + - 'dGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7QBQUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAABgcAVoA' + - 'AxslRxwCAAACAAIcAnQABCAgICA4QklNBCUAAAAAABCF+g4zyeKkyI/MF2pb7RQW/+4ADkFkb2Jl' + - 'AGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoKDBAMDAwMDAwQDA4PEA8ODBMT' + - 'FBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8fHx8fHx8fHx8fHx8fHx8fHx8f' + - 'Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgB4AKAAwERAAIRAQMRAf/EAKIAAAIDAQEB' + - 'AQAAAAAAAAAAAAIDAAEEBQYHCAEBAQEBAQEBAAAAAAAAAAAAAAECAwQFBhAAAgEDAgQEBAQFAgYB' + - 'AgUFAQIAEQMEIRIxQVEFYXEiE4GRMgahsUIUwdFSIwfw4fFicoIzFSSiFpKywmNzgzREZCURAQEB' + - 'AQACAgICAgIBBAIDAAABEQISAyExQRNRBGEicTKB8JGhFLFC4SMz/9oADAMBAAIRAxEAPwD8rwJA' + - 'JSRwkUalgarxEg6OHYu3Vdzkpj6EDexFRxPATFv+G5G3tVjs/ru5We6eyQFQEobnL0FQ7fhJ1Kc2' + - 'ORl2xayXVN3t7j7bOCCy10JrNsqAPMU85FEDoB0NYGnE3W7gYNsBPqNKgCZqx11yMK29vKtkX8g1' + - 'W3YZN6gUobjAabq6qOU5+N+r9N7/AA939q/fuRbRrPd7rXrIUC3iqgAIZqeoc6acJ5++P4+nTm/z' + - '9ux3PC7Rk5TZlyzex1KblzfbZrT3EFKHVqHiATOfzZmtbny9b2vMHcex2bqAfubdylpQN7NQCgct' + - 't2OjUIas58+vfhu9Y9Z2LNvX8G6HVkdHZgtFVrgDU3KtdJvn4qX5juox/ZJdQsjDWjAV16iXdqWY' + - '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' - ); - } - - function getImage2() { - return ( - 'data:image/jpeg;base64,' + - '/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK' + - 'CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU' + - 'FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAKAAoADASIA' + - 'AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA' + - 'AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3' + - 'ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm' + - 'p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA' + - 'AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx' + - 'BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK' + - 'U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3' + - 'uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDzqMFh' + - 'lRyOT16Z5/kacsQkYADAIzxzj3qeOEkhyOCMY7gj/wDXT41wig8DoR3r97btqj+aFIreXg7up65O' + - 'evcfqPSlMW7G1ec9umOvXP1q+AAx+UMjcfL1I69f1qNogMAA/J9cZ9h/hUqd9yW+5VRGcDqcn1yO' + - '+cUnk72O3Gck887vx+uatYGdgUKT2XHr1HenKuw88EdBjv61XMHN2I4bRnCn5S5OcHkY9vwzW9DB' + - 'HHAi7QT0PHas1SN55yvXP+e1alvIQgyrYHOQff8AD2rirtsuEk9SaBTDKoHO/ueB7/pXW6DY+VcL' + - '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' - ); - } - - return conversationCollection; -}; diff --git a/test/fixtures_test.js b/test/fixtures_test.js deleted file mode 100644 index bb88cec62..000000000 --- a/test/fixtures_test.js +++ /dev/null @@ -1,34 +0,0 @@ -/* global $, textsecure, Whisper */ - -'use strict'; - -describe('Fixtures', () => { - before(async () => { - // NetworkStatusView checks this method every five seconds while showing - - await clearDatabase(); - await textsecure.storage.user.setNumberAndDeviceId( - '05123456789abcdef05123456789abcdef05123456789abcdef05123456789abcd', - 2, - 'testDevice' - ); - - await window - .getConversationController() - .getOrCreateAndWait(window.libsession.Utils.UserUtils.getOurPubKeyStrFromCache(), 'private'); - }); - - it('renders', async () => { - await Whisper.Fixtures().saveAll(); - - window.getConversationController().reset(); - await window.getConversationController().load(); - - let view = new Whisper.InboxView({ window }); - view.$el.prependTo($('#render-light-theme')); - - view = new Whisper.InboxView({ window }); - view.$el.removeClass('light-theme').addClass('dark-theme'); - view.$el.prependTo($('#render-dark-theme')); - }); -}); diff --git a/test/i18n_test.js b/test/i18n_test.js deleted file mode 100644 index 3698476dd..000000000 --- a/test/i18n_test.js +++ /dev/null @@ -1,27 +0,0 @@ -/* global i18n */ - -describe('i18n', () => { - describe('i18n', () => { - it('returns empty string for unknown string', () => { - assert.strictEqual(i18n('random'), ''); - }); - it('returns message for given string', () => { - assert.equal(i18n('reportIssue'), 'Report an issue'); - }); - it('returns message with single substitution', () => { - const actual = i18n('attemptingReconnection', 5); - assert.equal(actual, 'Attempting reconnect in 5 seconds'); - }); - it('returns message with multiple substitutions', () => { - const actual = i18n('theyChangedTheTimer', ['Someone', '5 minutes']); - assert.equal(actual, 'Someone set the disappearing message timer to 5 minutes'); - }); - }); - - describe('getLocale', () => { - it('returns a string with length two or greater', () => { - const locale = i18n.getLocale(); - assert.isAtLeast(locale.trim().length, 2); - }); - }); -}); diff --git a/test/index.html b/test/index.html deleted file mode 100644 index e0f5e683c..000000000 --- a/test/index.html +++ /dev/null @@ -1,63 +0,0 @@ - - - - - TextSecure test runner - - - - - -
-
-
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/manual.txt b/test/manual.txt deleted file mode 100644 index 052eb80d5..000000000 --- a/test/manual.txt +++ /dev/null @@ -1,51 +0,0 @@ -Manual test script - -Some things are very difficult to test programmatically. Also, if you don't have adequate test coverage, a good first step is a comprehensive manual test script! https://blog.scottnonnenberg.com/web-application-test-strategy/ - -Conversation view: - Last seen indicator: - (dismissed three ways: 1. sending a message 2. switching away from conversation and back again 3. clicking scroll down button when last seen indicator is off-screen above) - - - Switch away from Signal app, but keep it visible - - Receive messages to conversation out of focus, and the last seen indicator should move up the screen with each new message. When the number of new messages can no longer fit on the screen, the last seen indicator should stay at the top of the screen, and new messages will appear below. The scroll down button will turn blue to indicate new messages out of view. - - Switch back to Signal app, and the last seen indicator and scroll down button should stay where they are. - - Click the scroll down button to go to the bottom of the window, and the button should disappear. - - Send a message, then scroll up. The last seen indicator should be gone. - - - Switch to a different conversation, then receive messages on original conversation - - Switch back to original conversation, and the last seen indicator should be visible - - Switch away from conversation and back. The last seen indicator should be gone. - - - Switch to a different conversation, then receive a lot of messages on original conversation - - Switch back to original conversation, and the last seen indicator should be visible, along with the scroll down button. - - Click the scroll down button to be taken to the newest message in the conversation - - - Scroll up on a conversation then switch to another application, keeping the Signal application visible. Receive new messages on that conversation. Switch back to application. The scroll down button should be blue, and the conversation scroll location should stay where it was. There should be a last seen indicator visible above the new messages. - - - Scroll to bottom of a conversation, then switch to another application, keeping Signal application visible. Receive new messages on that conversation. As new messages come in, the last seen indicator should march up the screen. Before it reaches the top, switch back to the application. This will mark those messages as read. Switch away from the application again, and receive new messages. The last seen indicator will scroll off the top of the screen as more and more new messages come in. - - - ADVANCED: Set up an automated script (or friend) to send you repeated messages. You should see the right number of unread upon entry of the conversation, along with with the last seen indicator. While the conversation is focused, new messages should increment the last seen indicator until it is offscreen above. Click the scroll down button to eliminate the last seen indicator, then scroll up. New messages received while scrolled up should not scroll the conversation, but will add a new last seen indicator and scroll down button. - - - ADVANCED: Set fetch limit to a low number, like 3 (in models/messages.js, fetchConversation function). Load the application, and don't select the conversation. Receive more than four new messages in that conversation. Select the conversation. The last seen indicator should reflect the total number of new messages and all of them should be visible. - - Marking messages as unread: - - Switch to a different conversation, then receive lots of messages on original conversation, more than would fill the screen - - Note the count before clicking into the conversation. Count the number of visible messages and ensure that the conversation's unread count is decremented by the right amount. - - Slowly scroll down so that one more message is visible. The conversation unread count should go down by one. - - Click the scroll down button. All messages should be marked read - even if you skipped a couple screens to get to the bottom. - - Scrolling: - - If scrolled to bottom of a conversation, should stay there when a new message comes in - - If scrolled to the middle of a conversation, should stay there when a new message comes in - - When you've scrolled up an entire screen's worth, a scroll down button in the bottom right should appear. - - Scroll-down button: - - Clicking it takes you to the bottom of the conversation, makes the button disappear - - If a new message comes in while it is already showing, it turns blue - - If a new message comes in while not at the bottom of the conversation (but button is not already showing), it should appear, already blue. - - If you've scrolled up higher than the last seen indicator, then clicking the scroll down button should take you to the last seen indicator. Once there, clicking the button will take you to the bottom of the conversation, at which point the button will disappear. - -Electron window locations - - Load app, move and resize window, close app. Start app. Window should be in the same place, with the same size. - - (OSX) Load app, full-screen window, close app. Start app. Window should be full screen. - - (Windows) Load app, maximize window, close app. Start app. Window should be maximized. diff --git a/test/models/conversations_test.js b/test/models/conversations_test.js deleted file mode 100644 index b71c148a7..000000000 --- a/test/models/conversations_test.js +++ /dev/null @@ -1,129 +0,0 @@ -// /* global textsecure, Whisper */ - -// 'use strict'; -// FIXME audric enable back those test -describe('ConversationCollection', () => { - // textsecure.messaging = true; - // before(clearDatabase); - // after(clearDatabase); - // it('should be ordered newest to oldest', () => { - // const conversations = new window.models.Conversation.ConversationCollection(); - // // Timestamps - // const today = new Date(); - // const tomorrow = new Date(); - // tomorrow.setDate(today.getDate() + 1); - // // Add convos - // conversations.add({ active_at: today }); - // conversations.add({ active_at: tomorrow }); - // const { models } = conversations; - // const firstTimestamp = models[0].get('active_at').getTime(); - // const secondTimestamp = models[1].get('active_at').getTime(); - // // Compare timestamps - // assert(firstTimestamp > secondTimestamp); - // }); - // }); - // describe('Conversation', () => { - // const attributes = { - // type: 'private', - // id: '051d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }; - // before(async () => { - // const convo = new window.models.Conversation.ConversationCollection().add(attributes); - // await window.Signal.Data.saveConversation(convo.attributes, { - // Conversation: window.models.Conversation.ConversationModel, - // }); - // // const message = convo.messageCollection.add({ - // // body: 'hello world', - // // conversationId: convo.id, - // // type: 'outgoing', - // // sent_at: Date.now(), - // // received_at: Date.now(), - // // }); - // // await message.commit(false); - // }); - // after(clearDatabase); - // it('contains its own messages', async () => { - // const convo = new window.models.Conversation.ConversationCollection().add({ - // id: '051d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // await convo.fetchMessages(); - // assert.notEqual(convo.messageCollection.length, 0); - // }); - // it('contains only its own messages', async () => { - // const convo = new window.models.Conversation.ConversationCollection().add({ - // id: '052d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // await convo.fetchMessages(); - // assert.strictEqual(convo.messageCollection.length, 0); - // }); - // it('adds conversation to message collection upon leaving group', async () => { - // const convo = new window.models.Conversation.ConversationCollection().add({ - // type: 'group', - // id: '052d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // await convo.leaveClosedGroup(); - // assert.notEqual(convo.messageCollection.length, 0); - // }); - // it('has a title', () => { - // const convos = new window.models.Conversation.ConversationCollection(); - // let convo = convos.add(attributes); - // assert.equal( - // convo.getTitle(), - // '051d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab' - // ); - // convo = convos.add({ type: '' }); - // assert.equal(convo.getTitle(), 'Unknown group'); - // convo = convos.add({ name: 'name' }); - // assert.equal(convo.getTitle(), 'name'); - // }); - // it('returns the number', () => { - // const convos = new window.models.Conversation.ConversationCollection(); - // let convo = convos.add(attributes); - // assert.equal( - // convo.getNumber(), - // '051d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab' - // ); - // convo = convos.add({ type: '' }); - // assert.equal(convo.getNumber(), ''); - // }); - // describe('when set to private', () => { - // it('correctly validates hex numbers', () => { - // const regularId = new window.models.Conversation.ConversationModel({ - // type: 'private', - // id: - // '051d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // const invalidId = new window.models.Conversation.ConversationModel({ - // type: 'private', - // id: - // 'j71d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // assert.ok(regularId.isValid()); - // assert.notOk(invalidId.isValid()); - // }); - // it('correctly validates length', () => { - // const regularId33 = new window.models.Conversation.ConversationModel({ - // type: 'private', - // id: - // '051d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // const regularId32 = new window.models.Conversation.ConversationModel({ - // type: 'private', - // id: '1d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94ab', - // }); - // const shortId = new window.models.Conversation.ConversationModel({ - // type: 'private', - // id: '771d11d', - // }); - // const longId = new window.models.Conversation.ConversationModel({ - // type: 'private', - // id: - // '771d11d01e56d9bfc3d74115c33225a632321b509ac17a13fdeac71165d09b94abaa', - // }); - // assert.ok(regularId33.isValid()); - // assert.ok(regularId32.isValid()); - // assert.notOk(shortId.isValid()); - // assert.notOk(longId.isValid()); - // }); - // }); -}); diff --git a/test/models/messages_test.js b/test/models/messages_test.js deleted file mode 100644 index 3c2ce50af..000000000 --- a/test/models/messages_test.js +++ /dev/null @@ -1,154 +0,0 @@ -'use strict'; - -const attributes = { - type: 'outgoing', - body: 'hi', - conversationId: 'foo', - attachments: [], - received_at: new Date().getTime(), -}; - -const source = '+14155555555'; - -describe('MessageCollection', () => { - before(async () => { - await clearDatabase(); - window.getConversationController().reset(); - window.textsecure.storage.user.getNumber = () => - '051111111111111111111111111111111111111111111111111111111111111111'; - await window.getConversationController().load(); - }); - after(() => { - return clearDatabase(); - }); - - it('gets outgoing contact', () => { - const messages = new window.models.Message.MessageCollection(); - const message = messages.add(attributes); - message.getContact(); - }); - - it('gets incoming contact', () => { - const messages = new window.models.Message.MessageCollection(); - const message = messages.add({ - type: 'incoming', - source, - conversationId: 'conversationId', - }); - message.getContact(); - }); - - it('should be ordered oldest to newest', () => { - const messages = new window.models.Message.MessageCollection(); - // Timestamps - const today = new Date(); - const tomorrow = new Date(); - tomorrow.setDate(today.getDate() + 1); - - // Add threads - messages.add({ received_at: today, conversationId: 'conversationId' }); - messages.add({ received_at: tomorrow, conversationId: 'conversationId' }); - - const { models } = messages; - const firstTimestamp = models[0].get('received_at').getTime(); - const secondTimestamp = models[1].get('received_at').getTime(); - - // Compare timestamps - assert(firstTimestamp < secondTimestamp); - }); - - // it('checks if is incoming message', () => { - // const messages = new window.models.Message.MessageCollection(); - // let message = messages.add(attributes); - // assert.notOk(message.isIncoming()); - // message = messages.add({ - // type: 'incoming', - // conversationId: 'conversationId', - // }); - // assert.ok(message.isIncoming()); - // }); - - // it('checks if is outgoing message', () => { - // const messages = new window.models.Message.MessageCollection(); - // let message = messages.add(attributes); - // assert.ok(message.isOutgoing()); - // message = messages.add({ - // type: 'incoming', - // conversationId: 'conversationId', - // }); - // assert.notOk(message.isOutgoing()); - // }); - - it('checks if is group update', () => { - const messages = new window.models.Message.MessageCollection(); - let message = messages.add(attributes); - assert.notOk(message.isGroupUpdate()); - - message = messages.add({ - group_update: true, - conversationId: 'conversationId', - }); - assert.ok(message.isGroupUpdate()); - }); - - it('returns an accurate description', () => { - const messages = new window.models.Message.MessageCollection(); - let message = messages.add(attributes); - - assert.equal( - message.getDescription(), - 'hi', - 'If no group updates or end session flags, return message body.' - ); - - message = messages.add({ - group_update: { left: 'Alice' }, - conversationId: 'conversationId', - }); - assert.equal( - message.getDescription(), - 'Alice has left the group.', - 'Notes one person leaving the group.' - ); - - message = messages.add({ - group_update: { name: 'blerg' }, - conversationId: 'conversationId', - }); - assert.equal( - message.getDescription(), - "Group name is now 'blerg'.", - 'Returns a single notice if only group_updates.name changes.' - ); - - message = messages.add({ - group_update: { joined: ['Bob'] }, - conversationId: 'conversationId', - }); - assert.equal( - message.getDescription(), - 'Bob joined the group.', - 'Returns a single notice if only group_updates.joined changes.' - ); - - message = messages.add({ - group_update: { joined: ['Bob', 'Alice', 'Eve'] }, - conversationId: 'conversationId', - }); - assert.equal( - message.getDescription(), - 'Bob, Alice, Eve joined the group.', - 'Notes when >1 person joins the group.' - ); - - message = messages.add({ - group_update: { joined: ['Bob'], name: 'blerg' }, - conversationId: 'conversationId', - }); - assert.equal( - message.getDescription(), - "Group name is now 'blerg'. Bob joined the group.", - 'Notes when there are multiple changes to group_updates properties.' - ); - }); -}); diff --git a/test/modules/.eslintrc.js b/test/modules/.eslintrc.js deleted file mode 100644 index eb9d189ca..000000000 --- a/test/modules/.eslintrc.js +++ /dev/null @@ -1,30 +0,0 @@ -// For reference: https://github.com/airbnb/javascript - -module.exports = { - env: { - mocha: true, - browser: true, - }, - - globals: { - check: true, - gen: true, - }, - - parserOptions: { - sourceType: 'module', - }, - - rules: { - // We still get the value of this rule, it just allows for dev deps - 'import/no-extraneous-dependencies': [ - 'error', - { - devDependencies: true, - }, - ], - - // We want to keep each test structured the same, even if its contents are tiny - 'arrow-body-style': 'off', - }, -}; diff --git a/test/modules/privacy_test.js b/test/modules/privacy_test.js deleted file mode 100644 index e8de43d25..000000000 --- a/test/modules/privacy_test.js +++ /dev/null @@ -1,161 +0,0 @@ -const path = require('path'); - -const { assert } = require('chai'); - -const Privacy = require('../../js/modules/privacy'); - -const APP_ROOT_PATH = path.join(__dirname, '..', '..', '..'); - -describe('Privacy', () => { - describe('redactSessionID', () => { - it('should redact all session IDs', () => { - const text = - 'This is a log line with a session ID 0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 and another one 05766049a70e725ad02f7fe61b10e461380a4d7433f98096b3cacbf0362d5cab62'; - - const actual = Privacy.redactSessionID(text); - const expected = 'This is a log line with a session ID [REDACTED] and another one [REDACTED]'; - assert.equal(actual, expected); - }); - - it('should not redact non session IDS', () => { - const text = - 'This is a log line with a non-session ID sadsad0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827888 and another one 766049a70e725ad02f7fe61b10e461380a4d7433f98096b3cacbf0362d5cab6234'; - - const actual = Privacy.redactSessionID(text); - assert.equal(actual, text); - }); - }); - - describe('redactGroupIds', () => { - it('should redact all group IDs', () => { - const text = 'This is a log line with two group IDs: group(123456789) and group(abcdefghij)'; - - const actual = Privacy.redactGroupIds(text); - const expected = - 'This is a log line with two group IDs: group([REDACTED]789) and group([REDACTED]hij)'; - assert.equal(actual, expected); - }); - - it('should remove newlines from redacted group IDs', () => { - const text = - 'This is a log line with two group IDs: group(12345678\n9)\nand group(abc\ndefghij)'; - - const actual = Privacy.redactGroupIds(text); - const expected = - 'This is a log line with two group IDs: group([REDACTED]789)\n' + - 'and group([REDACTED]hij)'; - assert.equal(actual, expected); - }); - }); - - describe('redactAll', () => { - it('should redact all sensitive information', () => { - const encodedAppRootPath = APP_ROOT_PATH.replace(/ /g, '%20'); - const text = - 'This is a log line with sensitive information:\n' + - `path1 ${APP_ROOT_PATH}/main.js\n` + - 'phone1 0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 ipsum\n' + - 'group 31032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 eeee\n' + - 'group1 group(123456789) doloret\n' + - `path2 file:///${encodedAppRootPath}/js/background.js.` + - 'phone2 0531033dc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 lorem\n' + - 'group2 group(abcdefghij) doloret\n' + - 'url1 https://you-have-to-hide.me aaa\n' + - 'url1 http://you-have-to-hide.me bbb\n' + - 'url1 127.0.0.1:22021 ccc\n'; - - const actual = Privacy.redactAll(text); - const expected = - 'This is a log line with sensitive information:\n' + - 'path1 [REDACTED]/main.js\n' + - 'phone1 [REDACTED] ipsum\n' + - 'group [REDACTED] eeee\n' + - 'group1 group([REDACTED]789) doloret\n' + - 'path2 file:///[REDACTED]/js/background.js.' + - 'phone2 [REDACTED] lorem\n' + - 'group2 group([REDACTED]hij) doloret\n' + - 'url1 [REDACTED] aaa\n' + - 'url1 [REDACTED] bbb\n' + - 'url1 [REDACTED]:22021 ccc\n'; - assert.equal(actual, expected); - }); - }); - - describe('_redactPath', () => { - it('should redact file paths', () => { - const testPath = '/Users/meow/Library/Application Support/Signal Beta'; - const text = - 'This is a log line with sensitive information:\n' + - `path1 ${testPath}/main.js\n` + - 'phone1 0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 ipsum\n'; - - const actual = Privacy._redactPath(testPath)(text); - const expected = - 'This is a log line with sensitive information:\n' + - 'path1 [REDACTED]/main.js\n' + - 'phone1 0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 ipsum\n'; - assert.equal(actual, expected); - }); - - it('should redact URL-encoded paths', () => { - const testPath = '/Users/meow/Library/Application Support/Signal Beta'; - const encodedTestPath = encodeURI(testPath); - const text = - 'This is a log line with sensitive information:\n' + - `path1 ${testPath}/main.js\n` + - 'phone1 0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 ipsum\n' + - 'group1 group(123456789) doloret\n' + - `path2 file:///${encodedTestPath}/js/background.js.`; - - const actual = Privacy._redactPath(testPath)(text); - const expected = - 'This is a log line with sensitive information:\n' + - 'path1 [REDACTED]/main.js\n' + - 'phone1 0531032fc7415b7cc1b7516480ad121d391eddce3cfb2cee27dd5b215609c32827 ipsum\n' + - 'group1 group(123456789) doloret\n' + - 'path2 file:///[REDACTED]/js/background.js.'; - assert.equal(actual, expected); - }); - - it('should redact stack traces with both forward and backslashes', () => { - const testPath = 'C:/Users/Meow/AppData/Local/Programs/loki-messenger-beta'; - const modifiedTestPath = 'C:\\Users\\Meow\\AppData\\Local\\Programs\\loki-messenger-beta'; - const text = - 'This is a log line with sensitive information:\n' + - `path1 ${testPath}\\main.js\n` + - 'phone1 +12223334455 ipsum\n' + - 'group1 group(123456789) doloret\n' + - `path2 ${modifiedTestPath}\\js\\background.js.`; - - const actual = Privacy._redactPath(testPath)(text); - const expected = - 'This is a log line with sensitive information:\n' + - 'path1 [REDACTED]\\main.js\n' + - 'phone1 +12223334455 ipsum\n' + - 'group1 group(123456789) doloret\n' + - 'path2 [REDACTED]\\js\\background.js.'; - assert.equal(actual, expected); - }); - - it('should redact stack traces with escaped backslashes', () => { - const testPath = 'C:\\Users\\Meow\\AppData\\Local\\Programs\\loki-messenger-beta'; - const modifiedTestPath = - 'C:\\\\Users\\\\Meow\\\\AppData\\\\Local\\\\Programs\\\\loki-messenger-beta'; - const text = - 'This is a log line with sensitive information:\n' + - `path1 ${testPath}\\main.js\n` + - 'phone1 +12223334455 ipsum\n' + - 'group1 group(123456789) doloret\n' + - `path2 ${modifiedTestPath}\\js\\background.js.`; - - const actual = Privacy._redactPath(testPath)(text); - const expected = - 'This is a log line with sensitive information:\n' + - 'path1 [REDACTED]\\main.js\n' + - 'phone1 +12223334455 ipsum\n' + - 'group1 group(123456789) doloret\n' + - 'path2 [REDACTED]\\js\\background.js.'; - assert.equal(actual, expected); - }); - }); -}); diff --git a/test/modules/types/attachment_test.js b/test/modules/types/attachment_test.js deleted file mode 100644 index e51d93b78..000000000 --- a/test/modules/types/attachment_test.js +++ /dev/null @@ -1,226 +0,0 @@ -require('mocha-testcheck').install(); - -const { assert } = require('chai'); - -const Attachment = require('../../../js/modules/types/attachment'); -const { stringToArrayBuffer } = require('../../../js/modules/string_to_array_buffer'); - -describe('Attachment', () => { - describe('replaceUnicodeOrderOverrides', () => { - it('should sanitize left-to-right order override character', async () => { - const input = { - contentType: 'image/jpeg', - fileName: 'test\u202Dfig.exe', - size: 1111, - }; - const expected = { - contentType: 'image/jpeg', - fileName: 'test\uFFFDfig.exe', - size: 1111, - }; - - const actual = await Attachment.replaceUnicodeOrderOverrides(input); - assert.deepEqual(actual, expected); - }); - - it('should sanitize right-to-left order override character', async () => { - const input = { - contentType: 'image/jpeg', - fileName: 'test\u202Efig.exe', - size: 1111, - }; - const expected = { - contentType: 'image/jpeg', - fileName: 'test\uFFFDfig.exe', - size: 1111, - }; - - const actual = await Attachment.replaceUnicodeOrderOverrides(input); - assert.deepEqual(actual, expected); - }); - - it('should sanitize multiple override characters', async () => { - const input = { - contentType: 'image/jpeg', - fileName: 'test\u202e\u202dlol\u202efig.exe', - size: 1111, - }; - const expected = { - contentType: 'image/jpeg', - fileName: 'test\uFFFD\uFFFDlol\uFFFDfig.exe', - size: 1111, - }; - - const actual = await Attachment.replaceUnicodeOrderOverrides(input); - assert.deepEqual(actual, expected); - }); - - const hasNoUnicodeOrderOverrides = value => - !value.includes('\u202D') && !value.includes('\u202E'); - - check.it( - 'should ignore non-order-override characters', - gen.string.suchThat(hasNoUnicodeOrderOverrides), - fileName => { - const input = { - contentType: 'image/jpeg', - fileName, - size: 1111, - }; - - const actual = Attachment._replaceUnicodeOrderOverridesSync(input); - assert.deepEqual(actual, input); - } - ); - }); - - describe('replaceUnicodeV2', () => { - it('should remove all bad characters', async () => { - const input = { - size: 1111, - fileName: - 'file\u202A\u202B\u202C\u202D\u202E\u2066\u2067\u2068\u2069\u200E\u200F\u061C.jpeg', - }; - const expected = { - fileName: - 'file\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD.jpeg', - size: 1111, - }; - - const actual = await Attachment.replaceUnicodeV2(input); - assert.deepEqual(actual, expected); - }); - - it('should should leave normal filename alone', async () => { - const input = { - fileName: 'normal.jpeg', - size: 1111, - }; - const expected = { - fileName: 'normal.jpeg', - size: 1111, - }; - - const actual = await Attachment.replaceUnicodeV2(input); - assert.deepEqual(actual, expected); - }); - - it('should handle missing fileName', async () => { - const input = { - size: 1111, - }; - const expected = { - size: 1111, - }; - - const actual = await Attachment.replaceUnicodeV2(input); - assert.deepEqual(actual, expected); - }); - }); - - describe('removeSchemaVersion', () => { - it('should remove existing schema version', () => { - const input = { - contentType: 'image/jpeg', - fileName: 'foo.jpg', - size: 1111, - schemaVersion: 1, - }; - - const expected = { - contentType: 'image/jpeg', - fileName: 'foo.jpg', - size: 1111, - }; - - const actual = Attachment.removeSchemaVersion({ - attachment: input, - logger: { - error: () => null, - }, - }); - assert.deepEqual(actual, expected); - }); - }); - - describe('migrateDataToFileSystem', () => { - it('should write data to disk and store relative path to it', async () => { - const input = { - contentType: 'image/jpeg', - data: stringToArrayBuffer('Above us only sky'), - fileName: 'foo.jpg', - size: 1111, - }; - - const expected = { - contentType: 'image/jpeg', - path: 'abc/abcdefgh123456789', - fileName: 'foo.jpg', - size: 1111, - }; - - const expectedAttachmentData = stringToArrayBuffer('Above us only sky'); - const writeNewAttachmentData = async attachmentData => { - assert.deepEqual(attachmentData, expectedAttachmentData); - return 'abc/abcdefgh123456789'; - }; - - const actual = await Attachment.migrateDataToFileSystem(input, { - writeNewAttachmentData, - logger: { - warn: () => null, - }, - }); - assert.deepEqual(actual, expected); - }); - - it('should skip over (invalid) attachments without data', async () => { - const input = { - contentType: 'image/jpeg', - fileName: 'foo.jpg', - size: 1111, - }; - - const expected = { - contentType: 'image/jpeg', - fileName: 'foo.jpg', - size: 1111, - }; - - const writeNewAttachmentData = async () => 'abc/abcdefgh123456789'; - - const actual = await Attachment.migrateDataToFileSystem(input, { - writeNewAttachmentData, - logger: { - warn: () => null, - }, - }); - assert.deepEqual(actual, expected); - }); - - it('should throw error if data is not valid', async () => { - const input = { - contentType: 'image/jpeg', - data: 42, - fileName: 'foo.jpg', - size: 1111, - }; - - const writeNewAttachmentData = async () => 'abc/abcdefgh123456789'; - - try { - await Attachment.migrateDataToFileSystem(input, { - writeNewAttachmentData, - logger: { - warn: () => null, - }, - }); - } catch (error) { - assert.strictEqual(error.message, 'Expected 42 to be an array buffer got: number'); - return; - } - - assert.fail('Unreachable'); - }); - }); -}); diff --git a/test/modules/types/errors_test.js b/test/modules/types/errors_test.js deleted file mode 100644 index ef37acbf0..000000000 --- a/test/modules/types/errors_test.js +++ /dev/null @@ -1,37 +0,0 @@ -const Path = require('path'); - -const { assert } = require('chai'); - -const Errors = require('../../../js/modules/types/errors'); - -const APP_ROOT_PATH = Path.join(__dirname, '..', '..', '..'); - -describe('Errors', () => { - describe('toLogFormat', () => { - it('should return error stack trace if present', () => { - const error = new Error('boom'); - assert.typeOf(error, 'Error'); - - const formattedError = Errors.toLogFormat(error); - assert.include(formattedError, 'errors_test.js'); - assert.include(formattedError, APP_ROOT_PATH, 'Formatted stack has app path'); - }); - - it('should return error string representation if stack is missing', () => { - const error = new Error('boom'); - error.stack = null; - assert.typeOf(error, 'Error'); - assert.isNull(error.stack); - - const formattedError = Errors.toLogFormat(error); - assert.strictEqual(formattedError, 'Error: boom'); - }); - - [0, false, null, undefined].forEach(value => { - it(`should return \`${value}\` argument`, () => { - const formattedNonError = Errors.toLogFormat(value); - assert.strictEqual(formattedNonError, value); - }); - }); - }); -}); diff --git a/test/modules/types/message_test.js b/test/modules/types/message_test.js deleted file mode 100644 index 83c92ee15..000000000 --- a/test/modules/types/message_test.js +++ /dev/null @@ -1,581 +0,0 @@ -const { assert } = require('chai'); -const sinon = require('sinon'); - -const Message = require('../../../js/modules/types/message'); -const { SignalService } = require('../../../ts/protobuf'); -const { stringToArrayBuffer } = require('../../../js/modules/string_to_array_buffer'); - -describe('Message', () => { - const logger = { - warn: () => null, - error: () => null, - }; - - describe('createAttachmentDataWriter', () => { - it('should ignore messages that didn’t go through attachment migration', async () => { - const input = { - body: 'Imagine there is no heaven…', - schemaVersion: 2, - }; - const expected = { - body: 'Imagine there is no heaven…', - schemaVersion: 2, - }; - const writeExistingAttachmentData = () => {}; - - const actual = await Message.createAttachmentDataWriter({ - writeExistingAttachmentData, - logger, - })(input); - assert.deepEqual(actual, expected); - }); - - it('should ignore messages without attachments', async () => { - const input = { - body: 'Imagine there is no heaven…', - schemaVersion: 4, - attachments: [], - }; - const expected = { - body: 'Imagine there is no heaven…', - schemaVersion: 4, - attachments: [], - }; - const writeExistingAttachmentData = () => {}; - - const actual = await Message.createAttachmentDataWriter({ - writeExistingAttachmentData, - logger, - })(input); - assert.deepEqual(actual, expected); - }); - - it('should write attachments to file system on original path', async () => { - const input = { - body: 'Imagine there is no heaven…', - schemaVersion: 4, - attachments: [ - { - path: 'ab/abcdefghi', - data: stringToArrayBuffer('It’s easy if you try'), - }, - ], - }; - const expected = { - body: 'Imagine there is no heaven…', - schemaVersion: 4, - attachments: [ - { - path: 'ab/abcdefghi', - }, - ], - preview: [], - }; - - const writeExistingAttachmentData = attachment => { - assert.equal(attachment.path, 'ab/abcdefghi'); - assert.deepEqual(attachment.data, stringToArrayBuffer('It’s easy if you try')); - }; - - const actual = await Message.createAttachmentDataWriter({ - writeExistingAttachmentData, - logger, - })(input); - assert.deepEqual(actual, expected); - }); - - it('should process quote attachment thumbnails', async () => { - const input = { - body: 'Imagine there is no heaven…', - schemaVersion: 4, - attachments: [], - quote: { - attachments: [ - { - thumbnail: { - path: 'ab/abcdefghi', - data: stringToArrayBuffer('It’s easy if you try'), - }, - }, - ], - }, - }; - const expected = { - body: 'Imagine there is no heaven…', - schemaVersion: 4, - attachments: [], - quote: { - attachments: [ - { - thumbnail: { - path: 'ab/abcdefghi', - }, - }, - ], - }, - preview: [], - }; - - const writeExistingAttachmentData = attachment => { - assert.equal(attachment.path, 'ab/abcdefghi'); - assert.deepEqual(attachment.data, stringToArrayBuffer('It’s easy if you try')); - }; - - const actual = await Message.createAttachmentDataWriter({ - writeExistingAttachmentData, - logger, - })(input); - assert.deepEqual(actual, expected); - }); - }); - - describe('initializeSchemaVersion', () => { - it('should ignore messages with previously inherited schema', () => { - const input = { - body: 'Imagine there is no heaven…', - schemaVersion: 2, - }; - const expected = { - body: 'Imagine there is no heaven…', - schemaVersion: 2, - }; - - const actual = Message.initializeSchemaVersion({ - message: input, - logger, - }); - assert.deepEqual(actual, expected); - }); - - context('for message without attachments', () => { - it('should initialize schema version to zero', () => { - const input = { - body: 'Imagine there is no heaven…', - attachments: [], - }; - const expected = { - body: 'Imagine there is no heaven…', - attachments: [], - schemaVersion: 0, - }; - - const actual = Message.initializeSchemaVersion({ - message: input, - logger, - }); - assert.deepEqual(actual, expected); - }); - }); - - context('for message with attachments', () => { - it('should inherit existing attachment schema version', () => { - const input = { - body: 'Imagine there is no heaven…', - attachments: [ - { - contentType: 'image/jpeg', - fileName: 'lennon.jpg', - schemaVersion: 7, - }, - ], - }; - const expected = { - body: 'Imagine there is no heaven…', - attachments: [ - { - contentType: 'image/jpeg', - fileName: 'lennon.jpg', - }, - ], - schemaVersion: 7, - }; - - const actual = Message.initializeSchemaVersion({ - message: input, - logger, - }); - assert.deepEqual(actual, expected); - }); - }); - }); - - describe('upgradeSchema', () => { - it('should upgrade an unversioned message to the latest version', async () => { - const input = { - attachments: [ - { - contentType: 'audio/aac', - flags: SignalService.AttachmentPointer.Flags.VOICE_MESSAGE, - data: stringToArrayBuffer('It’s easy if you try'), - fileName: 'test\u202Dfig.exe', - size: 1111, - }, - ], - schemaVersion: 0, - }; - const expected = { - attachments: [ - { - contentType: 'audio/aac', - flags: 1, - path: 'abc/abcdefg', - fileName: 'test\uFFFDfig.exe', - size: 1111, - }, - ], - hasAttachments: 1, - hasVisualMediaAttachments: undefined, - hasFileAttachments: undefined, - schemaVersion: Message.CURRENT_SCHEMA_VERSION, - }; - - const expectedAttachmentData = stringToArrayBuffer('It’s easy if you try'); - const context = { - writeNewAttachmentData: async attachmentData => { - assert.deepEqual(attachmentData, expectedAttachmentData); - return 'abc/abcdefg'; - }, - getAbsoluteAttachmentPath: () => 'some/path/on/disk', - makeObjectUrl: () => 'blob://FAKE', - revokeObjectUrl: () => null, - getImageDimensions: () => ({ height: 10, width: 15 }), - makeImageThumbnail: () => new Blob(), - makeVideoScreenshot: () => new Blob(), - logger: { - warn: () => null, - error: () => null, - }, - }; - const actual = await Message.upgradeSchema(input, context); - assert.deepEqual(actual, expected); - }); - - context('with multiple upgrade steps', () => { - it('should return last valid message when any upgrade step fails', async () => { - const input = { - attachments: [ - { - contentType: 'application/json', - data: null, - fileName: 'test\u202Dfig.exe', - size: 1111, - }, - ], - schemaVersion: 0, - }; - const expected = { - attachments: [ - { - contentType: 'application/json', - data: null, - fileName: 'test\u202Dfig.exe', - size: 1111, - }, - ], - hasUpgradedToVersion1: true, - schemaVersion: 1, - }; - - const v1 = async message => Object.assign({}, message, { hasUpgradedToVersion1: true }); - const v2 = async () => { - throw new Error('boom'); - }; - const v3 = async message => Object.assign({}, message, { hasUpgradedToVersion3: true }); - - const toVersion1 = Message._withSchemaVersion({ - schemaVersion: 1, - upgrade: v1, - }); - const toVersion2 = Message._withSchemaVersion({ - schemaVersion: 2, - upgrade: v2, - }); - const toVersion3 = Message._withSchemaVersion({ - schemaVersion: 3, - upgrade: v3, - }); - - const context = { logger }; - const upgradeSchema = async message => - toVersion3(await toVersion2(await toVersion1(message, context), context), context); - - const actual = await upgradeSchema(input); - assert.deepEqual(actual, expected); - }); - - it('should skip out-of-order upgrade steps', async () => { - const input = { - attachments: [ - { - contentType: 'application/json', - data: null, - fileName: 'test\u202Dfig.exe', - size: 1111, - }, - ], - schemaVersion: 0, - }; - const expected = { - attachments: [ - { - contentType: 'application/json', - data: null, - fileName: 'test\u202Dfig.exe', - size: 1111, - }, - ], - schemaVersion: 2, - hasUpgradedToVersion1: true, - hasUpgradedToVersion2: true, - }; - - const v1 = async attachment => - Object.assign({}, attachment, { hasUpgradedToVersion1: true }); - const v2 = async attachment => - Object.assign({}, attachment, { hasUpgradedToVersion2: true }); - const v3 = async attachment => - Object.assign({}, attachment, { hasUpgradedToVersion3: true }); - - const toVersion1 = Message._withSchemaVersion({ - schemaVersion: 1, - upgrade: v1, - }); - const toVersion2 = Message._withSchemaVersion({ - schemaVersion: 2, - upgrade: v2, - }); - const toVersion3 = Message._withSchemaVersion({ - schemaVersion: 3, - upgrade: v3, - }); - - const context = { logger }; - // NOTE: We upgrade to 3 before 2, i.e. the pipeline should abort: - const upgradeSchema = async attachment => - toVersion2(await toVersion3(await toVersion1(attachment, context), context), context); - - const actual = await upgradeSchema(input); - assert.deepEqual(actual, expected); - }); - }); - }); - - describe('_withSchemaVersion', () => { - it('should require a version number', () => { - const toVersionX = () => {}; - assert.throws( - () => Message._withSchemaVersion({ schemaVersion: toVersionX, upgrade: 2 }), - '_withSchemaVersion: schemaVersion is invalid' - ); - }); - - it('should require an upgrade function', () => { - assert.throws( - () => Message._withSchemaVersion({ schemaVersion: 2, upgrade: 3 }), - '_withSchemaVersion: upgrade must be a function' - ); - }); - - it('should skip upgrading if message has already been upgraded', async () => { - const upgrade = async message => Object.assign({}, message, { foo: true }); - const upgradeWithVersion = Message._withSchemaVersion({ - schemaVersion: 3, - upgrade, - }); - - const input = { - id: 'guid-guid-guid-guid', - schemaVersion: 4, - }; - const expected = { - id: 'guid-guid-guid-guid', - schemaVersion: 4, - }; - const actual = await upgradeWithVersion(input, { logger }); - assert.deepEqual(actual, expected); - }); - - it('should return original message if upgrade function throws', async () => { - const upgrade = async () => { - throw new Error('boom!'); - }; - const upgradeWithVersion = Message._withSchemaVersion({ - schemaVersion: 3, - upgrade, - }); - - const input = { - id: 'guid-guid-guid-guid', - schemaVersion: 0, - }; - const expected = { - id: 'guid-guid-guid-guid', - schemaVersion: 0, - }; - const actual = await upgradeWithVersion(input, { logger }); - assert.deepEqual(actual, expected); - }); - - it('should return original message if upgrade function returns null', async () => { - const upgrade = async () => null; - const upgradeWithVersion = Message._withSchemaVersion({ - schemaVersion: 3, - upgrade, - }); - - const input = { - id: 'guid-guid-guid-guid', - schemaVersion: 0, - }; - const expected = { - id: 'guid-guid-guid-guid', - schemaVersion: 0, - }; - const actual = await upgradeWithVersion(input, { logger }); - assert.deepEqual(actual, expected); - }); - }); - - describe('_mapQuotedAttachments', () => { - it('handles message with no quote', async () => { - const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); - const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); - - const message = { - body: 'hey there!', - }; - const result = await upgradeVersion(message); - assert.deepEqual(result, message); - }); - - it('handles quote with no attachments', async () => { - const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); - const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); - - const message = { - body: 'hey there!', - quote: { - text: 'hey!', - }, - }; - const expected = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [], - }, - }; - const result = await upgradeVersion(message, { logger }); - assert.deepEqual(result, expected); - }); - - it('handles zero attachments', async () => { - const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); - const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); - - const message = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [], - }, - }; - const result = await upgradeVersion(message, { logger }); - assert.deepEqual(result, message); - }); - - it('handles attachments with no thumbnail', async () => { - const upgradeAttachment = sinon.stub().throws(new Error("Shouldn't be called")); - const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); - - const message = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [ - { - fileName: 'manifesto.txt', - contentType: 'text/plain', - }, - ], - }, - }; - const result = await upgradeVersion(message, { logger }); - assert.deepEqual(result, message); - }); - - it('does not eliminate thumbnails with missing data field', async () => { - const upgradeAttachment = sinon.stub().returns({ fileName: 'processed!' }); - const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); - - const message = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [ - { - fileName: 'cat.gif', - contentType: 'image/gif', - thumbnail: { - fileName: 'not yet downloaded!', - }, - }, - ], - }, - }; - const expected = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [ - { - contentType: 'image/gif', - fileName: 'cat.gif', - thumbnail: { - fileName: 'processed!', - }, - }, - ], - }, - }; - const result = await upgradeVersion(message, { logger }); - assert.deepEqual(result, expected); - }); - - it('calls provided async function for each quoted attachment', async () => { - const upgradeAttachment = sinon.stub().resolves({ - path: '/new/path/on/disk', - }); - const upgradeVersion = Message._mapQuotedAttachments(upgradeAttachment); - - const message = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [ - { - thumbnail: { - data: 'data is here', - }, - }, - ], - }, - }; - const expected = { - body: 'hey there!', - quote: { - text: 'hey!', - attachments: [ - { - thumbnail: { - path: '/new/path/on/disk', - }, - }, - ], - }, - }; - const result = await upgradeVersion(message, { logger }); - assert.deepEqual(result, expected); - }); - }); -}); diff --git a/test/modules/types/mime_test.js b/test/modules/types/mime_test.js deleted file mode 100644 index bc85780cd..000000000 --- a/test/modules/types/mime_test.js +++ /dev/null @@ -1,28 +0,0 @@ -const { assert } = require('chai'); - -const MIME = require('../../../ts/types/MIME'); - -describe('MIME', () => { - describe('isJPEG', () => { - it('should return true for `image/jpeg`', () => { - assert.isTrue(MIME.isJPEG('image/jpeg')); - }); - - [ - 'jpg', - 'jpeg', - 'image/jpg', // invalid MIME type: https://stackoverflow.com/a/37266399/125305 - 'image/gif', - 'image/tiff', - 'application/json', - 0, - false, - null, - undefined, - ].forEach(value => { - it(`should return false for \`${value}\``, () => { - assert.isFalse(MIME.isJPEG(value)); - }); - }); - }); -}); diff --git a/test/modules/types/schema_version_test.js b/test/modules/types/schema_version_test.js deleted file mode 100644 index 34a97d7a9..000000000 --- a/test/modules/types/schema_version_test.js +++ /dev/null @@ -1,20 +0,0 @@ -require('mocha-testcheck').install(); -const { assert } = require('chai'); - -const SchemaVersion = require('../../../js/modules/types/schema_version'); - -describe('SchemaVersion', () => { - describe('isValid', () => { - check.it('should return true for positive integers', gen.posInt, input => { - assert.isTrue(SchemaVersion.isValid(input)); - }); - - check.it( - 'should return false for any other value', - gen.primitive.suchThat(value => typeof value !== 'number' || value < 0), - input => { - assert.isFalse(SchemaVersion.isValid(input)); - } - ); - }); -}); diff --git a/test/views/whisper_view_test.js b/test/views/whisper_view_test.js deleted file mode 100644 index 40de73aa5..000000000 --- a/test/views/whisper_view_test.js +++ /dev/null @@ -1,38 +0,0 @@ -/* global Whisper */ - -describe('Whisper.View', () => { - it('renders a template with render_attributes', () => { - const ViewClass = Whisper.View.extend({ - template: '
{{ variable }}
', - render_attributes: { - variable: 'value', - }, - }); - - const view = new ViewClass(); - view.render(); - assert.strictEqual(view.$el.html(), '
value
'); - }); - it('renders a template with no render_attributes', () => { - const ViewClass = Whisper.View.extend({ - template: '
static text
', - }); - - const view = new ViewClass(); - view.render(); - assert.strictEqual(view.$el.html(), '
static text
'); - }); - it('renders a template function with render_attributes function', () => { - const ViewClass = Whisper.View.extend({ - template() { - return '
{{ variable }}
'; - }, - render_attributes() { - return { variable: 'value' }; - }, - }); - const view = new ViewClass(); - view.render(); - assert.strictEqual(view.$el.html(), '
value
'); - }); -}); diff --git a/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts b/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts index 43ca6d30b..3e7aa6e54 100644 --- a/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts +++ b/ts/opengroup/opengroupV2/OpenGroupAPIV2.ts @@ -80,7 +80,7 @@ export async function sendApiV2Request( throw new Error('Invalid request'); } - if (!window.globalOnlineStatus) { + if (!window.getGlobalOnlineStatus()) { throw new pRetry.AbortError('Network is not available'); } diff --git a/ts/session/onions/onionPath.ts b/ts/session/onions/onionPath.ts index eea2f6465..891588dbe 100644 --- a/ts/session/onions/onionPath.ts +++ b/ts/session/onions/onionPath.ts @@ -12,6 +12,7 @@ const minimumGuardCount = 2; import { updateOnionPaths } from '../../state/ducks/onion'; import { ERROR_CODE_NO_CONNECT } from '../snode_api/SNodeAPI'; +import { getStoragePubKey } from '../types/PubKey'; const ONION_REQUEST_HOPS = 3; export let onionPaths: Array> = []; @@ -175,7 +176,7 @@ export async function incrementBadPathCountOrDrop(snodeEd25519: string) { ); if (pathWithSnodeIndex === -1) { - (window?.log?.info || console.warn)('Did not find any path containing this snode'); + window?.log?.info('Did not find any path containing this snode'); // this can only be bad. throw an abortError so we use another path if needed throw new pRetry.AbortError( 'incrementBadPathCountOrDrop: Did not find any path containing this snode' @@ -255,7 +256,7 @@ async function testGuardNode(snode: Snode) { const url = `https://${snode.ip}:${snode.port}${endpoint}`; const ourPK = UserUtils.getOurPubKeyStrFromCache(); - const pubKey = window.getStoragePubKey(ourPK); // truncate if testnet + const pubKey = getStoragePubKey(ourPK); // truncate if testnet const method = 'get_snodes_for_pubkey'; const params = { pubKey }; @@ -331,7 +332,7 @@ export async function selectGuardNodes(): Promise> { // we only want to repeat if the await fails // eslint-disable-next-line-no-await-in-loop while (selectedGuardNodes.length < desiredGuardCount) { - if (!window.globalOnlineStatus) { + if (!window.getGlobalOnlineStatus()) { window?.log?.error('selectedGuardNodes: offline'); throw new Error('selectedGuardNodes: offline'); } diff --git a/ts/session/snode_api/SNodeAPI.ts b/ts/session/snode_api/SNodeAPI.ts index ca05da353..61360f246 100644 --- a/ts/session/snode_api/SNodeAPI.ts +++ b/ts/session/snode_api/SNodeAPI.ts @@ -79,7 +79,6 @@ const getSslAgentForSeedNode = (seedNodeHost: string, isSsl = false) => { const sslOptions = { // as the seed nodes are using a self signed certificate, we have to provide it here. ca: crt, - // we might need to selectively disable that for tests on swarm-testing or so. // we have to reject them, otherwise our errors returned in the checkServerIdentity are simply not making the call fail. // so in production, rejectUnauthorized must be true. rejectUnauthorized: true, @@ -91,8 +90,6 @@ const getSslAgentForSeedNode = (seedNodeHost: string, isSsl = false) => { return err; } - // we might need to selectively disable that for tests on swarm-testing or so. - // Pin the public key, similar to HPKP pin-sha25 pinning if (sha256(cert.pubkey) !== pubkey256) { const msg = diff --git a/ts/session/snode_api/lokiRpc.ts b/ts/session/snode_api/lokiRpc.ts index 1a7809de8..5cf332028 100644 --- a/ts/session/snode_api/lokiRpc.ts +++ b/ts/session/snode_api/lokiRpc.ts @@ -1,5 +1,6 @@ import { default as insecureNodeFetch } from 'node-fetch'; import { Snode } from '../../data/data'; +import { getStoragePubKey } from '../types'; import { lokiOnionFetch, snodeHttpsAgent, SnodeResponse } from './onions'; @@ -32,7 +33,11 @@ async function lokiFetch( try { // Absence of targetNode indicates that we want a direct connection // (e.g. to connect to a seed node for the first time) - if (window.lokiFeatureFlags.useOnionRequests && targetNode) { + const useOnionRequests = + window.lokiFeatureFlags?.useOnionRequests === undefined + ? true + : window.lokiFeatureFlags?.useOnionRequests; + if (useOnionRequests && targetNode) { const fetchResult = await lokiOnionFetch(targetNode, fetchOptions.body, associatedWith, test); if (!fetchResult) { return undefined; @@ -92,7 +97,7 @@ export async function snodeRpc( // tslint:disable-next-line no-parameter-reassignment params = { ...params, - pubKey: window.getStoragePubKey(params.pubKey), + pubKey: getStoragePubKey(params.pubKey), }; } const body = { diff --git a/ts/session/snode_api/onions.ts b/ts/session/snode_api/onions.ts index 1942bb7d9..102297f8b 100644 --- a/ts/session/snode_api/onions.ts +++ b/ts/session/snode_api/onions.ts @@ -599,7 +599,7 @@ export async function incrementBadSnodeCountOrDrop({ associatedWith?: string; }) { if (!guardNodeEd25519) { - console.warn('We need a guardNodeEd25519 at all times'); + window?.log?.warn('We need a guardNodeEd25519 at all times'); } const oldFailureCount = snodeFailureCount[snodeEd25519] || 0; const newFailureCount = oldFailureCount + 1; @@ -608,7 +608,7 @@ export async function incrementBadSnodeCountOrDrop({ window?.log?.warn(`Failure threshold reached for: ${ed25519Str(snodeEd25519)}; dropping it.`); if (associatedWith) { - (window?.log?.info || console.warn)( + window?.log?.warn( `Dropping ${ed25519Str(snodeEd25519)} from swarm of ${ed25519Str(associatedWith)}` ); await dropSnodeFromSwarmIfNeeded(associatedWith, snodeEd25519); diff --git a/ts/session/snode_api/swarmPolling.ts b/ts/session/snode_api/swarmPolling.ts index 919f632ed..56d555a15 100644 --- a/ts/session/snode_api/swarmPolling.ts +++ b/ts/session/snode_api/swarmPolling.ts @@ -120,7 +120,6 @@ export class SwarmPolling { if (currentTimestamp - activeAt <= DURATION.DAYS * 7) { return SWARM_POLLING_TIMEOUT.MEDIUM_ACTIVE; } - return SWARM_POLLING_TIMEOUT.INACTIVE; } @@ -128,7 +127,7 @@ export class SwarmPolling { * Only public for testing */ public async TEST_pollForAllKeys() { - if (!window.globalOnlineStatus) { + if (!window.getGlobalOnlineStatus()) { window?.log?.error('pollForAllKeys: offline'); // Important to set up a new polling setTimeout(this.TEST_pollForAllKeys.bind(this), SWARM_POLLING_TIMEOUT.ACTIVE); @@ -150,12 +149,12 @@ export class SwarmPolling { ?.idForLogging() || group.pubkey.key; if (diff >= convoPollingTimeout) { - (window?.log?.info || console.warn)( + window?.log?.info( `Polling for ${loggingId}; timeout: ${convoPollingTimeout} ; diff: ${diff}` ); return this.TEST_pollOnceForKey(group.pubkey, true); } - (window?.log?.info || console.warn)( + window?.log?.info( `Not polling for ${loggingId}; timeout: ${convoPollingTimeout} ; diff: ${diff}` ); @@ -190,7 +189,6 @@ export class SwarmPolling { const COUNT = 1; let nodesToPoll = _.sampleSize(alreadyPolled, COUNT); - if (nodesToPoll.length < COUNT) { const notPolled = _.difference(snodes, alreadyPolled); diff --git a/ts/session/types/PubKey.ts b/ts/session/types/PubKey.ts index 3d23273bd..2076f2e33 100644 --- a/ts/session/types/PubKey.ts +++ b/ts/session/types/PubKey.ts @@ -1,5 +1,8 @@ import { fromHexToArray } from '../utils/String'; +export const getStoragePubKey = (key: string) => + window.isDev?.() || false ? key.substring(2) : key; + export class PubKey { public static readonly PUBKEY_LEN = 66; public static readonly HEX = '[0-9a-fA-F]'; diff --git a/ts/test/test-utils/utils/stubbing.ts b/ts/test/test-utils/utils/stubbing.ts index a11c31b0f..751d4a1b2 100644 --- a/ts/test/test-utils/utils/stubbing.ts +++ b/ts/test/test-utils/utils/stubbing.ts @@ -1,6 +1,5 @@ import * as sinon from 'sinon'; import * as DataShape from '../../../../ts/data/data'; -import { Application } from 'spectron'; const globalAny: any = global; const sandbox = sinon.createSandbox(); @@ -51,21 +50,6 @@ export function stubWindow(fn: K, value: WindowValue) }; } -export async function spyMessageQueueSend(app: Application) { - await app.webContents.executeJavaScript( - "var messageQueueSpy = sinon.spy(window.libsession.getMessageQueue(), 'send'); " - ); -} - -export async function getAllMessagesSent(app: Application) { - const messageQueueSpy = await app.webContents.executeJavaScript('messageQueueSpy.args;'); - if (!messageQueueSpy) { - throw new Error('Be sure to call spyMessageQueueSend() on the correct app first.'); - } - const messages = await app.webContents.executeJavaScript('messageQueueSpy.args'); - return messages; -} - export function restoreStubs() { globalAny.window = undefined; sandbox.restore(); diff --git a/ts/util/lint/linter.ts b/ts/util/lint/linter.ts index 93e52538d..080690540 100644 --- a/ts/util/lint/linter.ts +++ b/ts/util/lint/linter.ts @@ -144,7 +144,6 @@ const excludedFiles = [ '^node_modules/snapdragon-util/*', '^node_modules/snapdragon/*', '^node_modules/sockjs-client/*', - '^node_modules/spectron/*', '^node_modules/style-loader/*', '^node_modules/svgo/*', '^node_modules/text-encoding/*', diff --git a/ts/window.d.ts b/ts/window.d.ts index d984cf31d..7807f6e6c 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -63,9 +63,9 @@ declare global { toggleMenuBar: any; toggleSpellCheck: any; setTheme: (newTheme: string) => any; + isDev?: () => boolean; userConfig: any; versionInfo: any; - getStoragePubKey: (key: string) => string; getConversations: () => ConversationCollection; profileImages: any; MediaRecorder: any; @@ -78,7 +78,7 @@ declare global { messageId?: string | undefined; }) => Promise; LokiPushNotificationServer: any; - globalOnlineStatus: boolean; + getGlobalOnlineStatus: () => boolean; confirmationDialog: any; callWorker: (fnName: string, ...args: any) => Promise; setStartInTray: (val: boolean) => Promise; diff --git a/yarn.lock b/yarn.lock index 766ce2022..74ef17007 100644 --- a/yarn.lock +++ b/yarn.lock @@ -204,6 +204,27 @@ global-agent "^2.0.2" global-tunnel-ng "^2.7.1" +"@electron/get@^1.12.4": + version "1.12.4" + resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.12.4.tgz#a5971113fc1bf8fa12a8789dc20152a7359f06ab" + integrity sha512-6nr9DbJPUR9Xujw6zD3y+rS95TyItEVM0NVjt1EehY2vUWfIgPiIPVHxCvaTS0xr2B+DRxovYVKbuOWqC35kjg== + dependencies: + debug "^4.1.1" + env-paths "^2.2.0" + fs-extra "^8.1.0" + got "^9.6.0" + progress "^2.0.3" + semver "^6.2.0" + sumchecker "^3.0.1" + optionalDependencies: + global-agent "^2.0.2" + global-tunnel-ng "^2.7.1" + +"@electron/remote@^1.1.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@electron/remote/-/remote-1.2.1.tgz#665b9fc2c6a60f9e5039bf235e2c60ccd0242c32" + integrity sha512-yKh60I8KjezQkZqeuN5Nu2O/Z72+tgNgzvAa8QQPLtQbsrCOaeIWdXZQqierz4jQ5jzTNUk6KIcK3V2kFeaxaQ== + "@emotion/is-prop-valid@^0.8.8": version "0.8.8" resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a" @@ -309,6 +330,11 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== +"@sindresorhus/is@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.1.tgz#d26729db850fa327b7cacc5522252194404226f5" + integrity sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g== + "@sinonjs/commons@^1", "@sinonjs/commons@^1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.1.tgz#da5fd19a5f71177a53778073978873964f49acf1" @@ -359,6 +385,13 @@ dependencies: defer-to-connect "^1.0.1" +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + "@types/backbone@^1.4.2": version "1.4.2" resolved "https://registry.yarnpkg.com/@types/backbone/-/backbone-1.4.2.tgz#2af5ca6536d4cd510842eea6eeea11a42fa704b9" @@ -394,6 +427,16 @@ "@types/long" "*" "@types/node" "*" +"@types/cacheable-request@^6.0.1": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.2.tgz#c324da0197de0a98a2312156536ae262429ff6b9" + integrity sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "*" + "@types/node" "*" + "@types/responselike" "*" + "@types/chai-as-promised@^7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.2.tgz#2f564420e81eaf8650169e5a3a6b93e096e5068b" @@ -546,6 +589,11 @@ "@types/react" "*" hoist-non-react-statics "^3.3.0" +"@types/http-cache-semantics@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" + integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== + "@types/integer@*": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/integer/-/integer-4.0.0.tgz#3b778715df72d2cf8ba73bad27bd9d830907f944" @@ -580,6 +628,13 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== +"@types/keyv@*": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.2.tgz#5d97bb65526c20b6e0845f6b0d2ade4f28604ee5" + integrity sha512-/FvAK2p4jQOaJ6CGDHJTqZcUtbZe820qIeTg7o0Shg7drB4JHeL+V/dhSaly7NXx6u8eSee+r7coT+yuJEvDLg== + dependencies: + "@types/node" "*" + "@types/libsodium-wrappers@^0.7.8": version "0.7.8" resolved "https://registry.yarnpkg.com/@types/libsodium-wrappers/-/libsodium-wrappers-0.7.8.tgz#34575d7692fdbb7a7fdb63afcde381db86ec0de2" @@ -672,6 +727,20 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== +"@types/puppeteer-core@^5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@types/puppeteer-core/-/puppeteer-core-5.4.0.tgz#880a7917b4ede95cbfe2d5e81a558cfcb072c0fb" + integrity sha512-yqRPuv4EFcSkTyin6Yy17pN6Qz2vwVwTCJIDYMXbE3j8vTPhv0nCQlZOl5xfi0WHUkqvQsjAR8hAfjeMCoetwg== + dependencies: + "@types/puppeteer" "*" + +"@types/puppeteer@*": + version "5.4.4" + resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-5.4.4.tgz#e92abeccc4f46207c3e1b38934a1246be080ccd0" + integrity sha512-3Nau+qi69CN55VwZb0ATtdUAlYlqOOQ3OfQfq0Hqgc4JMFXiQT/XInlwQ9g6LbicDslE6loIFsXFklGh5XmI6Q== + dependencies: + "@types/node" "*" + "@types/qs@6.5.1": version "6.5.1" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.5.1.tgz#a38f69c62528d56ba7bd1f91335a8004988d72f7" @@ -778,6 +847,13 @@ dependencies: redux "^3.6.0" +"@types/responselike@*", "@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + "@types/retry@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" @@ -857,13 +933,6 @@ dependencies: "@types/node" "*" -"@types/webdriverio@^4.8.0": - version "4.13.3" - resolved "https://registry.yarnpkg.com/@types/webdriverio/-/webdriverio-4.13.3.tgz#c1571c4e62724135c0b11e7d7e36b07af5168856" - integrity sha512-AfSQM1xTO9Ax+u9uSQPDuw69DQ0qA2RMoKHn86jCgWNcwKVUjGMSP4sfSl3JOfcZN8X/gWvn7znVPp2/g9zcJA== - dependencies: - "@types/node" "*" - "@types/webpack@^5.28.0": version "5.28.0" resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-5.28.0.tgz#78dde06212f038d77e54116cfe69e88ae9ed2c03" @@ -873,6 +942,11 @@ tapable "^2.2.0" webpack "^5" +"@types/which@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf" + integrity sha512-8oDqyLC7eD4HM307boe2QWKyuzdzWBj56xI/imSl2cpL+U3tCMaTAkMJ4ee5JBZ/FsOJlvRGeIShiZDAl1qERA== + "@types/yargs-parser@*": version "15.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" @@ -885,6 +959,51 @@ dependencies: "@types/yargs-parser" "*" +"@types/yauzl@^2.9.1": + version "2.9.2" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" + integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA== + dependencies: + "@types/node" "*" + +"@wdio/config@6.12.1": + version "6.12.1" + resolved "https://registry.yarnpkg.com/@wdio/config/-/config-6.12.1.tgz#86d987b505d8ca85ec11471830d2ba296dab3bcf" + integrity sha512-V5hTIW5FNlZ1W33smHF4Rd5BKjGW2KeYhyXDQfXHjqLCeRiirZ9fABCo9plaVQDnwWSUMWYaAaIAifV82/oJCQ== + dependencies: + "@wdio/logger" "6.10.10" + deepmerge "^4.0.0" + glob "^7.1.2" + +"@wdio/logger@6.10.10": + version "6.10.10" + resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-6.10.10.tgz#1e07cf32a69606ddb94fa9fd4b0171cb839a5980" + integrity sha512-2nh0hJz9HeZE0VIEMI+oPgjr/Q37ohrR9iqsl7f7GW5ik+PnKYCT9Eab5mR1GNMG60askwbskgGC1S9ygtvrSw== + dependencies: + chalk "^4.0.0" + loglevel "^1.6.0" + loglevel-plugin-prefix "^0.8.4" + strip-ansi "^6.0.0" + +"@wdio/protocols@6.12.0": + version "6.12.0" + resolved "https://registry.yarnpkg.com/@wdio/protocols/-/protocols-6.12.0.tgz#e40850be62c42c82dd2c486655d6419cd9ec1e3e" + integrity sha512-UhTBZxClCsM3VjaiDp4DoSCnsa7D1QNmI2kqEBfIpyNkT3GcZhJb7L+nL0fTkzCwi7+/uLastb3/aOwH99gt0A== + +"@wdio/repl@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@wdio/repl/-/repl-6.11.0.tgz#5b1eab574b6b89f7f7c383e7295c06af23c3818e" + integrity sha512-FxrFKiTkFyELNGGVEH1uijyvNY7lUpmff6x+FGskFGZB4uSRs0rxkOMaEjxnxw7QP1zgQKr2xC7GyO03gIGRGg== + dependencies: + "@wdio/utils" "6.11.0" + +"@wdio/utils@6.11.0": + version "6.11.0" + resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-6.11.0.tgz#878c2500efb1a325bf5a66d2ff3d08162f976e8c" + integrity sha512-vf0sOQzd28WbI26d6/ORrQ4XKWTzSlWLm9W/K/eJO0NASKPEzR+E+Q2kaa+MJ4FKXUpjbt+Lxfo+C26TzBk7tg== + dependencies: + "@wdio/logger" "6.10.10" + "@webassemblyjs/ast@1.11.0": version "1.11.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" @@ -1208,6 +1327,11 @@ add-dom-event-listener@^1.1.0: dependencies: object-assign "4.x" +agent-base@5: + version "5.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-5.1.1.tgz#e8fb3f242959db44d63be665db7a8e739537a32c" + integrity sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -1406,31 +1530,34 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -archiver-utils@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174" - integrity sha1-5QtMCccL89aA4y/xt5lOn52JUXQ= +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== dependencies: - glob "^7.0.0" - graceful-fs "^4.1.0" + glob "^7.1.4" + graceful-fs "^4.2.0" lazystream "^1.0.0" - lodash "^4.8.0" - normalize-path "^2.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" readable-stream "^2.0.0" -archiver@~2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-2.1.1.tgz#ff662b4a78201494a3ee544d3a33fe7496509ebc" - integrity sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw= +archiver@^5.0.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.0.tgz#dd3e097624481741df626267564f7dd8640a45ba" + integrity sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg== dependencies: - archiver-utils "^1.3.0" - async "^2.0.0" + archiver-utils "^2.1.0" + async "^3.2.0" buffer-crc32 "^0.2.1" - glob "^7.0.0" - lodash "^4.8.0" - readable-stream "^2.0.0" - tar-stream "^1.5.0" - zip-stream "^1.2.0" + readable-stream "^3.6.0" + readdir-glob "^1.0.0" + tar-stream "^2.2.0" + zip-stream "^4.1.0" are-we-there-yet@~1.1.2: version "1.1.5" @@ -1585,13 +1712,18 @@ async@^1.5.0, async@~1.5.2: resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -async@^2.0.0, async@^2.6.2: +async@^2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== dependencies: lodash "^4.17.14" +async@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8" + integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1666,10 +1798,10 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== base@^0.11.1: version "0.11.2" @@ -1740,13 +1872,14 @@ biskviit@1.0.1: dependencies: psl "^1.1.7" -bl@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" - integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" blob-util@1.3.0: version "1.3.0" @@ -1905,29 +2038,11 @@ browserslist@^4.14.5: escalade "^3.1.1" node-releases "^1.1.71" -buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - -buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - -buffer-crc32@0.2.13, buffer-crc32@^0.2.1, buffer-crc32@~0.2.3: +buffer-crc32@0.2.13, buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= -buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -1938,13 +2053,13 @@ buffer-indexof@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== -buffer@^5.1.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.5.0.tgz#9c3caa3d623c33dd1c7ef584b89b88bf9c9bc1ce" - integrity sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww== +buffer@^5.2.1, buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" + base64-js "^1.3.1" + ieee754 "^1.1.13" buffers@~0.1.1: version "0.1.1" @@ -2044,6 +2159,11 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + cacheable-request@^6.0.0: version "6.1.0" resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" @@ -2057,6 +2177,19 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" +cacheable-request@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -2230,6 +2363,18 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== +chrome-launcher@^0.13.1: + version "0.13.4" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.13.4.tgz#4c7d81333c98282899c4e38256da23e00ed32f73" + integrity sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A== + dependencies: + "@types/node" "*" + escape-string-regexp "^1.0.5" + is-wsl "^2.2.0" + lighthouse-logger "^1.0.0" + mkdirp "^0.5.3" + rimraf "^3.0.2" + chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -2468,15 +2613,15 @@ component-indexof@0.0.3: resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24" integrity sha1-EdCRMSI5648yyPJa6csAL/6NPCQ= -compress-commons@^1.2.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.2.tgz#524a9f10903f3a813389b0225d27c48bb751890f" - integrity sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8= +compress-commons@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" + integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== dependencies: - buffer-crc32 "^0.2.1" - crc32-stream "^2.0.0" - normalize-path "^2.0.0" - readable-stream "^2.0.0" + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" compressible@~2.0.16: version "2.0.18" @@ -2503,7 +2648,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.2, concat-stream@^1.6.0, concat-stream@^1.6.2: +concat-stream@1.6.2, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -2621,20 +2766,21 @@ country-code-lookup@^0.0.19: resolved "https://registry.yarnpkg.com/country-code-lookup/-/country-code-lookup-0.0.19.tgz#3fbf0192758ecf0d5eee0efbc220d62706c50fd6" integrity sha512-lpvgdPyj8RuP0CSZhACNf5ueKlLbv/IQUAQfg7yr/qJbFrdcWV7Y+aDN9K/u/bx3MXRfcsjuW+TdIc0AEj7kDw== -crc32-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" - integrity sha1-483TtN8xaN10494/u8t7KX/pCPQ= +crc-32@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + integrity sha512-1uBwHxF+Y/4yF5G48fwnKq6QsIXheor3ZLPT80yGBV1oEUwpPojlEhQbWKVw1VwcTQyMGHK1/XMmTjmlsmTTGA== dependencies: - crc "^3.4.4" - readable-stream "^2.0.0" + exit-on-epipe "~1.0.1" + printj "~1.1.0" -crc@^3.4.4: - version "3.8.0" - resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6" - integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ== +crc32-stream@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" + integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== dependencies: - buffer "^5.1.0" + crc-32 "^1.2.0" + readable-stream "^3.4.0" cross-env@^6.0.3: version "6.0.3" @@ -2726,12 +2872,10 @@ css-loader@^3.6.0: schema-utils "^2.7.0" semver "^6.3.0" -css-parse@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" - integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= - dependencies: - css "^2.0.0" +css-shorthand-properties@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-shorthand-properties/-/css-shorthand-properties-1.1.1.tgz#1c808e63553c283f289f2dd56fcee8f3337bd935" + integrity sha512-Md+Juc7M3uOdbAFwOYlTrccIZ7oCFuzrhKYQjdeUEW/sE1hv17Jp/Bws+ReOPpGVBTYCBoYo+G17V5Qo8QQ75A== css-to-react-native@^3.0.0: version "3.0.0" @@ -2750,21 +2894,11 @@ css-tree@^1.1.2: mdn-data "2.0.14" source-map "^0.6.1" -css-value@~0.0.1: +css-value@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" integrity sha1-Xv1sLupeof1rasV+wEJ7GEUkJOo= -css@^2.0.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== - dependencies: - inherits "^2.0.3" - source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" - cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" @@ -2817,7 +2951,7 @@ dateformat@~1.0.12: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -2831,7 +2965,14 @@ debug@3.1.0: dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.1.0, debug@^3.2.6: +debug@4: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +debug@^3.1.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -2891,6 +3032,13 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + decompress-zip@0.3.x: version "0.3.2" resolved "https://registry.yarnpkg.com/decompress-zip/-/decompress-zip-0.3.2.tgz#f3fa2841666abce394604f4a9e8a7085c202d464" @@ -2943,10 +3091,10 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -deepmerge@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.0.1.tgz#25c1c24f110fb914f80001b925264dd77f3f4312" - integrity sha512-VIPwiMJqJ13ZQfaCsIFnp5Me9tnjURiaIFxfz7EH0Ci0dTSQpZtSLrqOicXqEd/z2r+z+Klk9GzmnRsgpgbOsQ== +deepmerge@^4.0.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== default-gateway@^4.2.0: version "4.2.0" @@ -2961,6 +3109,11 @@ defer-to-connect@^1.0.1: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -3033,6 +3186,26 @@ dev-null@^0.1.1: resolved "https://registry.yarnpkg.com/dev-null/-/dev-null-0.1.1.tgz#5a205ce3c2b2ef77b6238d6ba179eb74c6a0e818" integrity sha1-WiBc48Ky73e2I41roXnrdMag6Bg= +devtools-protocol@0.0.818844: + version "0.0.818844" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.818844.tgz#d1947278ec85b53e4c8ca598f607a28fa785ba9e" + integrity sha512-AD1hi7iVJ8OD0aMLQU5VK0XH9LDlA1+BcPIgrAxPfaibx2DbWucuyOhc4oyQCbnvDDO68nN6/LcKfqTP343Jjg== + +devtools@6.12.1: + version "6.12.1" + resolved "https://registry.yarnpkg.com/devtools/-/devtools-6.12.1.tgz#f0298c6d6f46d8d3b751dd8fa4a0c7bc76e1268f" + integrity sha512-JyG46suEiZmld7/UVeogkCWM0zYGt+2ML/TI+SkEp+bTv9cs46cDb0pKF3glYZJA7wVVL2gC07Ic0iCxyJEnCQ== + dependencies: + "@wdio/config" "6.12.1" + "@wdio/logger" "6.10.10" + "@wdio/protocols" "6.12.0" + "@wdio/utils" "6.11.0" + chrome-launcher "^0.13.1" + edge-paths "^2.1.0" + puppeteer-core "^5.1.0" + ua-parser-js "^0.7.21" + uuid "^8.0.0" + diff@3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" @@ -3158,6 +3331,14 @@ ecc-jsbn@~0.1.1: jsbn "~0.1.0" safer-buffer "^2.1.0" +edge-paths@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/edge-paths/-/edge-paths-2.2.1.tgz#d2d91513225c06514aeac9843bfce546abbf4391" + integrity sha512-AI5fC7dfDmCdKo3m5y7PkYE8m6bMqR6pvVpgtrZkkhcJXFLelUgkjrhk3kXXx8Kbw2cRaTT4LkOR7hqf39KJdw== + dependencies: + "@types/which" "^1.3.2" + which "^2.0.2" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -3170,11 +3351,6 @@ ejs@^3.1.3: dependencies: jake "^10.6.1" -ejs@~2.5.6: - version "2.5.9" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" - integrity sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ== - electron-builder@22.8.0: version "22.8.0" resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-22.8.0.tgz#d2c9fc5438c834e41fd794a271fca200165a3bad" @@ -3195,28 +3371,13 @@ electron-builder@22.8.0: update-notifier "^4.1.0" yargs "^15.3.1" -electron-chromedriver@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-8.0.0.tgz#16f6124d481e9312cc18abc16495ddc2d61f8264" - integrity sha512-d0210ExhkGOwYLXFZHQR6LISZ8UbMqXWLwjTe8Cdh44XlO4z4+6DWQfM0p7aB2Qak/An6tN732Yl98wN1ylZww== +electron-chromedriver@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/electron-chromedriver/-/electron-chromedriver-13.0.0.tgz#a553af7743215ac463e1e40e0db14d4a542ef762" + integrity sha512-fID1ms8wT7qNfoKkXHNpH0ZE8/Nclb5YmkF3O0w57OxsR8S9PxgE9CJAgaSGroxBgZ+ge1i2OU0Aq/WE/e/Neg== dependencies: - electron-download "^4.1.1" - extract-zip "^1.6.7" - -electron-download@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.1.tgz#02e69556705cc456e520f9e035556ed5a015ebe8" - integrity sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg== - dependencies: - debug "^3.0.0" - env-paths "^1.0.0" - fs-extra "^4.0.1" - minimist "^1.2.0" - nugget "^2.0.1" - path-exists "^3.0.0" - rc "^1.2.1" - semver "^5.4.1" - sumchecker "^2.0.2" + "@electron/get" "^1.12.4" + extract-zip "^2.0.0" electron-is-accelerator@^0.1.0: version "0.1.2" @@ -3354,7 +3515,7 @@ encoding@0.1.12: dependencies: iconv-lite "~0.4.13" -end-of-stream@^1.0.0, end-of-stream@^1.1.0: +end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -3385,11 +3546,6 @@ enquirer@^2.3.6: dependencies: ansi-colors "^4.1.1" -env-paths@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" - integrity sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA= - env-paths@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" @@ -3730,6 +3886,11 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + exit@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -3837,15 +3998,16 @@ extract-zip@^1.0.3: mkdirp "0.5.1" yauzl "2.4.1" -extract-zip@^1.6.7: - version "1.7.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" - integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== +extract-zip@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== dependencies: - concat-stream "^1.6.2" - debug "^2.6.9" - mkdirp "^0.5.4" + debug "^4.1.1" + get-stream "^5.1.0" yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" extsprintf@1.3.0: version "1.3.0" @@ -3862,6 +4024,11 @@ fast-deep-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + fast-deep-equal@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" @@ -4135,15 +4302,6 @@ fs-extra@9.0.0: jsonfile "^6.0.1" universalify "^1.0.0" -fs-extra@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -4234,7 +4392,7 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gaze@^1.0.0, gaze@~1.1.2: +gaze@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== @@ -4265,6 +4423,11 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== +get-port@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -4468,6 +4631,23 @@ globule@^1.0.0: lodash "~4.17.12" minimatch "~3.0.2" +got@^11.0.2, got@^11.8.0: + version "11.8.2" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599" + integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.1" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -4490,7 +4670,7 @@ graceful-fs@4.1.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.4.tgz#ef089d2880f033b011823ce5c8fae798da775dbd" integrity sha1-7widKIDwM7ARgjzlyPrnmNp3Xb0= -graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== @@ -4865,6 +5045,22 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +https-proxy-agent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b" + integrity sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg== + dependencies: + agent-base "5" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -4906,10 +5102,10 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== ignore@^3.3.3: version "3.3.10" @@ -5007,7 +5203,7 @@ inline-style-prefixer@^6.0.0: dependencies: css-in-js-utils "^2.0.0" -inquirer@^3.0.6, inquirer@~3.3.0: +inquirer@^3.0.6: version "3.3.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== @@ -5173,6 +5369,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -5350,6 +5551,13 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + is-yarn-global@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" @@ -5488,6 +5696,11 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -5607,6 +5820,13 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +keyv@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254" + integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA== + dependencies: + json-buffer "3.0.1" + killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" @@ -5703,6 +5923,14 @@ lie@*: dependencies: immediate "~3.0.5" +lighthouse-logger@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/lighthouse-logger/-/lighthouse-logger-1.3.0.tgz#ba6303e739307c4eee18f08249524e7dafd510db" + integrity sha512-BbqAKApLb9ywUli+0a+PcV04SyJ/N1q/8qgCNe6U97KbPCS1BTksEuHFLYdvc8DltuhfxIUBqDZsC0bBGtl3lA== + dependencies: + debug "^2.6.9" + marky "^1.2.2" + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -5829,6 +6057,11 @@ lodash-es@^4.2.1: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + lodash.compact@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash.compact/-/lodash.compact-3.0.1.tgz#540ce3837745975807471e16b4a2ba21e7256ca5" @@ -5839,6 +6072,16 @@ lodash.cond@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" integrity sha1-9HGh2khr5g9quVXRcRVSPdHSVdU= +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" + integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= + lodash.flatten@^4.2.0, lodash.flatten@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" @@ -5854,11 +6097,36 @@ lodash.isequal@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= +lodash.isobject@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" + integrity sha1-PI+41bW/S/kK4G4U8qUwpO2TXh0= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + lodash.isstring@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= +lodash.merge@^4.6.1: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + +lodash.zip@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" + integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA= + lodash@4.17.11: version "4.17.11" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" @@ -5869,7 +6137,7 @@ lodash@^3.10.1: resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= -lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.12, lodash@~4.17.5: +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.12, lodash@~4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -5911,7 +6179,12 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" -loglevel@^1.6.8: +loglevel-plugin-prefix@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/loglevel-plugin-prefix/-/loglevel-plugin-prefix-0.8.4.tgz#2fe0e05f1a820317d98d8c123e634c1bd84ff644" + integrity sha512-WpG9CcFAOjz/FtNht+QJeGpvVl/cdR6P0z6OcXSkr8wFJOsV2GRj2j10JLfjuA4aYkcKCNIEqRGCyTife9R8/g== + +loglevel@^1.6.0, loglevel@^1.6.8: version "1.7.1" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== @@ -5995,6 +6268,11 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +marky@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/marky/-/marky-1.2.2.tgz#4456765b4de307a13d263a69b0c79bf226e68323" + integrity sha512-k1dB2HNeaNyORco8ulVEhctyEGkKHb2YWAhDsxeFlW2nROIirsctBYzKwwS3Vza+sKTS1zO4Z+n9/+9WbGLIxQ== + matcher@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-2.1.0.tgz#64e1041c15b993e23b786f93320a7474bf833c28" @@ -6035,7 +6313,7 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.1.0, meow@^3.3.0: +meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= @@ -6172,6 +6450,11 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -6203,16 +6486,11 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: +minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minimist@~0.0.1: - version "0.0.10" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" - integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= - minipass@^2.3.4, minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" @@ -6251,6 +6529,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -6258,14 +6541,7 @@ mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: dependencies: minimist "0.0.8" -mkdirp@^0.5.4, mkdirp@~0.5.1: - version "0.5.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" - integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== - dependencies: - minimist "^1.2.5" - -mkdirp@^0.5.5: +mkdirp@^0.5.3, mkdirp@^0.5.5: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== @@ -6277,6 +6553,13 @@ mkdirp@^1.0.3: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mkdirp@~0.5.1: + version "0.5.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.4.tgz#fd01504a6797ec5c9be81ff43d204961ed64a512" + integrity sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw== + dependencies: + minimist "^1.2.5" + mkpath@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-0.1.0.tgz#7554a6f8d871834cc97b5462b122c4c124d6de91" @@ -6474,6 +6757,11 @@ node-fetch@2.3.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" integrity sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA== +node-fetch@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== + node-forge@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" @@ -6587,7 +6875,7 @@ normalize-package-data@^3.0.0: semver "^7.3.4" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.1.1: +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= @@ -6604,6 +6892,11 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-conf@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" @@ -6612,11 +6905,6 @@ npm-conf@^1.1.3: config-chain "^1.1.11" pify "^3.0.0" -npm-install-package@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/npm-install-package/-/npm-install-package-2.1.0.tgz#d7efe3cfcd7ab00614b896ea53119dc9ab259125" - integrity sha1-1+/jz816sAYUuJbqUxGdyaslkSU= - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -6641,19 +6929,6 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: gauge "~2.7.3" set-blocking "~2.0.0" -nugget@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" - integrity sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA= - dependencies: - debug "^2.1.3" - minimist "^1.1.0" - pretty-bytes "^1.0.2" - progress-stream "^1.1.0" - request "^2.45.0" - single-line-log "^1.1.2" - throttleit "0.0.2" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -6696,11 +6971,6 @@ object-keys@^1.0.12, object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= - object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -6760,14 +7030,6 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -optimist@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" - integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= - dependencies: - minimist "~0.0.1" - wordwrap "~0.0.2" - optionator@^0.8.2: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -6819,6 +7081,11 @@ p-cancelable@^1.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -7209,28 +7476,17 @@ prettier@1.19.0: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.0.tgz#3bec4489d5eebcd52b95ddd2c22467b5c852fde1" integrity sha512-GlAIjk6DjkNT6u/Bw5QCWrbzh9YlLKwwmJT//1YiCR3WDpZDnyss64aXHQZgF8VKeGlWnX6+tGsKSVxsZT/gtA== -pretty-bytes@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-1.0.4.tgz#0a22e8210609ad35542f8c8d5d2159aff0751c84" - integrity sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ= - dependencies: - get-stdin "^4.0.1" - meow "^3.1.0" +printj@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + integrity sha512-zA2SmoLaxZyArQTOPj5LXecR+RagfPSU5Kw1qP+jkWeNlrq+eJZyY2oS68SU1Z/7/myXM4lo9716laOFAVStCQ== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress-stream@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-1.2.0.tgz#2cd3cfea33ba3a89c9c121ec3347abe9ab125f77" - integrity sha1-LNPP6jO6OonJwSHsM0er6asSX3c= - dependencies: - speedometer "~0.1.2" - through2 "~0.2.3" - -progress@^2.0.0, progress@^2.0.3: +progress@^2.0.0, progress@^2.0.1, progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -7276,6 +7532,11 @@ proxy-addr@~2.0.5: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -7316,7 +7577,25 @@ pupa@^2.0.1: dependencies: escape-goat "^2.0.0" -q@^1.1.2, q@~1.5.0: +puppeteer-core@^5.1.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-5.5.0.tgz#dfb6266efe5a933cbf1a368d27025a6fd4f5a884" + integrity sha512-tlA+1n+ziW/Db03hVV+bAecDKse8ihFRXYiEypBe9IlLRvOCzYFG6qrCMBYK34HO/Q/Ecjc+tvkHRAfLVH+NgQ== + dependencies: + debug "^4.1.0" + devtools-protocol "0.0.818844" + extract-zip "^2.0.0" + https-proxy-agent "^4.0.0" + node-fetch "^2.6.1" + pkg-dir "^4.2.0" + progress "^2.0.1" + proxy-from-env "^1.0.0" + rimraf "^3.0.2" + tar-fs "^2.0.0" + unbzip2-stream "^1.3.3" + ws "^7.2.3" + +q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= @@ -7366,6 +7645,11 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -7480,7 +7764,7 @@ rc-util@^4.0.4, rc-util@^4.15.3, rc-util@^4.4.0: react-lifecycles-compat "^3.0.4" shallowequal "^1.1.0" -rc@^1.2.1, rc@^1.2.8: +rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7728,7 +8012,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^1.1.8, readable-stream@~1.1.9: +readable-stream@^1.1.8: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= @@ -7738,7 +8022,7 @@ readable-stream@^1.1.8, readable-stream@~1.1.9: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.5: +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -7751,7 +8035,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6: +readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -7760,6 +8044,13 @@ readable-stream@^3.0.6: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdir-glob@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.1.tgz#f0e10bb7bf7bfa7e0add8baffdc54c3f7dbee6c4" + integrity sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA== + dependencies: + minimatch "^3.0.4" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -7907,7 +8198,7 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2.x, request@^2.45.0, request@^2.83.0, request@^2.87.0, request@^2.88.0, request@^2.88.2: +request@2.x, request@^2.87.0, request@^2.88.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -7966,6 +8257,11 @@ resize-observer-polyfill@^1.5.1: resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== +resolve-alpn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.0.tgz#058bb0888d1cd4d12474e9a4b6eb17bdd5addc44" + integrity sha512-e4FNQs+9cINYMO5NMFc6kOUCdohjqFPSgMuwuZAOUWqrfWsen+Yjy5qZFkV5K7VO7tFSLKcUL97olkED7sCBHA== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -8032,6 +8328,20 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +responselike@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.0.tgz#26391bcc3174f750f9a79eacc40a12a5c42d7723" + integrity sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw== + dependencies: + lowercase-keys "^2.0.0" + +resq@^1.9.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/resq/-/resq-1.10.1.tgz#c05d1b3808016cceec4d485ceb375acb49565f53" + integrity sha512-zhp1iyUH02MLciv3bIM2bNtTFx/fqRsK4Jk73jcPqp00d/sMTTjOtjdTMAcgjrQKGx5DvQ/HSpeqaMW0atGRJA== + dependencies: + fast-deep-equal "^2.0.1" + restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -8058,10 +8368,10 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -rgb2hex@^0.1.9: - version "0.1.10" - resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.1.10.tgz#4fdd432665273e2d5900434940ceba0a04c8a8a8" - integrity sha512-vKz+kzolWbL3rke/xeTE2+6vHmZnNxGyDnaVW4OckntAIcc7DcZzWkQSfxMDwqHS8vhgySnIFyBUH7lIk6PxvQ== +rgb2hex@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/rgb2hex/-/rgb2hex-0.2.3.tgz#8aa464c517b8a26c7a79d767dabaec2b49ee78ec" + integrity sha512-clEe0m1xv+Tva1B/TOepuIcvLAxP0U+sCDfgt1SX1HmI2Ahr5/Cd/nzJM1e78NKVtWdoo0s33YehpFA8UfIShQ== rimraf@2, rimraf@^2.2.8, rimraf@^2.6.3: version "2.7.1" @@ -8158,7 +8468,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== @@ -8279,7 +8589,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0: +"semver@2 || 3 || 4 || 5", semver@^5.0.1, semver@^5.3.0, semver@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -8337,6 +8647,13 @@ serialize-error@^5.0.0: dependencies: type-fest "^0.8.0" +serialize-error@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-8.1.0.tgz#3a069970c712f78634942ddd50fbbc0eaebe2f67" + integrity sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ== + dependencies: + type-fest "^0.20.2" + serialize-javascript@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" @@ -8445,13 +8762,6 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -single-line-log@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-1.1.2.tgz#c2f83f273a3e1a16edb0995661da0ed5ef033364" - integrity sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q= - dependencies: - string-width "^1.0.1" - sinon@9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d" @@ -8546,7 +8856,7 @@ source-list-map@^2.0.1: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: +source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== @@ -8651,22 +8961,17 @@ spdy@^4.0.2: select-hose "^2.0.0" spdy-transport "^3.0.0" -spectron@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/spectron/-/spectron-10.0.1.tgz#d89fdd3c9625c7dbb5d1f047fda7cb922eda0125" - integrity sha512-eMAOr7ovYf+e6+DhkoxVWAMRfZvLJMjtZKwWYkL56fv3Ij6rxhYLjOxybKj0phgMYZ7o2cX5zu2NoyiUM756CA== +spectron@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/spectron/-/spectron-15.0.0.tgz#9c0e254b2be3f0725a81b8343092b9d0108439c7" + integrity sha512-eErHqymkEVb6H+LPZQoDYvWEv93o3nhxL7HXXdmC61ncV0jBckh8x3Qt6j+As2c1n0C/hKG9A2H1NnwGwD6agg== dependencies: - "@types/webdriverio" "^4.8.0" + "@electron/remote" "^1.1.0" dev-null "^0.1.1" - electron-chromedriver "^8.0.0" - request "^2.87.0" - split "^1.0.0" - webdriverio "^4.13.0" - -speedometer@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" - integrity sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0= + electron-chromedriver "^13.0.0" + got "^11.8.0" + split "^1.0.1" + webdriverio "^6.9.1" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -8675,7 +8980,7 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -split@^1.0.0: +split@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== @@ -8936,13 +9241,6 @@ substyle@^9.1.0: "@babel/runtime" "^7.3.4" invariant "^2.2.4" -sumchecker@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e" - integrity sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4= - dependencies: - debug "^2.2.0" - sumchecker@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" @@ -8990,13 +9288,6 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-color@~5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.0.1.tgz#1c5331f22250c84202805b2f17adf16699f3a39a" - integrity sha512-7FQGOlSQ+AQxBNXJpVDj8efTA/FtyB5wcNE1omXXJ0cq6jm1jjDwuROlYDbnzHqdNPqliWFhcioCWSyav+xBnA== - dependencies: - has-flag "^2.0.0" - symbol-observable@^1.0.3, symbol-observable@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -9024,18 +9315,26 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== -tar-stream@^1.5.0: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4, tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" tar@4.4.8: version "4.4.8" @@ -9134,19 +9433,6 @@ throttle-debounce@^3.0.1: resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== -throttleit@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-0.0.2.tgz#cfedf88e60c00dd9697b61fdd2a8343a9b680eaf" - integrity sha1-z+34jmDADdlpe2H90qg0OptoDq8= - -through2@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" - integrity sha1-6zKE2k6jEbbMis42U3SKUqvyWj8= - dependencies: - readable-stream "~1.1.9" - xtend "~2.1.1" - through@2, through@^2.3.6, through@^2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -9188,11 +9474,6 @@ to-arraybuffer@1.0.1: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= -to-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -9411,6 +9692,11 @@ type-fest@^0.18.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" @@ -9455,11 +9741,24 @@ typings-for-css-modules-loader@^1.7.0: graceful-fs "4.1.4" loader-utils "0.2.16" +ua-parser-js@^0.7.21: + version "0.7.28" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31" + integrity sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g== + uc.micro@^1.0.1: version "1.0.6" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== +unbzip2-stream@^1.3.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + underscore.string@~3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.2.3.tgz#806992633665d5e5fcb4db1fb3a862eb68e9e6da" @@ -9576,7 +9875,7 @@ url-parse@^1.4.3, url-parse@^1.5.1: querystringify "^2.1.1" requires-port "^1.0.0" -url@^0.11.0, url@~0.11.0: +url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= @@ -9626,6 +9925,11 @@ uuid@^3.3.2, uuid@^3.4.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.0.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + v8-compile-cache@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -9675,38 +9979,46 @@ wbuf@^1.1.0, wbuf@^1.7.3: dependencies: minimalistic-assert "^1.0.0" -wdio-dot-reporter@~0.0.8: - version "0.0.10" - resolved "https://registry.yarnpkg.com/wdio-dot-reporter/-/wdio-dot-reporter-0.0.10.tgz#facfb7c9c5984149951f59cbc3cd0752101cf0e0" - integrity sha512-A0TCk2JdZEn3M1DSG9YYbNRcGdx/YRw19lTiRpgwzH4qqWkO/oRDZRmi3Snn4L2j54KKTfPalBhlOtc8fojVgg== - -webdriverio@^4.13.0: - version "4.14.4" - resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-4.14.4.tgz#f7a94e9a6530819796088f42b009833d83de0386" - integrity sha512-Knp2vzuzP5c5ybgLu+zTwy/l1Gh0bRP4zAr8NWcrStbuomm9Krn9oRF0rZucT6AyORpXinETzmeowFwIoo7mNA== +webdriver@6.12.1: + version "6.12.1" + resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-6.12.1.tgz#30eee65340ea5124aa564f99a4dbc7d2f965b308" + integrity sha512-3rZgAj9o2XHp16FDTzvUYaHelPMSPbO1TpLIMUT06DfdZjNYIzZiItpIb/NbQDTPmNhzd9cuGmdI56WFBGY2BA== dependencies: - archiver "~2.1.0" - babel-runtime "^6.26.0" - css-parse "^2.0.0" - css-value "~0.0.1" - deepmerge "~2.0.1" - ejs "~2.5.6" - gaze "~1.1.2" - glob "~7.1.1" + "@wdio/config" "6.12.1" + "@wdio/logger" "6.10.10" + "@wdio/protocols" "6.12.0" + "@wdio/utils" "6.11.0" + got "^11.0.2" + lodash.merge "^4.6.1" + +webdriverio@^6.9.1: + version "6.12.1" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-6.12.1.tgz#5b6f1167373bd7a154419d8a930ef1ffda9d0537" + integrity sha512-Nx7ge0vTWHVIRUbZCT+IuMwB5Q0Q5nLlYdgnmmJviUKLuc3XtaEBkYPTbhHWHgSBXsPZMIc023vZKNkn+6iyeQ== + dependencies: + "@types/puppeteer-core" "^5.4.0" + "@wdio/config" "6.12.1" + "@wdio/logger" "6.10.10" + "@wdio/repl" "6.11.0" + "@wdio/utils" "6.11.0" + archiver "^5.0.0" + atob "^2.1.2" + css-shorthand-properties "^1.1.1" + css-value "^0.0.1" + devtools "6.12.1" + fs-extra "^9.0.1" + get-port "^5.1.1" grapheme-splitter "^1.0.2" - inquirer "~3.3.0" - json-stringify-safe "~5.0.1" - mkdirp "~0.5.1" - npm-install-package "~2.1.0" - optimist "~0.6.1" - q "~1.5.0" - request "^2.83.0" - rgb2hex "^0.1.9" - safe-buffer "~5.1.1" - supports-color "~5.0.0" - url "~0.11.0" - wdio-dot-reporter "~0.0.8" - wgxpath "~1.0.0" + lodash.clonedeep "^4.5.0" + lodash.isobject "^3.0.2" + lodash.isplainobject "^4.0.6" + lodash.zip "^4.2.0" + minimatch "^3.0.4" + puppeteer-core "^5.1.0" + resq "^1.9.1" + rgb2hex "0.2.3" + serialize-error "^8.0.0" + webdriver "6.12.1" webpack-cli@4.6.0: version "4.6.0" @@ -9883,11 +10195,6 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== -wgxpath@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wgxpath/-/wgxpath-1.0.0.tgz#eef8a4b9d558cc495ad3a9a2b751597ecd9af690" - integrity sha1-7vikudVYzEla06mit1FZfs2a9pA= - which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -9938,11 +10245,6 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -9999,23 +10301,16 @@ ws@^6.2.1: dependencies: async-limiter "~1.0.0" +ws@^7.2.3: + version "7.5.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.3.tgz#160835b63c7d97bfab418fc1b8a9fced2ac01a74" + integrity sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg== + xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= - dependencies: - object-keys "~0.4.0" - y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" @@ -10115,12 +10410,11 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zip-stream@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" - integrity sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ= +zip-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" + integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== dependencies: - archiver-utils "^1.3.0" - compress-commons "^1.2.0" - lodash "^4.8.0" - readable-stream "^2.0.0" + archiver-utils "^2.1.0" + compress-commons "^4.1.0" + readable-stream "^3.6.0"