diff --git a/__tests__/camelcase.test.js b/__tests__/camelcase.test.js new file mode 100644 index 0000000000..85d390a21d --- /dev/null +++ b/__tests__/camelcase.test.js @@ -0,0 +1,21 @@ +import camelcase from "../utils/camelcase"; + +test("convert string with space to camelcase format", () => { + expect(camelcase("camel case")).toBe("camelCase"); +}); + +test("convert string with underscore to camelcase format", () => { + expect(camelcase("camel_case")).toBe("camelCase"); +}); + +test("convert string with first letter capital to camelcase format", () => { + expect(camelcase("Camelcase")).toBe("camelcase"); +}); + +test("convert uppercase string to camelcase format", () => { + expect(camelcase("CAMELCASE")).toBe("camelcase"); +}); + +test("convert string with first letter capital for each word to camelcase format", () => { + expect(camelcase("Camel Case")).toBe("camelCase"); +}); diff --git a/analytics.js b/analytics.js index 7e3a19ffa5..fa4b7cdbe8 100644 --- a/analytics.js +++ b/analytics.js @@ -34,6 +34,7 @@ import { CONFIG_URL, MAX_WAIT_FOR_INTEGRATION_LOAD, INTEGRATION_LOAD_CHECK_INTERVAL, + POLYFILL_URL, } from "./utils/constants"; import { integrations } from "./integrations"; import RudderElementBuilder from "./utils/RudderElementBuilder"; @@ -1003,13 +1004,13 @@ class Analytics { } /** - * Call control pane to get client configs - * + * Load after polyfills are loaded * @param {*} writeKey - * @memberof Analytics + * @param {*} serverUrl + * @param {*} options + * @returns */ - load(writeKey, serverUrl, options) { - logger.debug("inside load "); + loadAfterPolyfill(writeKey, serverUrl, options) { if (options && options.cookieConsentManager) this.cookieConsentOptions = cloneDeep(options.cookieConsentManager); if (this.loaded) return; @@ -1130,6 +1131,44 @@ class Analytics { processDataInAnalyticsArray(this); } + /** + * Call control pane to get client configs + * + * @param {*} writeKey + * @memberof Analytics + */ + load(writeKey, serverUrl, options) { + // logger.debug("inside load "); + + // check if the below features are available in the browser or not + // If not present dynamically load from the polyfill cdn + if ( + !String.prototype.endsWith || + !String.prototype.startsWith || + !String.prototype.includes || + !Array.prototype.find || + !Array.prototype.includes || + !Promise || + !Object.entries + ) { + ScriptLoader("polyfill", POLYFILL_URL); + const self = this; + const interval = setInterval(function () { + // check if the polyfill is loaded + if (window.hasOwnProperty("polyfill")) { + clearInterval(interval); + self.loadAfterPolyfill(writeKey, serverUrl, options); + } + }, 100); + + setTimeout(() => { + clearInterval(interval); + }, MAX_WAIT_FOR_INTEGRATION_LOAD); + } else { + this.loadAfterPolyfill(writeKey, serverUrl, options); + } + } + ready(callback) { if (!this.loaded) return; if (typeof callback === "function") { diff --git a/integrations/Fullstory/browser.js b/integrations/Fullstory/browser.js index c1a6305c5e..6bc9fe5e9d 100644 --- a/integrations/Fullstory/browser.js +++ b/integrations/Fullstory/browser.js @@ -1,6 +1,6 @@ /* eslint-disable class-methods-use-this */ /* eslint-disable no-undef */ -import camelcase from "camelcase"; +import camelcase from "../../utils/camelcase"; import logger from "../../utils/logUtil"; import { NAME } from "./constants"; diff --git a/package.json b/package.json index b29781005f..bcf34403b9 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,6 @@ "babel-eslint": "^10.1.0", "babel-polyfill": "^6.26.0", "btoa": "^1.2.1", - "camelcase": "^6.0.0", "component-cookie": "^1.1.4", "component-each": "^0.2.6", "component-emitter": "github:component/emitter", @@ -72,7 +71,6 @@ "regenerator-runtime": "^0.13.7", "rudder-component-cookie": "0.0.1", "semver": "^7.1.3", - "set-value": "^4.1.0", "universal-analytics": "^0.4.20", "xmlhttprequest": "^1.8.0" }, diff --git a/utils/camelcase.js b/utils/camelcase.js new file mode 100644 index 0000000000..af10936d47 --- /dev/null +++ b/utils/camelcase.js @@ -0,0 +1,51 @@ +// util function to convert the input to string type +function convertToString(input) { + if (input) { + if (typeof input === "string") { + return input; + } + + return String(input); + } + return ""; +} + +// convert string to words +function toWords(input) { + input = convertToString(input); + + var regex = + /[A-Z\xC0-\xD6\xD8-\xDE]?[a-z\xDF-\xF6\xF8-\xFF]+|[A-Z\xC0-\xD6\xD8-\xDE]+(?![a-z\xDF-\xF6\xF8-\xFF])|\d+/g; + + return input.match(regex); +} + +// convert the input array to camel case +function toCamelCase(inputArray) { + let result = ""; + + for (let i = 0, len = inputArray.length; i < len; i++) { + const currentStr = inputArray[i]; + + let tempStr = currentStr.toLowerCase(); + + if (i !== 0) { + // convert first letter to upper case (the word is in lowercase) + tempStr = tempStr.substr(0, 1).toUpperCase() + tempStr.substr(1); + } + + result += tempStr; + } + + return result; +} + +// this function call all other functions + +function camelcase(input) { + const words = toWords(input); + + return toCamelCase(words); +} + +export default camelcase; diff --git a/utils/constants.js b/utils/constants.js index 5c8db6b5b8..51cc943c06 100644 --- a/utils/constants.js +++ b/utils/constants.js @@ -90,6 +90,9 @@ const FLUSH_INTERVAL_DEFAULT = 5000; const MAX_WAIT_FOR_INTEGRATION_LOAD = 10000; const INTEGRATION_LOAD_CHECK_INTERVAL = 1000; +const POLYFILL_URL = + "https://polyfill.io/v3/polyfill.min.js?features=Array.prototype.find%2CArray.prototype.includes%2CPromise%2CString.prototype.endsWith%2CString.prototype.includes%2CString.prototype.startsWith%2CObject.entries"; + export { ReservedPropertyKeywords, MessageType, @@ -102,6 +105,7 @@ export { FLUSH_INTERVAL_DEFAULT, MAX_WAIT_FOR_INTEGRATION_LOAD, INTEGRATION_LOAD_CHECK_INTERVAL, + POLYFILL_URL, }; /* module.exports = { MessageType: MessageType, diff --git a/utils/utils.js b/utils/utils.js index 9ce1166fa0..43fd9352e8 100644 --- a/utils/utils.js +++ b/utils/utils.js @@ -1,7 +1,6 @@ // import * as XMLHttpRequestNode from "Xmlhttprequest"; import { parse } from "component-url"; import get from "get-value"; -import set from "set-value"; import logger from "./logUtil"; import { commonNames } from "../integrations/integration_cname"; import { clientToServerNames } from "../integrations/client_server_name"; @@ -555,7 +554,13 @@ function extractCustomFields(message, destination, keys, exclusionFields) { }); objKeys.map((k) => { if (!(typeof messageContext[k] === "undefined")) { - set(destination, k, get(messageContext, k)); + if (destination) { + destination[k] = get(messageContext, k); + } else { + destination = { + k: get(messageContext, k), + }; + } } }); } @@ -605,11 +610,10 @@ function getDefinedTraits(message) { get(traitsValue, "firstName") && get(traitsValue, "lastName") ) { - set( + traitsValue.name = `${get(traitsValue, "firstName")} ${get( traitsValue, - "name", - `${get(traitsValue, "firstName")} ${get(traitsValue, "lastName")}` - ); + "lastName" + )}`; } return traitsValue; }