From 79585d5b84d814932783c97bae851ac361b548a5 Mon Sep 17 00:00:00 2001 From: Kelson Warner Date: Tue, 22 Dec 2020 08:27:42 -0800 Subject: [PATCH] style(automatting and quality): Add prettier and eslint to run on commit and build, deprecate jshint (#336) * style(autoformat and quality checks): Adding eslint and prettier, deprecating jshint * style(autoformat and quality checks):AMP-32165 update makefile * style(autoformat and quality checks): get all files to pass prettier and eslint * style(autoformat and quality checks): Adding husky pre-commit hooks * style(autoformatting): fix order of lint staged commands * ci: add eslint and prettier checks to test * build: remove eslint and prettier checks from makefile * build: added website directory to prettier and eslint checks --- .eslintrc.json | 26 + .github/workflows/test.yml | 8 + .jshintrc | 94 - .npmignore | 3 +- .prettierignore | 1 + .prettierrc.json | 6 + .vscode/settings.json | 24 + Makefile | 5 +- package.json | 28 +- scripts/readme.js | 13 +- scripts/version.js | 9 +- src/amplitude-client.js | 448 +- src/amplitude-snippet.js | 85 +- src/amplitude.js | 73 +- src/base-cookie.js | 2 +- src/base64.js | 172 +- src/base64Id.js | 2 +- src/constants.js | 6 +- src/cookie.js | 29 +- src/cookiestorage.js | 32 +- src/get-host.js | 2 +- src/identify.js | 24 +- src/index.js | 12 +- src/language.js | 10 +- src/localstorage.js | 37 +- src/metadata-storage.js | 29 +- src/revenue.js | 6 +- src/type.js | 17 +- src/utf8.js | 84 +- src/utils.js | 27 +- src/utm.js | 3 +- src/uuid.js | 43 +- src/xhr.js | 10 +- test/amplitude-client.js | 1757 +++---- test/amplitude.js | 1001 ++-- test/base-cookie.js | 20 +- test/base64.js | 10 +- test/base64Id.js | 2 +- test/browser/chai.js | 8729 +++++++++++++++++---------------- test/browser/require.js | 941 +++- test/browser/server.js | 9 +- test/browser/sinon.js | 8782 +++++++++++++++++----------------- test/cookiestorage.js | 12 +- test/identify.js | 85 +- test/language.js | 116 +- test/md5.js | 10 +- test/mock-cookie.js | 12 +- test/revenue.js | 31 +- test/snippet-tests.js | 23 +- test/top-domain.js | 6 +- test/ua-parser.js | 2296 +++++++-- test/utils.js | 174 +- test/utm.js | 29 +- test/uuid.js | 4 +- website/docusaurus.config.js | 3 +- website/generate-jsdoc.js | 83 +- yarn.lock | 733 ++- 57 files changed, 14730 insertions(+), 11508 deletions(-) create mode 100644 .eslintrc.json delete mode 100644 .jshintrc create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 .vscode/settings.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..0c7d3e65 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,26 @@ +{ + "extends": ["eslint:recommended", "plugin:prettier/recommended"], + "plugins": ["prettier", "@amplitude/eslint-plugin-amplitude"], + "env": { "es6": true, "browser": true, "node": true, "mocha": true }, + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2018 + }, + "rules": { + "prettier/prettier": "error", + "no-prototype-builtins": "off" + }, + "globals": { + "BUILD_COMPAT_REACT_NATIVE": "readonly", + "BUILD_COMPAT_LOCAL_STORAGE": "readonly", + "BUILD_COMPAT_SNIPPET": "readonly", + "BUILD_COMPAT_2_0": "readonly", + "assert": "readonly", + "expect": "readonly", + "should": "readonly", + "define": "readonly", + "amplitude": "readonly", + "opera": "readonly", + "ActiveXObject": "readonly" + } +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e11edc4e..48d524f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -30,6 +30,14 @@ jobs: run: | yarn install --frozen-lockfile + - name: prettier check + run: | + yarn run lint:prettier + + - name: eslint check + run: | + yarn run lint:eslint + - name: Build and run tests run: | make test diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index 1eb270d1..00000000 --- a/.jshintrc +++ /dev/null @@ -1,94 +0,0 @@ -{ - // JSHint Default Configuration File (as on JSHint website) - // See http://jshint.com/docs/ for more details - - "maxerr" : 50, // {int} Maximum error before stopping - - // Enforcing - "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : false, // true: Identifiers must be in camelCase - "curly" : true, // true: Require {} for every new block or scope - "eqeqeq" : true, // true: Require triple equals (===) for comparison - "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() - "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc. - "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` - "indent" : 2, // {int} Number of spaces to use for indentation - "latedef" : false, // true: Require variables/functions to be defined before being used - "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : true, // true: Prohibit use of empty blocks - "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters. - "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment) - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : false, // Quotation mark consistency: - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : true, // true: Require all defined variables be used - "strict" : false, // true: Requires all functions run in ES5 Strict Mode - "maxparams" : false, // {int} Max number of formal params allowed per function - "maxdepth" : false, // {int} Max depth of nested blocks (within functions) - "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : false, // {int} Max cyclomatic complexity per function - "maxlen" : false, // {int} Max number of characters per line - - // Relaxing - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : false, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : false, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : false, // true: Tolerate defining variables inside control statements - "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : false, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : false, // true: Tolerate functions being defined in loops - "multistr" : false, // true: Tolerate multi-line strings - "noyield" : false, // true: Tolerate generator functions with no yield statement in them. - "notypeof" : false, // true: Tolerate invalid typeof operator values - "proto" : false, // true: Tolerate using the `__proto__` property - "scripturl" : false, // true: Tolerate script-targeted URLs - "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : false, // true: Tolerate using this in a non-constructor function - - // Environments - "browser" : true, // Web Browser (window, document, etc) - "browserify" : false, // Browserify (node.js code in the browser) - "couch" : false, // CouchDB - "devel" : true, // Development/debugging (alert, confirm, etc) - "esversion" : 9, // Support ES version 9 syntax - "dojo" : false, // Dojo Toolkit - "jasmine" : false, // Jasmine - "jquery" : false, // jQuery - "mocha" : true, // Mocha - "mootools" : false, // MooTools - "node" : true, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "qunit" : false, // QUnit - "rhino" : false, // Rhino - "shelljs" : false, // ShellJS - "worker" : false, // Web Workers - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - - // Custom Globals - "globals" : { // additional predefined global variables - "BUILD_COMPAT_2_0": true, - "BUILD_COMPAT_SNIPPET": true, - "BUILD_COMPAT_LOCAL_STORAGE": true, - "BUILD_COMPAT_REACT_NATIVE": true, - "assert": true - } -} diff --git a/.npmignore b/.npmignore index d3359d22..d2cf5287 100644 --- a/.npmignore +++ b/.npmignore @@ -14,7 +14,8 @@ build karma.conf.js scripts .npmignore -.jshintrc +.prettierrc.json +.eslintrc.json amplitude.min.js amplitude-snippet.min.js amplitude.nocompat.min.js diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..dd449725 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +*.md diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..9fbc63fd --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,6 @@ +{ + "printWidth": 120, + "proseWrap": "always", + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..d7ff04ac --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,24 @@ +{ + "editor.codeActionsOnSave": { + "source.fixAll": true + }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnType": true, + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.rulers": [120], + "editor.tabSize": 2, + "files.autoSave": "onWindowChange", + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "search.exclude": { + "**/node_modules/": true, + "**/build/": true, + "**/dist/": true + }, + "[json]": { + "editor.formatOnType": false, + "editor.formatOnPaste": false, + "editor.formatOnSave": false + } +} diff --git a/Makefile b/Makefile index 050250f7..1efef90a 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ TESTS = $(wildcard test/*.js) BINS = node_modules/.bin MINIFY = $(BINS)/uglifyjs JSDOC = $(BINS)/jsdoc -JSHINT = $(BINS)/jshint BUILD_DIR = build PROJECT = amplitude OUT = $(PROJECT).js @@ -65,9 +64,8 @@ README.md: $(SNIPPET_OUT) version # $(OUT): node_modules $(SRC) package.json rollup.config.js rollup.min.js rollup.native.js rollup.esm.js rollup.umd.js rollup.umd.min.js - @$(JSHINT) --verbose $(SRC) @NODE_ENV=production $(ROLLUP) --config rollup.config.js # is the snippet build config - @NODE_ENV=production $(ROLLUP) --config rollup.esm.js # does not concat dependencies, only has module and dependencies + @NODE_ENV=production $(ROLLUP) --config rollup.esm.js # does not concat dependencies, only has module and dependencies @NODE_ENV=production $(ROLLUP) --config rollup.umd.js # generates npm version, also usable in require js app @NODE_ENV=production $(ROLLUP) --config rollup.native.js # generates react native build @NODE_ENV=production $(ROLLUP) --config rollup.nocompat.js # may be able to remove @@ -79,7 +77,6 @@ $(OUT): node_modules $(SRC) package.json rollup.config.js rollup.min.js rollup.n # Target for minified `amplitude-snippet.js` file. # $(SNIPPET_OUT): $(SRC) $(SNIPPET) - @$(JSHINT) --verbose $(SNIPPET) @$(MINIFY) $(SNIPPET) -m -b max-line-len=80,beautify=false | awk 'NF' > $(SNIPPET_OUT) $(SEGMENT_SNIPPET_OUT): $(SRC) $(SNIPPET) diff --git a/package.json b/package.json index 010d921d..ad01c3e8 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "query-string": "5" }, "devDependencies": { + "@amplitude/eslint-plugin-amplitude": "^1.0.1", "@babel/core": "^7.3.4", "@babel/plugin-external-helpers": "^7.2.0", "@babel/plugin-proposal-object-rest-spread": "^7.3.4", @@ -32,11 +33,14 @@ "@semantic-release/git": "^9.0.0", "chai": "^4.1.2", "date-fns": "^1.30.1", + "eslint": "^7.15.0", + "eslint-config-prettier": "^7.0.0", + "eslint-plugin-prettier": "^3.3.0", "express": "^4.16.2", "fs-extra": "^4.0.2", + "husky": "^4.3.6", "jsdoc": "^3.6.3", "jsdoc-to-markdown": "^6.0.1", - "jshint": "^2.9.6", "karma": "^4.0.0", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^2.2.0", @@ -46,8 +50,9 @@ "karma-sauce-launcher": "^2.0.2", "karma-sinon": "^1.0.5", "karma-sourcemap-loader": "^0.3.7", + "lint-staged": "^10.5.3", "mocha": "^4.0.1", - "prettier": "^2.1.1", + "prettier": "^2.2.1", "requirejs": "^2.3.6", "rollup": "^1.4.1", "rollup-plugin-babel": "^4.3.2", @@ -67,7 +72,13 @@ "docs:install": "cd website/ && yarn install", "docs:generate-jsdoc": "cd website && yarn generate-jsdoc", "docs:start": "cd website/ && yarn start", - "docs:deploy": "cd website/ && yarn deploy" + "docs:deploy": "cd website/ && yarn deploy", + "lint": "yarn run lint:prettier && yarn run lint:eslint", + "lint:prettier": "prettier --check \"{src,test,scripts,website}/**/*.js\"", + "lint:eslint": "eslint \"{src,test,scripts,website}/**/*.js\"", + "fix": "yarn run fix:eslint && yarn run fix:prettier", + "fix:prettier": "prettier --write \"{src,test,scripts,website}/**/*.js\"", + "fix:eslint": "eslint --fix \"{src,test,scripts,website}/**/*.js\"" }, "bugs": { "url": "https://github.com/amplitude/amplitude-javascript/issues" @@ -75,5 +86,16 @@ "homepage": "https://github.com/amplitude/amplitude-javascript#readme", "directories": { "test": "test" + }, + "husky": { + "hooks": { + "pre-commit": "lint-staged" + } + }, + "lint-staged": { + "{src,test,scripts,website}/**/*.js": [ + "prettier --write", + "eslint --fix" + ] } } diff --git a/scripts/readme.js b/scripts/readme.js index 2c865878..4fa9f989 100644 --- a/scripts/readme.js +++ b/scripts/readme.js @@ -3,16 +3,17 @@ var path = require('path'); // Update the README with the minified snippet. var cwd = process.cwd(); -var readmeFilename = path.join(cwd, "README.md"); +var readmeFilename = path.join(cwd, 'README.md'); var readme = fs.readFileSync(readmeFilename, 'utf-8'); -var snippetFilename = path.join(cwd, "amplitude-snippet.min.js"); +var snippetFilename = path.join(cwd, 'amplitude-snippet.min.js'); var snippet = fs.readFileSync(snippetFilename, 'utf-8'); var script = -' '; + ' '; var updated = readme.replace(/ +/, script); fs.writeFileSync(readmeFilename, updated); diff --git a/scripts/version.js b/scripts/version.js index 2df50db3..3d1f5d17 100644 --- a/scripts/version.js +++ b/scripts/version.js @@ -1,7 +1,6 @@ const fs = require('fs'); const path = require('path'); -const {version} = require('../package'); -const {format} = require('date-fns'); +const { version } = require('../package'); const crypto = require('crypto'); const cwd = process.cwd(); @@ -9,9 +8,7 @@ const cwd = process.cwd(); function replaceTextInFile(filepath, match, replacement) { var filename = path.join(cwd, filepath); - const updatedText = fs - .readFileSync(filename, 'utf-8') - .replace(match, replacement); + const updatedText = fs.readFileSync(filename, 'utf-8').replace(match, replacement); if (updatedText.indexOf(replacement) === -1) { throw new Error(`Failed to update text in ${filepath}`); @@ -35,7 +32,7 @@ const sdkText = fs.readFileSync(path.join('.', `amplitude.min.js`), 'utf-8'); const hash = crypto.createHash('sha384').update(sdkText).digest('base64'); replaceTextInFile( path.join('src', 'amplitude-snippet.js'), - /as.integrity = 'sha384-[a-zA-Z0-9+\/]+';/, + /as.integrity = 'sha384-[a-zA-Z0-9+/]+';/, `as.integrity = 'sha384-${hash}';`, ); diff --git a/src/amplitude-client.js b/src/amplitude-client.js index e031a684..9bcf3b1f 100644 --- a/src/amplitude-client.js +++ b/src/amplitude-client.js @@ -5,7 +5,7 @@ import cookieStorage from './cookiestorage'; import MetadataStorage from '../src/metadata-storage'; import getUtmData from './utm'; // Urchin Tracking Module import Identify from './identify'; -import localStorage from './localstorage'; // jshint ignore:line +import localStorage from './localstorage'; import md5 from 'blueimp-md5'; import Request from './xhr'; import Revenue from './revenue'; @@ -38,13 +38,15 @@ if (BUILD_COMPAT_REACT_NATIVE) { */ var AmplitudeClient = function AmplitudeClient(instanceName) { if (!isBrowserEnv()) { - utils.log.warn('amplitude-js will not work in a non-browser environment. If you are planning to add Amplitude to a node environment, please use @amplitude/node'); + utils.log.warn( + 'amplitude-js will not work in a non-browser environment. If you are planning to add Amplitude to a node environment, please use @amplitude/node', + ); } this._instanceName = utils.isEmptyString(instanceName) ? Constants.DEFAULT_INSTANCE : instanceName.toLowerCase(); this._unsentEvents = []; this._unsentIdentifys = []; this._ua = new UAParser(navigator.userAgent).getResult(); - this.options = {...DEFAULT_OPTIONS, trackingOptions: {...DEFAULT_OPTIONS.trackingOptions}}; + this.options = { ...DEFAULT_OPTIONS, trackingOptions: { ...DEFAULT_OPTIONS.trackingOptions } }; this.cookieStorage = new cookieStorage().getStorage(); this._q = []; // queue for proxied functions before script load this._sending = false; @@ -86,10 +88,12 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o try { _parseConfig(this.options, opt_config); - + if (isBrowserEnv() && window.Prototype !== undefined && Array.prototype.toJSON) { prototypeJsFix(); - utils.log.warn('Prototype.js injected Array.prototype.toJSON. Deleting Array.prototype.toJSON to prevent double-stringify'); + utils.log.warn( + 'Prototype.js injected Array.prototype.toJSON. Deleting Array.prototype.toJSON to prevent double-stringify', + ); } if (this.options.cookieName !== DEFAULT_OPTIONS.cookieName) { @@ -97,8 +101,9 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o } this.options.apiKey = apiKey; - this._storageSuffix = '_' + apiKey + (this._instanceName === Constants.DEFAULT_INSTANCE ? '' : '_' + this._instanceName); - this._storageSuffixV5 = apiKey.slice(0,6); + this._storageSuffix = + '_' + apiKey + (this._instanceName === Constants.DEFAULT_INSTANCE ? '' : '_' + this._instanceName); + this._storageSuffixV5 = apiKey.slice(0, 6); this._oldCookiename = this.options.cookieName + this._storageSuffix; this._unsentKey = this.options.unsentKey + this._storageSuffix; @@ -110,7 +115,7 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o expirationDays: this.options.cookieExpiration, domain: this.options.domain, secure: this.options.secureCookie, - sameSite: this.options.sameSiteCookie + sameSite: this.options.sameSiteCookie, }); this._metadataStorage = new MetadataStorage({ @@ -120,12 +125,12 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o domain: this.options.domain, secure: this.options.secureCookie, sameSite: this.options.sameSiteCookie, - storage: this.options.storage + storage: this.options.storage, }); const hasOldCookie = !!this.cookieStorage.get(this._oldCookiename); const hasNewCookie = !!this._metadataStorage.load(); - this._useOldCookie = (!hasNewCookie && hasOldCookie) && !this.options.cookieForceUpgrade; + this._useOldCookie = !hasNewCookie && hasOldCookie && !this.options.cookieForceUpgrade; const hasCookie = hasNewCookie || hasOldCookie; this.options.domain = this.cookieStorage.options().domain; @@ -139,7 +144,8 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o } var trackingOptions = _generateApiPropertiesTrackingConfig(this); - this._apiPropertiesTrackingOptions = Object.keys(trackingOptions).length > 0 ? {tracking_options: trackingOptions} : {}; + this._apiPropertiesTrackingOptions = + Object.keys(trackingOptions).length > 0 ? { tracking_options: trackingOptions } : {}; if (this.options.cookieForceUpgrade && hasOldCookie) { if (!hasNewCookie) { @@ -152,13 +158,12 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o this._pendingReadStorage = true; const initFromStorage = (storedDeviceId) => { - this.options.deviceId = this._getInitialDeviceId( - opt_config && opt_config.deviceId, storedDeviceId - ); + this.options.deviceId = this._getInitialDeviceId(opt_config && opt_config.deviceId, storedDeviceId); this.options.userId = (type(opt_userId) === 'string' && !utils.isEmptyString(opt_userId) && opt_userId) || (type(opt_userId) === 'number' && opt_userId.toString()) || - this.options.userId || null; + this.options.userId || + null; var now = new Date().getTime(); if (!this._sessionId || !this._lastEventTime || now - this._lastEventTime > this.options.sessionTimeout) { @@ -201,54 +206,66 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o if (AsyncStorage) { this._migrateUnsentEvents(() => { Promise.all([ - AsyncStorage.getItem(this._storageSuffix), - AsyncStorage.getItem(this.options.unsentKey + this._storageSuffix), - AsyncStorage.getItem(this.options.unsentIdentifyKey + this._storageSuffix), - ]).then((values) => { - if (values[0]) { - const cookieData = JSON.parse(values[0]); - if (cookieData) { - _loadCookieDataProps(this, cookieData); + AsyncStorage.getItem(this._storageSuffix), + AsyncStorage.getItem(this.options.unsentKey + this._storageSuffix), + AsyncStorage.getItem(this.options.unsentIdentifyKey + this._storageSuffix), + ]) + .then((values) => { + if (values[0]) { + const cookieData = JSON.parse(values[0]); + if (cookieData) { + _loadCookieDataProps(this, cookieData); + } + } + if (this.options.saveEvents) { + this._unsentEvents = this._parseSavedUnsentEventsString(values[1]) + .map((event) => ({ event })) + .concat(this._unsentEvents); + this._unsentIdentifys = this._parseSavedUnsentEventsString(values[2]) + .map((event) => ({ event })) + .concat(this._unsentIdentifys); } - } - if (this.options.saveEvents) { - this._unsentEvents = this._parseSavedUnsentEventsString(values[1]).map(event => ({event})).concat(this._unsentEvents); - this._unsentIdentifys = this._parseSavedUnsentEventsString(values[2]).map(event => ({event})).concat(this._unsentIdentifys); - } - if (DeviceInfo) { - Promise.all([ - DeviceInfo.getCarrier(), - DeviceInfo.getModel(), - DeviceInfo.getManufacturer(), - DeviceInfo.getVersion(), - DeviceInfo.getUniqueId(), - ]).then(values => { - this.deviceInfo = { - carrier: values[0], - model: values[1], - manufacturer: values[2], - version: values[3] - }; - initFromStorage(values[4]); + if (DeviceInfo) { + Promise.all([ + DeviceInfo.getCarrier(), + DeviceInfo.getModel(), + DeviceInfo.getManufacturer(), + DeviceInfo.getVersion(), + DeviceInfo.getUniqueId(), + ]) + .then((values) => { + this.deviceInfo = { + carrier: values[0], + model: values[1], + manufacturer: values[2], + version: values[3], + }; + initFromStorage(values[4]); + this.runQueuedFunctions(); + if (type(opt_callback) === 'function') { + opt_callback(this); + } + }) + .catch((err) => { + this.options.onError(err); + }); + } else { + initFromStorage(); this.runQueuedFunctions(); - if (type(opt_callback) === 'function') { - opt_callback(this); - } - }).catch((err) => { - this.options.onError(err); - }); - } else { - initFromStorage(); - this.runQueuedFunctions(); - } - }).catch((err) => { - this.options.onError(err); - }); + } + }) + .catch((err) => { + this.options.onError(err); + }); }); } else { if (this.options.saveEvents) { - this._unsentEvents = this._loadSavedUnsentEvents(this.options.unsentKey).map(event => ({event})).concat(this._unsentEvents); - this._unsentIdentifys = this._loadSavedUnsentEvents(this.options.unsentIdentifyKey).map(event => ({event})).concat(this._unsentIdentifys); + this._unsentEvents = this._loadSavedUnsentEvents(this.options.unsentKey) + .map((event) => ({ event })) + .concat(this._unsentEvents); + this._unsentIdentifys = this._loadSavedUnsentEvents(this.options.unsentIdentifyKey) + .map((event) => ({ event })) + .concat(this._unsentIdentifys); } initFromStorage(); this.runQueuedFunctions(); @@ -266,8 +283,7 @@ AmplitudeClient.prototype.deleteLowerLevelDomainCookies = function () { const host = getHost(); const cookieHost = - (this.options.domain && this.options.domain[0] === '.') ? - this.options.domain.slice(1) : this.options.domain; + this.options.domain && this.options.domain[0] === '.' ? this.options.domain.slice(1) : this.options.domain; if (!cookieHost) { return; @@ -279,8 +295,8 @@ AmplitudeClient.prototype.deleteLowerLevelDomainCookies = function () { const cookieHostParts = cookieHost.split('.'); for (let i = hostParts.length; i > cookieHostParts.length; --i) { - const deleteDomain = hostParts.slice(hostParts.length - i).join('.'); - baseCookie.set(this._cookieName, null, {domain: '.' + deleteDomain}); + const deleteDomain = hostParts.slice(hostParts.length - i).join('.'); + baseCookie.set(this._cookieName, null, { domain: '.' + deleteDomain }); } baseCookie.set(this._cookieName, null, {}); } @@ -295,7 +311,7 @@ AmplitudeClient.prototype._getInitialDeviceId = function (configDeviceId, stored if (this.options.deviceIdFromUrlParam) { let deviceIdFromUrlParam = this._getDeviceIdFromUrlParam(this._getUrlParams()); if (deviceIdFromUrlParam) { - return deviceIdFromUrlParam; + return deviceIdFromUrlParam; } } @@ -327,40 +343,47 @@ const _validateUnsentEventQueue = (queue) => { * @private */ AmplitudeClient.prototype._migrateUnsentEvents = function _migrateUnsentEvents(cb) { - Promise.all([ - AsyncStorage.getItem(this.options.unsentKey), - AsyncStorage.getItem(this.options.unsentIdentifyKey), - ]).then((values) => { - if (this.options.saveEvents) { - var unsentEventsString = values[0]; - var unsentIdentifyKey = values[1]; + Promise.all([AsyncStorage.getItem(this.options.unsentKey), AsyncStorage.getItem(this.options.unsentIdentifyKey)]) + .then((values) => { + if (this.options.saveEvents) { + var unsentEventsString = values[0]; + var unsentIdentifyKey = values[1]; - var itemsToSet = []; - var itemsToRemove = []; + var itemsToSet = []; + var itemsToRemove = []; - if (!!unsentEventsString) { - itemsToSet.push(AsyncStorage.setItem(this.options.unsentKey + this._storageSuffix, JSON.stringify(unsentEventsString))); - itemsToRemove.push(AsyncStorage.removeItem(this.options.unsentKey)); - } + if (unsentEventsString) { + itemsToSet.push( + AsyncStorage.setItem(this.options.unsentKey + this._storageSuffix, JSON.stringify(unsentEventsString)), + ); + itemsToRemove.push(AsyncStorage.removeItem(this.options.unsentKey)); + } - if (!!unsentIdentifyKey) { - itemsToSet.push(AsyncStorage.setItem(this.options.unsentIdentifyKey + this._storageSuffix, JSON.stringify(unsentIdentifyKey))); - itemsToRemove.push(AsyncStorage.removeItem(this.options.unsentIdentifyKey)); - } + if (unsentIdentifyKey) { + itemsToSet.push( + AsyncStorage.setItem( + this.options.unsentIdentifyKey + this._storageSuffix, + JSON.stringify(unsentIdentifyKey), + ), + ); + itemsToRemove.push(AsyncStorage.removeItem(this.options.unsentIdentifyKey)); + } - if (itemsToSet.length > 0) { - Promise.all(itemsToSet).then(() => { - Promise.all(itemsToRemove); - }).catch((err) => { - this.options.onError(err); - }); + if (itemsToSet.length > 0) { + Promise.all(itemsToSet) + .then(() => { + Promise.all(itemsToRemove); + }) + .catch((err) => { + this.options.onError(err); + }); + } } - } - }) - .then(cb) - .catch((err) => { - this.options.onError(err); - }); + }) + .then(cb) + .catch((err) => { + this.options.onError(err); + }); }; /** @@ -404,7 +427,7 @@ var _parseConfig = function _parseConfig(options, config) { // validates config value is defined, is the correct type, and some additional value sanity checks var parseValidateAndLoad = function parseValidateAndLoad(key) { if (!options.hasOwnProperty(key)) { - return; // skip bogus config values + return; // skip bogus config values } var inputValue = config[key]; @@ -414,8 +437,10 @@ var _parseConfig = function _parseConfig(options, config) { } if (expectedType === 'boolean') { options[key] = !!inputValue; - } else if ((expectedType === 'string' && !utils.isEmptyString(inputValue)) || - (expectedType === 'number' && inputValue > 0)) { + } else if ( + (expectedType === 'string' && !utils.isEmptyString(inputValue)) || + (expectedType === 'number' && inputValue > 0) + ) { options[key] = inputValue; } else if (expectedType === 'object') { _parseConfig(options[key], inputValue); @@ -474,7 +499,10 @@ AmplitudeClient.prototype._loadSavedUnsentEvents = function _loadSavedUnsentEven * Load saved events from localStorage. JSON deserializes event array. Handles case where string is corrupted. * @private */ -AmplitudeClient.prototype._parseSavedUnsentEventsString = function _parseSavedUnsentEventsString(savedUnsentEventsString, unsentKey) { +AmplitudeClient.prototype._parseSavedUnsentEventsString = function _parseSavedUnsentEventsString( + savedUnsentEventsString, + unsentKey, +) { if (utils.isEmptyString(savedUnsentEventsString)) { return []; // new app, does not have any saved events } @@ -482,10 +510,11 @@ AmplitudeClient.prototype._parseSavedUnsentEventsString = function _parseSavedUn if (type(savedUnsentEventsString) === 'string') { try { var events = JSON.parse(savedUnsentEventsString); - if (type(events) === 'array') { // handle case where JSON dumping of unsent events is corrupted + if (type(events) === 'array') { + // handle case where JSON dumping of unsent events is corrupted return events; } - } catch (e) {} + } catch (e) {} /* eslint-disable-line no-empty */ } utils.log.error('Unable to load ' + unsentKey + ' events. Restart with a new empty queue.'); return []; @@ -578,12 +607,15 @@ AmplitudeClient.prototype._sendEventsIfReady = function _sendEventsIfReady() { } // otherwise schedule an upload after 30s - if (!this._updateScheduled) { // make sure we only schedule 1 upload + if (!this._updateScheduled) { + // make sure we only schedule 1 upload this._updateScheduled = true; - setTimeout(function() { + setTimeout( + function () { this._updateScheduled = false; this.sendEvents(); - }.bind(this), this.options.eventUploadPeriodMillis + }.bind(this), + this.options.eventUploadPeriodMillis, ); } @@ -679,7 +711,7 @@ var _saveCookieData = function _saveCookieData(scope) { lastEventTime: scope._lastEventTime, eventId: scope._eventId, identifyId: scope._identifyId, - sequenceNumber: scope._sequenceNumber + sequenceNumber: scope._sequenceNumber, }; if (AsyncStorage) { AsyncStorage.setItem(scope._storageSuffix, JSON.stringify(cookieData)); @@ -764,7 +796,7 @@ AmplitudeClient.prototype._saveGclid = function _saveGclid(urlParams) { if (utils.isEmptyString(gclid)) { return; } - var gclidProperties = {'gclid': gclid}; + var gclidProperties = { gclid: gclid }; _sendParamsReferrerUserProperties(this, gclidProperties); return gclidProperties; }; @@ -802,8 +834,8 @@ AmplitudeClient.prototype._saveReferrer = function _saveReferrer(referrer) { return; } var referrerInfo = { - 'referrer': referrer, - 'referring_domain': this._getReferringDomain(referrer) + referrer: referrer, + referring_domain: this._getReferringDomain(referrer), }; _sendParamsReferrerUserProperties(this, referrerInfo); return referrerInfo; @@ -816,24 +848,24 @@ AmplitudeClient.prototype._saveReferrer = function _saveReferrer(referrer) { */ AmplitudeClient.prototype.saveEvents = function saveEvents() { try { - const serializedUnsentEvents = JSON.stringify(this._unsentEvents.map(({event}) => event)); + const serializedUnsentEvents = JSON.stringify(this._unsentEvents.map(({ event }) => event)); if (AsyncStorage) { AsyncStorage.setItem(this.options.unsentKey + this._storageSuffix, serializedUnsentEvents); } else { this._setInStorage(localStorage, this.options.unsentKey, serializedUnsentEvents); } - } catch (e) {} + } catch (e) {} /* eslint-disable-line no-empty */ try { - const serializedIdentifys = JSON.stringify(this._unsentIdentifys.map(unsentIdentify => unsentIdentify.event)); + const serializedIdentifys = JSON.stringify(this._unsentIdentifys.map((unsentIdentify) => unsentIdentify.event)); if (AsyncStorage) { AsyncStorage.setItem(this.options.unsentIdentifyKey + this._storageSuffix, serializedIdentifys); } else { this._setInStorage(localStorage, this.options.unsentIdentifyKey, serializedIdentifys); } - } catch (e) {} + } catch (e) {} /* eslint-disable-line no-empty */ }; /** @@ -856,7 +888,7 @@ AmplitudeClient.prototype.setDomain = function setDomain(domain) { expirationDays: this.options.cookieExpiration, secure: this.options.secureCookie, domain: domain, - sameSite: this.options.sameSiteCookie + sameSite: this.options.sameSiteCookie, }); this.options.domain = this.cookieStorage.options().domain; _loadCookieData(this); @@ -878,7 +910,7 @@ AmplitudeClient.prototype.setUserId = function setUserId(userId) { } try { - this.options.userId = (userId !== undefined && userId !== null && ('' + userId)) || null; + this.options.userId = (userId !== undefined && userId !== null && '' + userId) || null; _saveCookieData(this); } catch (e) { utils.log.error(e); @@ -900,13 +932,16 @@ AmplitudeClient.prototype.setUserId = function setUserId(userId) { * @param {string|list} groupName - the name of the group (ex: 15), or a list of names of the groups * @example amplitudeClient.setGroup('orgId', 15); // this adds the current user to orgId 15. */ -AmplitudeClient.prototype.setGroup = function(groupType, groupName) { +AmplitudeClient.prototype.setGroup = function (groupType, groupName) { if (this._shouldDeferCall()) { return this._q.push(['setGroup'].concat(Array.prototype.slice.call(arguments, 0))); } - if (!this._apiKeySet('setGroup()') || !utils.validateInput(groupType, 'groupType', 'string') || - utils.isEmptyString(groupType)) { + if ( + !this._apiKeySet('setGroup()') || + !utils.validateInput(groupType, 'groupType', 'string') || + utils.isEmptyString(groupType) + ) { return; } @@ -957,12 +992,12 @@ AmplitudeClient.prototype.resetSessionId = function resetSessionId() { }; /** - * Regenerates a new random deviceId for current user. Note: this is not recommended unless you know what you - * are doing. This can be used in conjunction with `setUserId(null)` to anonymize users after they log out. - * With a null userId and a completely new deviceId, the current user would appear as a brand new user in dashboard. - * This uses src/uuid.js to regenerate the deviceId. - * @public - */ + * Regenerates a new random deviceId for current user. Note: this is not recommended unless you know what you + * are doing. This can be used in conjunction with `setUserId(null)` to anonymize users after they log out. + * With a null userId and a completely new deviceId, the current user would appear as a brand new user in dashboard. + * This uses src/uuid.js to regenerate the deviceId. + * @public + */ AmplitudeClient.prototype.regenerateDeviceId = function regenerateDeviceId() { if (this._shouldDeferCall()) { return this._q.push(['regenerateDeviceId'].concat(Array.prototype.slice.call(arguments, 0))); @@ -972,13 +1007,13 @@ AmplitudeClient.prototype.regenerateDeviceId = function regenerateDeviceId() { }; /** - * Sets a custom deviceId for current user. Note: this is not recommended unless you know what you are doing - * (like if you have your own system for managing deviceIds). Make sure the deviceId you set is sufficiently unique - * (we recommend something like a UUID - see src/uuid.js for an example of how to generate) to prevent conflicts with other devices in our system. - * @public - * @param {string} deviceId - custom deviceId for current user. - * @example amplitudeClient.setDeviceId('45f0954f-eb79-4463-ac8a-233a6f45a8f0'); - */ + * Sets a custom deviceId for current user. Note: this is not recommended unless you know what you are doing + * (like if you have your own system for managing deviceIds). Make sure the deviceId you set is sufficiently unique + * (we recommend something like a UUID - see src/uuid.js for an example of how to generate) to prevent conflicts with other devices in our system. + * @public + * @param {string} deviceId - custom deviceId for current user. + * @example amplitudeClient.setDeviceId('45f0954f-eb79-4463-ac8a-233a6f45a8f0'); + */ AmplitudeClient.prototype.setDeviceId = function setDeviceId(deviceId) { if (this._shouldDeferCall()) { return this._q.push(['setDeviceId'].concat(Array.prototype.slice.call(arguments, 0))); @@ -990,7 +1025,7 @@ AmplitudeClient.prototype.setDeviceId = function setDeviceId(deviceId) { try { if (!utils.isEmptyString(deviceId)) { - this.options.deviceId = ('' + deviceId); + this.options.deviceId = '' + deviceId; _saveCookieData(this); } } catch (e) { @@ -1034,7 +1069,7 @@ AmplitudeClient.prototype.setUserProperties = function setUserProperties(userPro * @public * @example amplitudeClient.clearUserProperties(); */ -AmplitudeClient.prototype.clearUserProperties = function clearUserProperties(){ +AmplitudeClient.prototype.clearUserProperties = function clearUserProperties() { if (this._shouldDeferCall()) { return this._q.push(['clearUserProperties'].concat(Array.prototype.slice.call(arguments, 0))); } @@ -1074,13 +1109,13 @@ var _convertProxyObjectToRealObject = function _convertProxyObjectToRealObject(i * var identify = new amplitude.Identify().set('colors', ['rose', 'gold']).add('karma', 1).setOnce('sign_up_date', '2016-03-31'); * amplitude.identify(identify); */ -AmplitudeClient.prototype.identify = function(identify_obj, opt_callback) { +AmplitudeClient.prototype.identify = function (identify_obj, opt_callback) { if (this._shouldDeferCall()) { return this._q.push(['identify'].concat(Array.prototype.slice.call(arguments, 0))); } if (!this._apiKeySet('identify()')) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'API key is not set'}); + opt_callback(0, 'No request sent', { reason: 'API key is not set' }); } return; } @@ -1094,43 +1129,49 @@ AmplitudeClient.prototype.identify = function(identify_obj, opt_callback) { // only send if there are operations if (Object.keys(identify_obj.userPropertiesOperations).length > 0) { return this._logEvent( - Constants.IDENTIFY_EVENT, null, null, identify_obj.userPropertiesOperations, null, null, null, opt_callback - ); + Constants.IDENTIFY_EVENT, + null, + null, + identify_obj.userPropertiesOperations, + null, + null, + null, + opt_callback, + ); } else { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'No user property operations'}); + opt_callback(0, 'No request sent', { reason: 'No user property operations' }); } } } else { utils.log.error('Invalid identify input type. Expected Identify object but saw ' + type(identify_obj)); if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Invalid identify input type'}); + opt_callback(0, 'No request sent', { reason: 'Invalid identify input type' }); } } }; -AmplitudeClient.prototype.groupIdentify = function(group_type, group_name, identify_obj, opt_callback) { +AmplitudeClient.prototype.groupIdentify = function (group_type, group_name, identify_obj, opt_callback) { if (this._shouldDeferCall()) { return this._q.push(['groupIdentify'].concat(Array.prototype.slice.call(arguments, 0))); } if (!this._apiKeySet('groupIdentify()')) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'API key is not set'}); + opt_callback(0, 'No request sent', { reason: 'API key is not set' }); } return; } - if (!utils.validateInput(group_type, 'group_type', 'string') || - utils.isEmptyString(group_type)) { + if (!utils.validateInput(group_type, 'group_type', 'string') || utils.isEmptyString(group_type)) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Invalid group type'}); + opt_callback(0, 'No request sent', { reason: 'Invalid group type' }); } return; } if (group_name === null || group_name === undefined) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Invalid group name'}); + opt_callback(0, 'No request sent', { reason: 'Invalid group name' }); } return; } @@ -1144,17 +1185,24 @@ AmplitudeClient.prototype.groupIdentify = function(group_type, group_name, ident // only send if there are operations if (Object.keys(identify_obj.userPropertiesOperations).length > 0) { return this._logEvent( - Constants.GROUP_IDENTIFY_EVENT, null, null, null, {[group_type]: group_name}, identify_obj.userPropertiesOperations, null, opt_callback - ); + Constants.GROUP_IDENTIFY_EVENT, + null, + null, + null, + { [group_type]: group_name }, + identify_obj.userPropertiesOperations, + null, + opt_callback, + ); } else { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'No group property operations'}); + opt_callback(0, 'No request sent', { reason: 'No group property operations' }); } } } else { utils.log.error('Invalid identify input type. Expected Identify object but saw ' + type(identify_obj)); if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Invalid identify input type'}); + opt_callback(0, 'No request sent', { reason: 'Invalid identify input type' }); } } }; @@ -1180,19 +1228,28 @@ AmplitudeClient.prototype.setVersionName = function setVersionName(versionName) * Private logEvent method. Keeps apiProperties from being publicly exposed. * @private */ -AmplitudeClient.prototype._logEvent = function _logEvent(eventType, eventProperties, apiProperties, userProperties, groups, groupProperties, timestamp, callback) { +AmplitudeClient.prototype._logEvent = function _logEvent( + eventType, + eventProperties, + apiProperties, + userProperties, + groups, + groupProperties, + timestamp, + callback, +) { if (!BUILD_COMPAT_REACT_NATIVE) { _loadCookieData(this); // reload cookie before each log event to sync event meta-data between windows and tabs } if (!eventType) { if (type(callback) === 'function') { - callback(0, 'No request sent', {reason: 'Missing eventType'}); + callback(0, 'No request sent', { reason: 'Missing eventType' }); } return; } if (this.options.optOut) { if (type(callback) === 'function') { - callback(0, 'No request sent', {reason: 'optOut is set to true'}); + callback(0, 'No request sent', { reason: 'optOut is set to true' }); } return; } @@ -1205,7 +1262,7 @@ AmplitudeClient.prototype._logEvent = function _logEvent(eventType, eventPropert eventId = this.nextEventId(); } var sequenceNumber = this.nextSequenceNumber(); - var eventTime = (type(timestamp) === 'number') ? timestamp : new Date().getTime(); + var eventTime = type(timestamp) === 'number' ? timestamp : new Date().getTime(); if (!this._sessionId || !this._lastEventTime || eventTime - this._lastEventTime > this.options.sessionTimeout) { this._sessionId = eventTime; } @@ -1231,8 +1288,8 @@ AmplitudeClient.prototype._logEvent = function _logEvent(eventType, eventPropert } userProperties = userProperties || {}; - var trackingOptions = {...this._apiPropertiesTrackingOptions}; - apiProperties = {...(apiProperties || {}), ...trackingOptions}; + var trackingOptions = { ...this._apiPropertiesTrackingOptions }; + apiProperties = { ...(apiProperties || {}), ...trackingOptions }; eventProperties = eventProperties || {}; groups = groups || {}; groupProperties = groupProperties || {}; @@ -1243,33 +1300,33 @@ AmplitudeClient.prototype._logEvent = function _logEvent(eventType, eventPropert event_id: eventId, session_id: this._sessionId || -1, event_type: eventType, - version_name: _shouldTrackField(this, 'version_name') ? (this.options.versionName || versionName || null) : null, + version_name: _shouldTrackField(this, 'version_name') ? this.options.versionName || versionName || null : null, platform: _shouldTrackField(this, 'platform') ? this.options.platform : null, - os_name: _shouldTrackField(this, 'os_name') ? (osName || null) : null, - os_version: _shouldTrackField(this, 'os_version') ? (osVersion || null) : null, - device_model: _shouldTrackField(this, 'device_model') ? (deviceModel || null) : null, - device_manufacturer: _shouldTrackField(this, 'device_manufacturer') ? (deviceManufacturer || null) : null, + os_name: _shouldTrackField(this, 'os_name') ? osName || null : null, + os_version: _shouldTrackField(this, 'os_version') ? osVersion || null : null, + device_model: _shouldTrackField(this, 'device_model') ? deviceModel || null : null, + device_manufacturer: _shouldTrackField(this, 'device_manufacturer') ? deviceManufacturer || null : null, language: _shouldTrackField(this, 'language') ? this.options.language : null, - carrier: _shouldTrackField(this, 'carrier') ? (carrier || null): null, + carrier: _shouldTrackField(this, 'carrier') ? carrier || null : null, api_properties: apiProperties, event_properties: utils.truncate(utils.validateProperties(eventProperties)), user_properties: utils.truncate(utils.validateProperties(userProperties)), uuid: UUID(), library: { name: BUILD_COMPAT_REACT_NATIVE ? 'amplitude-react-native' : 'amplitude-js', - version: version + version: version, }, sequence_number: sequenceNumber, // for ordering events and identifys groups: utils.truncate(utils.validateGroups(groups)), group_properties: utils.truncate(utils.validateProperties(groupProperties)), - user_agent: this._userAgent + user_agent: this._userAgent, }; if (eventType === Constants.IDENTIFY_EVENT || eventType === Constants.GROUP_IDENTIFY_EVENT) { - this._unsentIdentifys.push({event, callback}); + this._unsentIdentifys.push({ event, callback }); this._limitEventsQueued(this._unsentIdentifys); } else { - this._unsentEvents.push({event, callback}); + this._unsentEvents.push({ event, callback }); this._limitEventsQueued(this._unsentEvents); } @@ -1346,25 +1403,30 @@ AmplitudeClient.prototype.logEvent = function logEvent(eventType, eventPropertie * Note: the server response code and response body from the event upload are passed to the callback function. * @example amplitudeClient.logEvent('Clicked Homepage Button', {'finished_flow': false, 'clicks': 15}); */ -AmplitudeClient.prototype.logEventWithTimestamp = function logEvent(eventType, eventProperties, timestamp, opt_callback) { +AmplitudeClient.prototype.logEventWithTimestamp = function logEvent( + eventType, + eventProperties, + timestamp, + opt_callback, +) { if (this._shouldDeferCall()) { return this._q.push(['logEventWithTimestamp'].concat(Array.prototype.slice.call(arguments, 0))); } if (!this._apiKeySet('logEvent()')) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'API key not set'}); + opt_callback(0, 'No request sent', { reason: 'API key not set' }); } return -1; } if (!utils.validateInput(eventType, 'eventType', 'string')) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Invalid type for eventType'}); + opt_callback(0, 'No request sent', { reason: 'Invalid type for eventType' }); } return -1; } if (utils.isEmptyString(eventType)) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Missing eventType'}); + opt_callback(0, 'No request sent', { reason: 'Missing eventType' }); } return -1; } @@ -1387,19 +1449,19 @@ AmplitudeClient.prototype.logEventWithTimestamp = function logEvent(eventType, e * Note: the server response code and response body from the event upload are passed to the callback function. * @example amplitudeClient.logEventWithGroups('Clicked Button', null, {'orgId': 24}); */ -AmplitudeClient.prototype.logEventWithGroups = function(eventType, eventProperties, groups, opt_callback) { +AmplitudeClient.prototype.logEventWithGroups = function (eventType, eventProperties, groups, opt_callback) { if (this._shouldDeferCall()) { return this._q.push(['logEventWithGroups'].concat(Array.prototype.slice.call(arguments, 0))); } if (!this._apiKeySet('logEventWithGroups()')) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'API key not set'}); + opt_callback(0, 'No request sent', { reason: 'API key not set' }); } return -1; } if (!utils.validateInput(eventType, 'eventType', 'string')) { if (type(opt_callback) === 'function') { - opt_callback(0, 'No request sent', {reason: 'Invalid type for eventType'}); + opt_callback(0, 'No request sent', { reason: 'Invalid type for eventType' }); } return -1; } @@ -1470,12 +1532,21 @@ if (BUILD_COMPAT_2_0) { return -1; } - return this._logEvent(Constants.REVENUE_EVENT, {}, { - productId: product, - special: 'revenue_amount', - quantity: quantity || 1, - price: price - }, null, null, null, null, null); + return this._logEvent( + Constants.REVENUE_EVENT, + {}, + { + productId: product, + special: 'revenue_amount', + quantity: quantity || 1, + price: price, + }, + null, + null, + null, + null, + null, + ); }; } @@ -1520,12 +1591,12 @@ var _removeEvents = function _removeEvents(scope, eventQueue, maxId, status, res */ AmplitudeClient.prototype.sendEvents = function sendEvents() { if (!this._apiKeySet('sendEvents()')) { - this.removeEvents(Infinity, Infinity, 0, 'No request sent', {reason: 'API key not set'}); + this.removeEvents(Infinity, Infinity, 0, 'No request sent', { reason: 'API key not set' }); return; } if (this.options.optOut) { - this.removeEvents(Infinity, Infinity, 0, 'No request sent', {reason: 'Opt out is set to true'}); + this.removeEvents(Infinity, Infinity, 0, 'No request sent', { reason: 'Opt out is set to true' }); return; } @@ -1541,7 +1612,7 @@ AmplitudeClient.prototype.sendEvents = function sendEvents() { } this._sending = true; - var protocol = this.options.forceHttps ? 'https' : ('https:' === window.location.protocol ? 'https' : 'http'); + var protocol = this.options.forceHttps ? 'https' : 'https:' === window.location.protocol ? 'https' : 'http'; var url = protocol + '://' + this.options.apiEndpoint; // fetch events to send @@ -1549,7 +1620,7 @@ AmplitudeClient.prototype.sendEvents = function sendEvents() { var mergedEvents = this._mergeEventsAndIdentifys(numEvents); var maxEventId = mergedEvents.maxEventId; var maxIdentifyId = mergedEvents.maxIdentifyId; - var events = JSON.stringify(mergedEvents.eventsToSend.map(({event}) => event)); + var events = JSON.stringify(mergedEvents.eventsToSend.map(({ event }) => event)); var uploadTime = new Date().getTime(); var data = { @@ -1557,11 +1628,11 @@ AmplitudeClient.prototype.sendEvents = function sendEvents() { e: events, v: Constants.API_VERSION, upload_time: uploadTime, - checksum: md5(Constants.API_VERSION + this.options.apiKey + events + uploadTime) + checksum: md5(Constants.API_VERSION + this.options.apiKey + events + uploadTime), }; var scope = this; - new Request(url, data).send(function(status, response) { + new Request(url, data).send(function (status, response) { scope._sending = false; try { if (status === 200 && response === 'success') { @@ -1575,7 +1646,7 @@ AmplitudeClient.prototype.sendEvents = function sendEvents() { // Send more events if any queued during previous send. scope._sendEventsIfReady(); - // handle payload too large + // handle payload too large } else if (status === 413) { // utils.log('request too large'); // Can't even get this one massive event through. Drop it, even if it is an identify. @@ -1586,7 +1657,6 @@ AmplitudeClient.prototype.sendEvents = function sendEvents() { // The server complained about the length of the request. Backoff and try again. scope.options.uploadBatchSize = Math.ceil(numEvents / 2); scope.sendEvents(); - } // else { // all the events are still queued, and will be retried when the next @@ -1630,17 +1700,19 @@ AmplitudeClient.prototype._mergeEventsAndIdentifys = function _mergeEventsAndIde unsentEvent = this._unsentEvents[eventIndex++]; maxEventId = unsentEvent.event.event_id; - // case 2: no events - grab from identifys + // case 2: no events - grab from identifys } else if (noEvents) { unsentEvent = this._unsentIdentifys[identifyIndex++]; maxIdentifyId = unsentEvent.event.event_id; - // case 3: need to compare sequence numbers + // case 3: need to compare sequence numbers } else { // events logged before v2.5.0 won't have a sequence number, put those first - if (!('sequence_number' in this._unsentEvents[eventIndex].event) || - this._unsentEvents[eventIndex].event.sequence_number < - this._unsentIdentifys[identifyIndex].event.sequence_number) { + if ( + !('sequence_number' in this._unsentEvents[eventIndex].event) || + this._unsentEvents[eventIndex].event.sequence_number < + this._unsentIdentifys[identifyIndex].event.sequence_number + ) { unsentEvent = this._unsentEvents[eventIndex++]; maxEventId = unsentEvent.event.event_id; } else { @@ -1655,7 +1727,7 @@ AmplitudeClient.prototype._mergeEventsAndIdentifys = function _mergeEventsAndIde return { eventsToSend: eventsToSend, maxEventId: maxEventId, - maxIdentifyId: maxIdentifyId + maxIdentifyId: maxIdentifyId, }; }; diff --git a/src/amplitude-snippet.js b/src/amplitude-snippet.js index 5b9d11ac..74f41d9e 100644 --- a/src/amplitude-snippet.js +++ b/src/amplitude-snippet.js @@ -1,11 +1,11 @@ /** -* Imported in client browser via