diff --git a/.circleci/config.yml b/.circleci/config.yml
index 6e3cc6599..e7fc4ec7d 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -34,6 +34,7 @@ jobs:
- checkout
- *getDeps
- run: yarn commitlint-circle
+ - run: yarn core lint
test-core:
<<: *nodeJob
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..66666f82a
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,6 @@
+semi: false
+singleQuote: true
+overrides:
+ - files: '*.{ts,js}'
+ options:
+ useTabs: true
diff --git a/HACKING.md b/HACKING.md
index 4afd59bd1..489e592c2 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -1,30 +1,47 @@
-
## Environment
-This project is a Yarn workspace, npm is not supported. To install dependencies run :
+This project is a Yarn workspace, npm is not supported. To install dependencies run :
```bash
$ yarn
```
-### Useful commands
+### Building
-- Build everything:
- ```bash
- $ yarn build
- ```
- Build the `@segment/react-native` package:
```bash
$ yarn core build
```
+- Build the `@segment/react-native-*` packages:
+ ```bash
+ $ yarn integrations build
+ ```
+- Build the test application for iOS and Android:
+ ```bash
+ $ yarn test-app build
+ ```
+- Launch these three steps one by one:
+ ```bash
+ $ yarn build
+ ```
+
+## Testing
+
+```bash
+$ yarn test
+```
### Architecture
- `packages/core`: the `@segment/react-native` module
- `docs`: the generated TypeScript documentation, commited using a `lint-staged` hook
-- `packages/integration-build`:
+ - `src`: JavaScript module
+ - `ios`: iOS native module
+ - `android`: Android native module
+- `packages/integrations`:
- `integrations.yml`: the unique source of truth for supported integrations
- - `generators`: a set of generators using `integrations.yml`
+ - `src`: a set of generators using `integrations.yml`
- `gen-integrations.js`: generates `@segment/react-native-*` packages in `build/`
- `gen-readme.js`: updates `README.md` [Integrations](README.md#integrations) section
- - `test-app`
+ - `test-app`:
+ - `project`: the generated react-native test-app root
diff --git a/README.md b/README.md
index 85ac46d8d..a757382c3 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ The hassle-free way to add analytics to your React-Native app.
#### iOS
- CocoaPods (**recommended**)
- - [Don't have CocoaPods setup?](#setup-cocoapods-in-an-existing-project)
+ - [Don't have CocoaPods setup?](#setup-cocoapods-in-an-existing-project)
- or [manually install `Analytics`](#ios-support-without-cocoapods)
## Installation
@@ -30,6 +30,7 @@ $ yarn react-native link
See the [API docs](packages/core/docs/classes/analytics.client.md) for more details.
+
```js
import analytics from '@segment/react-native'
import Mixpanel from '@segment/react-native-mixpanel'
@@ -65,8 +66,8 @@ analytics.screen('Home')
There are two ways to send data to your analytics services through this library:
-1. [Through the Segment servers](#cloud-based-connection-modes)
-2. [Directly from the device using bundled SDK’s](#packaging-device-based-destination-sdks)
+1. [Through the Segment servers](#cloud-based-connection-modes)
+2. [Directly from the device using bundled SDK’s](#packaging-device-based-destination-sdks)
**Note**: Refer to the specific destination’s docs to see if your tool must be bundled in the app or sent server-side.
@@ -88,23 +89,23 @@ $ yarn add @segment/react-native-google-analytics
$ yarn react-native link
```
-In your code :
+In your code :
```js
import analytics from '@segment/react-native'
import GoogleAnalytics from '@segment/react-native-google-analytics'
await analytics
- .configure()
- .using(GoogleAnalytics)
- // ...
- .setup('writeKey')
-
+ .configure()
+ .using(GoogleAnalytics)
+ // ...
+ .setup('writeKey')
```
#### Integrations
+
| Name | iOS | Android | npm package |
| -------------------------------------------------------------------------------------------------- | ------------------ | ------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| [Adjust](https://www.npmjs.com/package/@segment/react-native-adjust) | :white_check_mark: | :white_check_mark: | [`@segment/react-native-adjust`](https://www.npmjs.com/package/@segment/react-native-adjust) |
@@ -126,8 +127,8 @@ await analytics
| [Quantcast](https://www.npmjs.com/package/@segment/react-native-quantcast-android) | :x: | :white_check_mark: | [`@segment/react-native-quantcast-android`](https://www.npmjs.com/package/@segment/react-native-quantcast-android) |
| [Taplytics](https://www.npmjs.com/package/@segment/react-native-taplytics-ios) | :white_check_mark: | :x: | [`@segment/react-native-taplytics-ios`](https://www.npmjs.com/package/@segment/react-native-taplytics-ios) |
| [Tapstream](https://www.npmjs.com/package/@segment/react-native-tapstream-android) | :x: | :white_check_mark: | [`@segment/react-native-tapstream-android`](https://www.npmjs.com/package/@segment/react-native-tapstream-android) |
-
+
## Troubleshooting
@@ -141,28 +142,30 @@ However, if you cannot use Cocoapods, you can manually install our dynamic frame
Here are the steps for installing manually:
-1. Download the [latest built SDK](https://github.com/segmentio/analytics-ios/releases), and unzip the zip file.
-2. Drag the unzipped Analytics.framework folder into your Xcode project.
- Make sure to check `Copy items if needed`.
- ![Add Analytics.framework](docs/ios/add-analytics-framework.png)
-3. In the `General` tab for your project, search for `Embedded Binaries` and add the `Analytics.framework`.
- ![Embed Analytics.framework](docs/ios/embed-analytics-framework.png)
+1. Download the [latest built SDK](https://github.com/segmentio/analytics-ios/releases), and unzip the zip file.
+2. Drag the unzipped Analytics.framework folder into your Xcode project.
+ Make sure to check `Copy items if needed`.
+ ![Add Analytics.framework](docs/ios/add-analytics-framework.png)
+3. In the `General` tab for your project, search for `Embedded Binaries` and add the `Analytics.framework`.
+ ![Embed Analytics.framework](docs/ios/embed-analytics-framework.png)
Please note, if you are choosing to not use a dependency manager, you must keep files up-to-date with regularly scheduled, manual updates.
### Setup CocoaPods in an existing project
-1. Check that `ios/Podfile` doesn't exist
-2. `cd ios`
-3. `pod init`
-4. Open `Podfile`
-5. Edit your app `target` to have these `pod` declarations and the `Add new pods below this line` comment :
- ```ruby
- target 'MyReactNativeApp' do
- pod 'React', :path => '../node_modules/react-native'
- pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
-
- # Add new pods below this line
- end
- ```
-6. `pod install`
+1. Check that `ios/Podfile` doesn't exist
+2. `cd ios`
+3. `pod init`
+4. Open `Podfile`
+5. Edit your app `target` to have these `pod` declarations and the `Add new pods below this line` comment :
+
+ ```ruby
+ target 'MyReactNativeApp' do
+ pod 'React', :path => '../node_modules/react-native'
+ pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
+
+ # Add new pods below this line
+ end
+ ```
+
+6. `pod install`
diff --git a/circle b/circle
deleted file mode 100644
index e69de29bb..000000000
diff --git a/package.json b/package.json
index 4bf36551e..a19e7f1af 100644
--- a/package.json
+++ b/package.json
@@ -14,18 +14,25 @@
]
},
"scripts": {
- "core": "yarn workspace @segment/react-native run",
- "integrations": "yarn workspace @local/integrations run",
- "test-app": "yarn workspace @local/test-app run",
+ "core": "yarn workspace @segment/react-native",
+ "integrations": "yarn workspace @local/integrations",
+ "test-app": "yarn workspace @local/test-app",
"build:core": "yarn core build",
"build:integrations": "yarn integrations build",
"build:test-app": "yarn test-app build",
"build": "run-s build:{core,integrations,test-app}",
"test:core": "yarn core test",
"test": "run-p test:*",
+ "lint:prettier": "prettier $(git ls-files '**/*.ts' '**/*.js' '**/*.json' '**/*.md') --list-different",
+ "lint:core": "yarn core lint",
+ "lint": "run-s lint:*",
+ "docs:core": "yarn core docs",
+ "docs": "run-s docs:*",
"cz": "git-cz",
"precommit": "lint-staged",
- "commitmsg": "commitlint -E GIT_PARAMS"
+ "commitmsg": "commitlint -E GIT_PARAMS",
+ "lint-staged:ts": "run-p build:core docs:core && git add packages/core/docs",
+ "lint-staged:integrations": "yarn integrations generate:readme && git add README.md"
},
"commitlint": {
"extends": [
@@ -38,13 +45,16 @@
}
},
"lint-staged": {
- "packages/core/ts/**/*.ts": [
- "yarn core docs --",
- "git add packages/core/docs"
+ "packages/core/src/**/*.ts": [
+ "prettier --write",
+ "yarn lint-staged:ts"
],
"packages/integrations/integrations.yml": [
- "yarn integrations generate:readme --",
- "git add README.md"
+ "yarn lint-staged:integrations"
+ ],
+ "*.{js,json,md}": [
+ "prettier --write",
+ "git add"
]
},
"devDependencies": {
@@ -57,6 +67,7 @@
"husky": "^0.14.3",
"lint-staged": "^7.2.0",
"npm-run-all": "^4.1.3",
+ "prettier": "^1.14.2",
"rimraf": "^2.6.2"
}
}
diff --git a/packages/core/docs/README.md b/packages/core/docs/README.md
new file mode 100644
index 000000000..ff129953e
--- /dev/null
+++ b/packages/core/docs/README.md
@@ -0,0 +1,42 @@
+
+
+## Index
+
+### Modules
+
+* [ChainedConfiguration](modules/analytics.chainedconfiguration.md)
+
+### Classes
+
+* [Client](classes/analytics.client.md)
+
+### Type aliases
+
+* [Integration](#integration)
+* [WriteKey](#writekey)
+
+---
+
+## Type aliases
+
+
+
+### Integration
+
+**ΤIntegration**: * `function` | `object`
+*
+
+*Defined in analytics.ts:170*
+
+___
+
+
+### WriteKey
+
+**ΤWriteKey**: * `string` | `object`
+*
+
+*Defined in analytics.ts:172*
+
+___
+
diff --git a/packages/core/docs/classes/analytics.client.md b/packages/core/docs/classes/analytics.client.md
new file mode 100644
index 000000000..b5440503e
--- /dev/null
+++ b/packages/core/docs/classes/analytics.client.md
@@ -0,0 +1,264 @@
+[@segment/react-native](../README.md) > [Client](../classes/analytics.client.md)
+
+# Class: Client
+
+## Hierarchy
+
+**Client**
+
+## Index
+
+### Properties
+
+* [ready](analytics.client.md#ready)
+
+### Methods
+
+* [alias](analytics.client.md#alias)
+* [catch](analytics.client.md#catch)
+* [configure](analytics.client.md#configure)
+* [disable](analytics.client.md#disable)
+* [enable](analytics.client.md#enable)
+* [flush](analytics.client.md#flush)
+* [group](analytics.client.md#group)
+* [identify](analytics.client.md#identify)
+* [reset](analytics.client.md#reset)
+* [screen](analytics.client.md#screen)
+* [track](analytics.client.md#track)
+
+---
+
+## Properties
+
+
+
+### ready
+
+**● ready**: *`false`* = false
+
+*Defined in analytics.ts:13*
+
+Whether the client is ready to send events to Segment.
+
+This becomes `true` when `.setup()` succeeds. All calls will be queued until it becomes `true`.
+
+___
+
+## Methods
+
+
+
+### alias
+
+▸ **alias**(newId: *`string`*): `this`
+
+*Defined in analytics.ts:115*
+
+Merge two user identities, effectively connecting two sets of user data as one. This may not be supported by all integrations.
+
+When you learn more about who the group is, you can record that information with group.
+
+**Parameters:**
+
+| Param | Type | Description |
+| ------ | ------ | ------ |
+| newId | `string` | The new ID you want to alias the existing ID to. The existing ID will be either the previousId if you have called identify, or the anonymous ID. |
+
+**Returns:** `this`
+
+___
+
+
+### catch
+
+▸ **catch**(handler: *[ErrorHandler]()*): `this`
+
+*Defined in analytics.ts:23*
+
+Catch React-Native bridge errors
+
+These errors are emitted when calling the native counterpart.
+
+**Parameters:**
+
+| Param | Type |
+| ------ | ------ |
+| handler | [ErrorHandler]() |
+
+**Returns:** `this`
+
+___
+
+
+### configure
+
+▸ **configure**(): [Configuration](../interfaces/analytics.chainedconfiguration.configuration.md)
+
+*Defined in analytics.ts:43*
+
+Configure the Analytics module.
+
+This method returns a fluent-style API to configure the SDK :
+
+```js
+analytics
+ .configure()
+ .using(Mixpanel, GoogleAnalytics)
+ .trackAppLifecycle()
+ .ios()
+ .trackDeepLinks()
+ .setup("YOUR_WRITE_KEY")
+```
+
+**Returns:** [Configuration](../interfaces/analytics.chainedconfiguration.configuration.md)
+
+___
+
+
+### disable
+
+▸ **disable**(): `this`
+
+*Defined in analytics.ts:154*
+
+Completely disable the sending of any analytics data.
+
+If you have a way for users to actively or passively (sometimes based on location) opt-out of analytics data collection, you can use this method to turn off all data collection.
+
+**Returns:** `this`
+
+___
+
+
+### enable
+
+▸ **enable**(): `this`
+
+*Defined in analytics.ts:144*
+
+Enable the sending of analytics data. Enabled by default.
+
+Occasionally used in conjunction with disable user opt-out handling.
+
+**Returns:** `this`
+
+___
+
+
+### flush
+
+▸ **flush**(): `this`
+
+*Defined in analytics.ts:135*
+
+Trigger an upload of all queued events.
+
+This is useful when you want to force all messages queued on the device to be uploaded. Please note that not all integrations respond to this method.
+
+**Returns:** `this`
+
+___
+
+
+### group
+
+▸ **group**(groupId: *`string`*, traits?: *[JsonMap]()*): `this`
+
+*Defined in analytics.ts:102*
+
+Associate a user with a group, organization, company, project, or w/e _you_ call them.
+
+When you learn more about who the group is, you can record that information with group.
+
+**Parameters:**
+
+| Param | Type | Default value | Description |
+| ------ | ------ | ------ | ------ |
+| groupId | `string` | - | A database ID for this group. |
+| `Default value` traits | [JsonMap]() | {} | A dictionary of traits you know about the group. Things like: name, employees, etc. |
+
+**Returns:** `this`
+
+___
+
+
+### identify
+
+▸ **identify**(userId: *`string`*, traits?: *[JsonMap]()*): `this`
+
+*Defined in analytics.ts:90*
+
+Associate a user with their unique ID and record traits about them.
+
+When you learn more about who your user is, you can record that information with identify.
+
+**Parameters:**
+
+| Param | Type | Default value | Description |
+| ------ | ------ | ------ | ------ |
+| userId | `string` | - | database ID (or email address) for this user. If you don't have a userId but want to record traits, you should pass nil. For more information on how we generate the UUID and Apple's policies on IDs, see [https://segment.io/libraries/ios#ids](https://segment.io/libraries/ios#ids) |
+| `Default value` traits | [JsonMap]() | {} | A dictionary of traits you know about the user. Things like: email, name, plan, etc. |
+
+**Returns:** `this`
+
+___
+
+
+### reset
+
+▸ **reset**(): `this`
+
+*Defined in analytics.ts:125*
+
+Reset any user state that is cached on the device.
+
+This is useful when a user logs out and you want to clear the identity. It will clear any traits or userId's cached on the device.
+
+**Returns:** `this`
+
+___
+
+
+### screen
+
+▸ **screen**(name: *`string`*, properties?: *[JsonMap]()*): `this`
+
+*Defined in analytics.ts:76*
+
+Record the screens or views your users see.
+
+When a user views a screen in your app, you'll want to record that here. For some tools like Google Analytics and Flurry, screen views are treated specially, and are different from "events" kind of like "page views" on the web. For services that don't treat "screen views" specially, we map "screen" straight to "track" with the same parameters. For example, Mixpanel doesn't treat "screen views" any differently. So a call to "screen" will be tracked as a normal event in Mixpanel, but get sent to Google Analytics and Flurry as a "screen".
+
+**Parameters:**
+
+| Param | Type | Default value | Description |
+| ------ | ------ | ------ | ------ |
+| name | `string` | - | The title of the screen being viewed. We recommend using human-readable names like 'Photo Feed' or 'Completed Purchase Screen'. |
+| `Default value` properties | [JsonMap]() | {} | A dictionary of properties for the screen view event. If the event was 'Added to Shopping Cart', it might have properties like price, productType, etc. |
+
+**Returns:** `this`
+
+___
+
+
+### track
+
+▸ **track**(event: *`string`*, properties?: *[JsonMap]()*): `this`
+
+*Defined in analytics.ts:58*
+
+Record the actions your users perform.
+
+When a user performs an action in your app, you'll want to track that action for later analysis. Use the event name to say what the user did, and properties to specify any interesting details of the action.
+
+**Parameters:**
+
+| Param | Type | Default value | Description |
+| ------ | ------ | ------ | ------ |
+| event | `string` | - | The name of the event you're tracking. We recommend using human-readable names like \`Played a Song\` or \`Updated Status\`. |
+| `Default value` properties | [JsonMap]() | {} | A dictionary of properties for the event. If the event was 'Added to Shopping Cart', it might have properties like price, productType, etc. |
+
+**Returns:** `this`
+
+___
+
diff --git a/packages/core/docs/interfaces/analytics.chainedconfiguration.android.md b/packages/core/docs/interfaces/analytics.chainedconfiguration.android.md
new file mode 100644
index 000000000..84114aeb2
--- /dev/null
+++ b/packages/core/docs/interfaces/analytics.chainedconfiguration.android.md
@@ -0,0 +1,94 @@
+[@segment/react-native](../README.md) > [ChainedConfiguration](../modules/analytics.chainedconfiguration.md) > [Android](../interfaces/analytics.chainedconfiguration.android.md)
+
+# Interface: Android
+
+## Hierarchy
+
+ [Base](analytics.chainedconfiguration.base.md)
+
+**↳ Android**
+
+## Index
+
+### Methods
+
+* [android](analytics.chainedconfiguration.android.md#android)
+* [disableDeviceId](analytics.chainedconfiguration.android.md#disabledeviceid)
+* [ios](analytics.chainedconfiguration.android.md#ios)
+* [setup](analytics.chainedconfiguration.android.md#setup)
+
+---
+
+## Methods
+
+
+
+### android
+
+▸ **android**(): [Android](analytics.chainedconfiguration.android.md)
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[android](analytics.chainedconfiguration.base.md#android)*
+
+*Defined in analytics.ts:193*
+
+Access Android specific settings
+
+**Returns:** [Android](analytics.chainedconfiguration.android.md)
+
+___
+
+
+### disableDeviceId
+
+▸ **disableDeviceId**(): `this`
+
+*Defined in analytics.ts:254*
+
+Disable the collection of the device identifier. Enabled by default.
+
+The device identifier is obtained using :
+
+* `android.provider.Settings.Secure.ANDROID_ID`
+* `android.os.Build.SERIAL`
+* or Telephony Identifier retrieved via TelephonyManager as available
+
+**Returns:** `this`
+
+___
+
+
+### ios
+
+▸ **ios**(): [iOS](analytics.chainedconfiguration.ios.md)
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[ios](analytics.chainedconfiguration.base.md#ios)*
+
+*Defined in analytics.ts:189*
+
+Access iOS specific settings
+
+**Returns:** [iOS](analytics.chainedconfiguration.ios.md)
+
+___
+
+
+### setup
+
+▸ **setup**(writeKey: *[WriteKey](../#writekey)*): `Promise`<[Client](../classes/analytics.client.md)>
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[setup](analytics.chainedconfiguration.base.md#setup)*
+
+*Defined in analytics.ts:185*
+
+Finalize the configuration and initialize the Analytics client.
+
+**Parameters:**
+
+| Param | Type | Description |
+| ------ | ------ | ------ |
+| writeKey | [WriteKey](../#writekey) | your Segment.io write key |
+
+**Returns:** `Promise`<[Client](../classes/analytics.client.md)>
+
+___
+
diff --git a/packages/core/docs/interfaces/analytics.chainedconfiguration.base.md b/packages/core/docs/interfaces/analytics.chainedconfiguration.base.md
new file mode 100644
index 000000000..7985fe1e8
--- /dev/null
+++ b/packages/core/docs/interfaces/analytics.chainedconfiguration.base.md
@@ -0,0 +1,72 @@
+[@segment/react-native](../README.md) > [ChainedConfiguration](../modules/analytics.chainedconfiguration.md) > [Base](../interfaces/analytics.chainedconfiguration.base.md)
+
+# Interface: Base
+
+## Hierarchy
+
+**Base**
+
+↳ [Configuration](analytics.chainedconfiguration.configuration.md)
+
+↳ [iOS](analytics.chainedconfiguration.ios.md)
+
+↳ [Android](analytics.chainedconfiguration.android.md)
+
+## Index
+
+### Methods
+
+* [android](analytics.chainedconfiguration.base.md#android)
+* [ios](analytics.chainedconfiguration.base.md#ios)
+* [setup](analytics.chainedconfiguration.base.md#setup)
+
+---
+
+## Methods
+
+
+
+### android
+
+▸ **android**(): [Android](analytics.chainedconfiguration.android.md)
+
+*Defined in analytics.ts:193*
+
+Access Android specific settings
+
+**Returns:** [Android](analytics.chainedconfiguration.android.md)
+
+___
+
+
+### ios
+
+▸ **ios**(): [iOS](analytics.chainedconfiguration.ios.md)
+
+*Defined in analytics.ts:189*
+
+Access iOS specific settings
+
+**Returns:** [iOS](analytics.chainedconfiguration.ios.md)
+
+___
+
+
+### setup
+
+▸ **setup**(writeKey: *[WriteKey](../#writekey)*): `Promise`<[Client](../classes/analytics.client.md)>
+
+*Defined in analytics.ts:185*
+
+Finalize the configuration and initialize the Analytics client.
+
+**Parameters:**
+
+| Param | Type | Description |
+| ------ | ------ | ------ |
+| writeKey | [WriteKey](../#writekey) | your Segment.io write key |
+
+**Returns:** `Promise`<[Client](../classes/analytics.client.md)>
+
+___
+
diff --git a/packages/core/docs/interfaces/analytics.chainedconfiguration.configuration.md b/packages/core/docs/interfaces/analytics.chainedconfiguration.configuration.md
new file mode 100644
index 000000000..06065de88
--- /dev/null
+++ b/packages/core/docs/interfaces/analytics.chainedconfiguration.configuration.md
@@ -0,0 +1,170 @@
+[@segment/react-native](../README.md) > [ChainedConfiguration](../modules/analytics.chainedconfiguration.md) > [Configuration](../interfaces/analytics.chainedconfiguration.configuration.md)
+
+# Interface: Configuration
+
+## Hierarchy
+
+ [Base](analytics.chainedconfiguration.base.md)
+
+**↳ Configuration**
+
+## Index
+
+### Methods
+
+* [android](analytics.chainedconfiguration.configuration.md#android)
+* [debug](analytics.chainedconfiguration.configuration.md#debug)
+* [flushAt](analytics.chainedconfiguration.configuration.md#flushat)
+* [ios](analytics.chainedconfiguration.configuration.md#ios)
+* [recordScreenViews](analytics.chainedconfiguration.configuration.md#recordscreenviews)
+* [setup](analytics.chainedconfiguration.configuration.md#setup)
+* [trackAppLifecycleEvents](analytics.chainedconfiguration.configuration.md#trackapplifecycleevents)
+* [trackAttributionData](analytics.chainedconfiguration.configuration.md#trackattributiondata)
+* [using](analytics.chainedconfiguration.configuration.md#using)
+
+---
+
+## Methods
+
+
+
+### android
+
+▸ **android**(): [Android](analytics.chainedconfiguration.android.md)
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[android](analytics.chainedconfiguration.base.md#android)*
+
+*Defined in analytics.ts:193*
+
+Access Android specific settings
+
+**Returns:** [Android](analytics.chainedconfiguration.android.md)
+
+___
+
+
+### debug
+
+▸ **debug**(): `this`
+
+*Defined in analytics.ts:223*
+
+**Returns:** `this`
+
+___
+
+
+### flushAt
+
+▸ **flushAt**(at: *`number`*): `this`
+
+*Defined in analytics.ts:218*
+
+The number of queued events that the analytics client should flush at.
+
+Setting this to `1` will not queue any events and will use more battery. `20` by default.
+
+**Parameters:**
+
+| Param | Type |
+| ------ | ------ |
+| at | `number` |
+
+**Returns:** `this`
+
+___
+
+
+### ios
+
+▸ **ios**(): [iOS](analytics.chainedconfiguration.ios.md)
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[ios](analytics.chainedconfiguration.base.md#ios)*
+
+*Defined in analytics.ts:189*
+
+Access iOS specific settings
+
+**Returns:** [iOS](analytics.chainedconfiguration.ios.md)
+
+___
+
+
+### recordScreenViews
+
+▸ **recordScreenViews**(): `this`
+
+*Defined in analytics.ts:202*
+
+Whether the analytics client should automatically make a screen call when a view controller is added to a view hierarchy. Because the iOS underlying implementation uses method swizzling, we recommend initializing the analytics client as early as possible (before any screens are displayed).
+
+**Returns:** `this`
+
+___
+
+
+### setup
+
+▸ **setup**(writeKey: *[WriteKey](../#writekey)*): `Promise`<[Client](../classes/analytics.client.md)>
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[setup](analytics.chainedconfiguration.base.md#setup)*
+
+*Defined in analytics.ts:185*
+
+Finalize the configuration and initialize the Analytics client.
+
+**Parameters:**
+
+| Param | Type | Description |
+| ------ | ------ | ------ |
+| writeKey | [WriteKey](../#writekey) | your Segment.io write key |
+
+**Returns:** `Promise`<[Client](../classes/analytics.client.md)>
+
+___
+
+
+### trackAppLifecycleEvents
+
+▸ **trackAppLifecycleEvents**(): `this`
+
+*Defined in analytics.ts:207*
+
+Enable the automatic tracking of application lifecycle events, such as "Application Installed", "Application Updated" and "Application Opened".
+
+**Returns:** `this`
+
+___
+
+
+### trackAttributionData
+
+▸ **trackAttributionData**(): `this`
+
+*Defined in analytics.ts:211*
+
+Whether the analytics client should automatically track attribution data from enabled providers using the mobile service.
+
+**Returns:** `this`
+
+___
+
+
+### using
+
+▸ **using**(...integrations: *[Integration](../#integration)[]*): `this`
+
+*Defined in analytics.ts:222*
+
+Register a set of integrations to be used with this Analytics instance.
+
+**Parameters:**
+
+| Param | Type |
+| ------ | ------ |
+| `Rest` integrations | [Integration](../#integration)[] |
+
+**Returns:** `this`
+
+___
+
diff --git a/packages/core/docs/interfaces/analytics.chainedconfiguration.ios.md b/packages/core/docs/interfaces/analytics.chainedconfiguration.ios.md
new file mode 100644
index 000000000..a42b577cd
--- /dev/null
+++ b/packages/core/docs/interfaces/analytics.chainedconfiguration.ios.md
@@ -0,0 +1,120 @@
+[@segment/react-native](../README.md) > [ChainedConfiguration](../modules/analytics.chainedconfiguration.md) > [iOS](../interfaces/analytics.chainedconfiguration.ios.md)
+
+# Interface: iOS
+
+## Hierarchy
+
+ [Base](analytics.chainedconfiguration.base.md)
+
+**↳ iOS**
+
+## Index
+
+### Methods
+
+* [android](analytics.chainedconfiguration.ios.md#android)
+* [ios](analytics.chainedconfiguration.ios.md#ios)
+* [recordBluetooth](analytics.chainedconfiguration.ios.md#recordbluetooth)
+* [setup](analytics.chainedconfiguration.ios.md#setup)
+* [trackAdvertising](analytics.chainedconfiguration.ios.md#trackadvertising)
+* [trackDeepLinks](analytics.chainedconfiguration.ios.md#trackdeeplinks)
+
+---
+
+## Methods
+
+
+
+### android
+
+▸ **android**(): [Android](analytics.chainedconfiguration.android.md)
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[android](analytics.chainedconfiguration.base.md#android)*
+
+*Defined in analytics.ts:193*
+
+Access Android specific settings
+
+**Returns:** [Android](analytics.chainedconfiguration.android.md)
+
+___
+
+
+### ios
+
+▸ **ios**(): [iOS](analytics.chainedconfiguration.ios.md)
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[ios](analytics.chainedconfiguration.base.md#ios)*
+
+*Defined in analytics.ts:189*
+
+Access iOS specific settings
+
+**Returns:** [iOS](analytics.chainedconfiguration.ios.md)
+
+___
+
+
+### recordBluetooth
+
+▸ **recordBluetooth**(): `this`
+
+*Defined in analytics.ts:233*
+
+Whether the analytics client should record bluetooth information.
+
+When enabled please make sure to add a description for `NSBluetoothPeripheralUsageDescription` in your `Info.plist` explaining explaining why your app is accessing Bluetooth APIs.
+
+**Returns:** `this`
+
+___
+
+
+### setup
+
+▸ **setup**(writeKey: *[WriteKey](../#writekey)*): `Promise`<[Client](../classes/analytics.client.md)>
+
+*Inherited from [Base](analytics.chainedconfiguration.base.md).[setup](analytics.chainedconfiguration.base.md#setup)*
+
+*Defined in analytics.ts:185*
+
+Finalize the configuration and initialize the Analytics client.
+
+**Parameters:**
+
+| Param | Type | Description |
+| ------ | ------ | ------ |
+| writeKey | [WriteKey](../#writekey) | your Segment.io write key |
+
+**Returns:** `Promise`<[Client](../classes/analytics.client.md)>
+
+___
+
+
+### trackAdvertising
+
+▸ **trackAdvertising**(): `this`
+
+*Defined in analytics.ts:237*
+
+Whether the analytics client should track advertisting info.
+
+**Returns:** `this`
+
+___
+
+
+### trackDeepLinks
+
+▸ **trackDeepLinks**(): `this`
+
+*Defined in analytics.ts:243*
+
+Whether the analytics client should automatically track deep links.
+
+You'll still need to call the continueUserActivity and openURL methods on the analytics client.
+
+**Returns:** `this`
+
+___
+
diff --git a/packages/core/docs/modules/analytics.chainedconfiguration.md b/packages/core/docs/modules/analytics.chainedconfiguration.md
new file mode 100644
index 000000000..bd79f898f
--- /dev/null
+++ b/packages/core/docs/modules/analytics.chainedconfiguration.md
@@ -0,0 +1,15 @@
+[@segment/react-native](../README.md) > [ChainedConfiguration](../modules/analytics.chainedconfiguration.md)
+
+# Module: ChainedConfiguration
+
+## Index
+
+### Interfaces
+
+* [Android](../interfaces/analytics.chainedconfiguration.android.md)
+* [Base](../interfaces/analytics.chainedconfiguration.base.md)
+* [Configuration](../interfaces/analytics.chainedconfiguration.configuration.md)
+* [iOS](../interfaces/analytics.chainedconfiguration.ios.md)
+
+---
+
diff --git a/packages/core/package.json b/packages/core/package.json
index 1fb66d96d..ef0ae5d5b 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,56 +1,60 @@
{
- "name": "@segment/react-native",
- "version": "0.0.1",
- "description": "The hassle-free way to add analytics to your React-Native app.",
- "license": "MIT",
- "main": "build/cjs/index.js",
- "module": "build/esm/index.js",
- "types": "build/esm/index.d.ts",
- "files": [
- "android",
- "ios",
- "build",
- "src",
- "RNAnalytics.podspec"
- ],
- "scripts": {
- "build:clean": "rimraf build",
- "build:ts": "run-p build:ts:*",
- "build:ts:cjs": "tsc --target es5 --outDir build/cjs --module commonjs",
- "build:ts:esm": "tsc --target es5 --outDir build/esm --module esnext",
- "build": "run-s build:{clean,ts}",
- "docs:clean": "rimraf docs",
- "docs:gen": "typedoc --out docs --ignoreCompilerErrors --excludePrivate --excludeExternals --theme markdown --mode file --entrypoint Analytics --gitRevision master",
- "docs": "run-s docs:clean docs:gen",
- "test": "jest"
- },
- "devDependencies": {
- "@types/jest": "^23.3.1",
- "babel-core": "^6.26.3",
- "babel-jest": "^23.4.2",
- "jest": "^23.4.2",
- "jest-mock-console": "^0.4.0",
- "ts-jest": "^23.1.3",
- "typedoc": "^0.11.1",
- "typedoc-plugin-markdown": "^1.1.13",
- "typescript": "^3.0.1"
+ "name": "@segment/react-native",
+ "version": "0.0.1",
+ "description": "The hassle-free way to add analytics to your React-Native app.",
+ "license": "MIT",
+ "main": "build/cjs/index.js",
+ "module": "build/esm/index.js",
+ "types": "build/esm/index.d.ts",
+ "files": [
+ "android",
+ "ios",
+ "build",
+ "src",
+ "RNAnalytics.podspec"
+ ],
+ "scripts": {
+ "build:clean": "rimraf build",
+ "build:ts": "run-p build:ts:*",
+ "build:ts:cjs": "tsc --target es5 --outDir build/cjs --module commonjs",
+ "build:ts:esm": "tsc --target es5 --outDir build/esm --module esnext",
+ "build": "run-s build:{clean,ts}",
+ "docs:clean": "rimraf docs",
+ "docs:gen": "typedoc --out docs --ignoreCompilerErrors --excludePrivate --excludeExternals --theme markdown --mode file --entrypoint Analytics --gitRevision master",
+ "docs": "run-s docs:{clean,gen}",
+ "lint": "tslint -p .",
+ "test": "jest"
+ },
+ "devDependencies": {
+ "@types/jest": "^23.3.1",
+ "babel-core": "^6.26.3",
+ "babel-jest": "^23.4.2",
+ "jest": "^23.4.2",
+ "jest-mock-console": "^0.4.0",
+ "ts-jest": "^23.1.3",
+ "tslint": "^5.11.0",
+ "tslint-config-prettier": "^1.14.0",
+ "tslint-plugin-prettier": "^1.3.0",
+ "typedoc": "^0.11.1",
+ "typedoc-plugin-markdown": "^1.1.13",
+ "typescript": "^3.0.1"
+ },
+ "jest": {
+ "transform": {
+ "^.+\\.tsx?$": "ts-jest"
},
- "jest": {
- "transform": {
- "^.+\\.tsx?$": "ts-jest"
- },
- "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(tsx?)$",
- "moduleFileExtensions": [
- "ts",
- "tsx",
- "js",
- "jsx",
- "json",
- "node"
- ],
- "rootDir": "src",
- "collectCoverage": true,
- "coverageDirectory": "../build/coverage",
- "testEnvironment": "node"
- }
+ "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(tsx?)$",
+ "moduleFileExtensions": [
+ "ts",
+ "tsx",
+ "js",
+ "jsx",
+ "json",
+ "node"
+ ],
+ "rootDir": "src",
+ "collectCoverage": true,
+ "coverageDirectory": "../build/coverage",
+ "testEnvironment": "node"
+ }
}
diff --git a/packages/core/src/__mocks__/bridge.ts b/packages/core/src/__mocks__/bridge.ts
index 5179db00f..8ea32d0bd 100644
--- a/packages/core/src/__mocks__/bridge.ts
+++ b/packages/core/src/__mocks__/bridge.ts
@@ -1,12 +1,12 @@
export default {
- setup: jest.fn(),
- track: jest.fn(),
- identify: jest.fn(),
- screen: jest.fn(),
- group: jest.fn(),
- alias: jest.fn(),
- reset: jest.fn(),
- flush: jest.fn(),
- enable: jest.fn(),
- disable: jest.fn()
+ alias: jest.fn(),
+ disable: jest.fn(),
+ enable: jest.fn(),
+ flush: jest.fn(),
+ group: jest.fn(),
+ identify: jest.fn(),
+ reset: jest.fn(),
+ screen: jest.fn(),
+ setup: jest.fn(),
+ track: jest.fn()
}
diff --git a/packages/core/src/__tests__/analytics.spec.ts b/packages/core/src/__tests__/analytics.spec.ts
index 54619c491..63f53275f 100644
--- a/packages/core/src/__tests__/analytics.spec.ts
+++ b/packages/core/src/__tests__/analytics.spec.ts
@@ -1,94 +1,80 @@
-import mockConsole, {RestoreConsole} from 'jest-mock-console'
+import mockConsole, { RestoreConsole } from 'jest-mock-console'
-import {Analytics} from '../analytics'
+import { Analytics } from '../analytics'
import Bridge from '../bridge'
jest.mock('../bridge')
-const getBridgeStub = (name: K): jest.Mock<(typeof Bridge)[K]> => (Bridge as any)[name]
+const getBridgeStub = (
+ name: K
+): jest.Mock<(typeof Bridge)[K]> => (Bridge as any)[name]
let analytics: Analytics.Client = null!
let restoreConsole: RestoreConsole = null!
beforeEach(async () => {
- restoreConsole = mockConsole()
- analytics = new Analytics.Client()
- Object.keys(Bridge).forEach(key =>
- getBridgeStub(key as any).mockClear()
- )
-
- await analytics
- .configure()
- .setup('write key')
+ restoreConsole = mockConsole()
+ analytics = new Analytics.Client()
+ Object.keys(Bridge).forEach(key => getBridgeStub(key as any).mockClear())
+
+ await analytics.configure().setup('write key')
})
afterEach(() => {
- restoreConsole()
+ restoreConsole()
})
-it('is ready', () =>
- expect(analytics.ready).toBe(true)
-)
+it('is ready', () => expect(analytics.ready).toBe(true))
it('catches bridge errors', async () => {
- const error = new Error('test-error')
- const onError = jest.fn()
-
- getBridgeStub('track').mockImplementationOnce(() => Promise.reject(error))
- analytics.catch(onError)
- analytics.track('test')
-
- expect(onError).not.toHaveBeenCalled()
- await new Promise(resolve => setImmediate(resolve))
- expect(onError).toHaveBeenCalledWith(error)
+ const error = new Error('test-error')
+ const onError = jest.fn()
+
+ getBridgeStub('track').mockImplementationOnce(() => Promise.reject(error))
+ analytics.catch(onError)
+ analytics.track('test')
+
+ expect(onError).not.toHaveBeenCalled()
+ await new Promise(resolve => setImmediate(resolve))
+ expect(onError).toHaveBeenCalledWith(error)
})
it('logs uncaught bridge errors', async () => {
- const error = new Error('test-error')
-
- getBridgeStub('track').mockImplementationOnce(() =>
- new Promise((_, reject) =>
- setImmediate(() => reject(error))
- )
- )
- analytics.track('test')
-
- expect(console.error).not.toHaveBeenCalled()
- await new Promise(resolve => setImmediate(resolve))
- expect(console.error).toHaveBeenCalledWith('Uncaught Analytics error', error)
+ const error = new Error('test-error')
+
+ getBridgeStub('track').mockImplementationOnce(
+ () => new Promise((_, reject) => setImmediate(() => reject(error)))
+ )
+ analytics.track('test')
+
+ expect(console.error).not.toHaveBeenCalled()
+ await new Promise(resolve => setImmediate(resolve))
+ expect(console.error).toHaveBeenCalledWith('Uncaught Analytics error', error)
})
it('waits for .setup()', async () => {
- const client = new Analytics.Client()
+ const client = new Analytics.Client()
+
+ client.track('test 1')
+ client.track('test 2')
- client.track('test 1')
- client.track('test 2')
-
- expect(Bridge.track).not.toHaveBeenCalled()
- await client.configure().setup('key')
+ expect(Bridge.track).not.toHaveBeenCalled()
+ await client.configure().setup('key')
- expect(Bridge.track).toHaveBeenNthCalledWith(1, 'test 1', {})
- expect(Bridge.track).toHaveBeenNthCalledWith(2, 'test 2', {})
+ expect(Bridge.track).toHaveBeenNthCalledWith(1, 'test 1', {})
+ expect(Bridge.track).toHaveBeenNthCalledWith(2, 'test 2', {})
})
it('does .track()', () =>
- testCall('track')('Added to cart', {productId: 'azertyuiop'})
-)
+ testCall('track')('Added to cart', { productId: 'azertyuiop' }))
it('does .screen()', () =>
- testCall('screen')('Shopping cart', {from: 'Product page'})
-)
+ testCall('screen')('Shopping cart', { from: 'Product page' }))
-it('does .identify()', () =>
- testCall('identify')('sloth', {eats: 'leaves'})
-)
+it('does .identify()', () => testCall('identify')('sloth', { eats: 'leaves' }))
-it('does .group()', () =>
- testCall('group')('bots', {humans: false})
-)
+it('does .group()', () => testCall('group')('bots', { humans: false }))
-it('does .alias()', () =>
- testCall('alias')('new alias')
-)
+it('does .alias()', () => testCall('alias')('new alias'))
it('does .reset()', testCall('reset'))
it('does .flush()', testCall('flush'))
@@ -96,8 +82,8 @@ it('does .enable()', testCall('enable'))
it('does .disable()', testCall('disable'))
function testCall(name: K): (typeof Bridge)[K] {
- return function(...args: any[]) {
- (analytics as any)[name](...args)
- expect(Bridge[name]).toHaveBeenNthCalledWith(1, ...args)
- } as any
+ return ((...args: any[]) => {
+ analytics.constructor.prototype[name].call(analytics, ...args)
+ expect(Bridge[name]).toHaveBeenNthCalledWith(1, ...args)
+ }) as any
}
diff --git a/packages/core/src/__tests__/configuration.spec.ts b/packages/core/src/__tests__/configuration.spec.ts
index a9f6e1574..9bf95fa85 100644
--- a/packages/core/src/__tests__/configuration.spec.ts
+++ b/packages/core/src/__tests__/configuration.spec.ts
@@ -1,5 +1,5 @@
-import {configure} from '../configuration'
import Bridge from '../bridge'
+import { configure } from '../configuration'
jest.mock('../bridge')
@@ -7,113 +7,110 @@ const config = () => configure(null as any, jest.fn())
const writeKey = 'test-write-key'
const defaultConfig = {
- flushAt: 20,
-
- recordScreenViews: false,
- trackAppLifecycleEvents: false,
- trackAttributionData: false,
- debug: false,
-
- ios: {
- writeKey,
- recordBluetooth: false,
- trackAdvertising: false,
- trackDeepLinks: false
- },
- android: {
- writeKey,
- collectDeviceId: true
- }
+ flushAt: 20,
+
+ debug: false,
+ recordScreenViews: false,
+ trackAppLifecycleEvents: false,
+ trackAttributionData: false,
+
+ android: {
+ collectDeviceId: true,
+ writeKey
+ },
+ ios: {
+ recordBluetooth: false,
+ trackAdvertising: false,
+ trackDeepLinks: false,
+ writeKey
+ }
}
beforeEach(() => {
- (Bridge.setup as jest.Mock).mockClear()
+ ;(Bridge.setup as jest.Mock).mockClear()
})
it('uses the default configuration', async () => {
- await config().setup(writeKey)
+ await config().setup(writeKey)
- expect(Bridge.setup).toHaveBeenLastCalledWith(defaultConfig)
+ expect(Bridge.setup).toHaveBeenLastCalledWith(defaultConfig)
})
it('produces a valid configuration', async () => {
- await config()
- .recordScreenViews()
- .trackAppLifecycleEvents()
- .trackAttributionData()
- .flushAt(42)
- .debug()
- .ios()
- .recordBluetooth()
- .trackAdvertising()
- .trackDeepLinks()
- .android()
- .disableDeviceId()
- .setup(writeKey)
-
- expect(Bridge.setup).toHaveBeenLastCalledWith({
- flushAt: 42,
-
- recordScreenViews: true,
- trackAppLifecycleEvents: true,
- trackAttributionData: true,
- debug: true,
-
- ios: {
- writeKey,
- recordBluetooth: true,
- trackAdvertising: true,
- trackDeepLinks: true
- },
- android: {
- writeKey,
- collectDeviceId: false
- }
- })
+ await config()
+ .recordScreenViews()
+ .trackAppLifecycleEvents()
+ .trackAttributionData()
+ .flushAt(42)
+ .debug()
+ .ios()
+ .recordBluetooth()
+ .trackAdvertising()
+ .trackDeepLinks()
+ .android()
+ .disableDeviceId()
+ .setup(writeKey)
+
+ expect(Bridge.setup).toHaveBeenLastCalledWith({
+ flushAt: 42,
+
+ debug: true,
+ recordScreenViews: true,
+ trackAppLifecycleEvents: true,
+ trackAttributionData: true,
+
+ android: {
+ collectDeviceId: false,
+ writeKey
+ },
+ ios: {
+ recordBluetooth: true,
+ trackAdvertising: true,
+ trackDeepLinks: true,
+ writeKey
+ }
+ })
})
it('supports per-platform write keys', async () => {
- const android = 'write key android'
- const ios = 'write key ios'
-
- await config().setup({ios, android})
-
- expect(Bridge.setup).toHaveBeenLastCalledWith({
- ...defaultConfig,
- ios: {
- ...defaultConfig.ios,
- writeKey: ios
- },
- android: {
- ...defaultConfig.android,
- writeKey: android
- }
- })
+ const android = 'write key android'
+ const ios = 'write key ios'
+
+ await config().setup({ ios, android })
+
+ expect(Bridge.setup).toHaveBeenLastCalledWith({
+ ...defaultConfig,
+ android: {
+ ...defaultConfig.android,
+ writeKey: android
+ },
+ ios: {
+ ...defaultConfig.ios,
+ writeKey: ios
+ }
+ })
})
it('waits for integrations to register', async () => {
- const stub = jest.fn(async t =>
- setTimeout(
- () => {
- expect(Bridge.setup).not.toHaveBeenCalled()
- t()
- },
- 500
- )
- )
-
- await config()
- .using(() => ({then: stub}))
- .setup(writeKey)
-
- expect(stub).toHaveBeenCalled()
- expect(Bridge.setup).toHaveBeenCalled()
+ const stub = jest.fn(async t =>
+ setTimeout(() => {
+ expect(Bridge.setup).not.toHaveBeenCalled()
+ t()
+ }, 500)
+ )
+
+ await config()
+ .using(() => ({ then: stub }))
+ .setup(writeKey)
+
+ expect(stub).toHaveBeenCalled()
+ expect(Bridge.setup).toHaveBeenCalled()
})
it('supports disabled integrations', async () => {
- await config()
- .using({disabled: true})
- .setup(writeKey)
+ await config()
+ .using({ disabled: true })
+ .setup(writeKey)
- expect(Bridge.setup).toHaveBeenCalled()
+ expect(Bridge.setup).toHaveBeenCalled()
})
diff --git a/packages/core/src/__tests__/index.spec.ts b/packages/core/src/__tests__/index.spec.ts
index b7be796cc..38a9969d3 100644
--- a/packages/core/src/__tests__/index.spec.ts
+++ b/packages/core/src/__tests__/index.spec.ts
@@ -1,8 +1,7 @@
-import {analytics} from '..'
-import {Analytics} from '../analytics'
+import { analytics } from '..'
+import { Analytics } from '../analytics'
jest.mock('../bridge')
it('exports an instance of Analytics.Client', () =>
- expect(analytics).toBeInstanceOf(Analytics.Client)
-)
+ expect(analytics).toBeInstanceOf(Analytics.Client))
diff --git a/packages/core/src/analytics.ts b/packages/core/src/analytics.ts
index 5b662ef44..002a87c09 100644
--- a/packages/core/src/analytics.ts
+++ b/packages/core/src/analytics.ts
@@ -1,266 +1,264 @@
import Bridge from './bridge'
-import {configure} from './configuration'
-import {ErrorHandler, nativeWrapper} from './utils'
+import { configure } from './configuration'
+import { ErrorHandler, nativeWrapper } from './utils'
export namespace Analytics {
- export class Client {
- /**
- * Whether the client is ready to send events to Segment.
- *
- * This becomes `true` when `.setup()` succeeds.
- * All calls will be queued until it becomes `true`.
- */
- public readonly ready = false
+ export class Client {
+ /**
+ * Whether the client is ready to send events to Segment.
+ *
+ * This becomes `true` when `.setup()` succeeds.
+ * All calls will be queued until it becomes `true`.
+ */
+ public readonly ready = false
- private readonly wrapper = nativeWrapper(this, err => this.handleError(err))
- private readonly handlers: ErrorHandler[] = []
+ private readonly wrapper = nativeWrapper(this, err => this.handleError(err))
+ private readonly handlers: ErrorHandler[] = []
- /**
- * Catch React-Native bridge errors
- *
- * These errors are emitted when calling the native counterpart.
- */
- public catch(handler: ErrorHandler) {
- this.handlers.push(handler)
+ /**
+ * Catch React-Native bridge errors
+ *
+ * These errors are emitted when calling the native counterpart.
+ */
+ public catch(handler: ErrorHandler) {
+ this.handlers.push(handler)
- return this
- }
+ return this
+ }
- /**
- * Configure the Analytics module.
- *
- * This method returns a fluent-style API to configure the SDK :
- * ```js
- * analytics
- * .configure()
- * .using(Mixpanel, GoogleAnalytics)
- * .trackAppLifecycle()
- * .ios()
- * .trackDeepLinks()
- * .setup("YOUR_WRITE_KEY")
- * ```
- */
- public configure() {
- return configure(this, this.wrapper.ready)
- }
+ /**
+ * Configure the Analytics module.
+ *
+ * This method returns a fluent-style API to configure the SDK :
+ * ```js
+ * analytics
+ * .configure()
+ * .using(Mixpanel, GoogleAnalytics)
+ * .trackAppLifecycle()
+ * .ios()
+ * .trackDeepLinks()
+ * .setup("YOUR_WRITE_KEY")
+ * ```
+ */
+ public configure() {
+ return configure(this, this.wrapper.ready)
+ }
- /**
- * Record the actions your users perform.
- *
- * When a user performs an action in your app, you'll want to track that action for later analysis.
- * Use the event name to say what the user did, and properties to specify any interesting details of the action.
- *
- * @param event The name of the event you're tracking.
- * We recommend using human-readable names like `Played a Song` or `Updated Status`.
- * @param properties A dictionary of properties for the event.
- * If the event was 'Added to Shopping Cart', it might have properties like price, productType, etc.
- */
- public track(event: string, properties: JsonMap = {}) {
- return this.wrapper.call(() => Bridge.track(event, properties))
- }
+ /**
+ * Record the actions your users perform.
+ *
+ * When a user performs an action in your app, you'll want to track that action for later analysis.
+ * Use the event name to say what the user did, and properties to specify any interesting details of the action.
+ *
+ * @param event The name of the event you're tracking.
+ * We recommend using human-readable names like `Played a Song` or `Updated Status`.
+ * @param properties A dictionary of properties for the event.
+ * If the event was 'Added to Shopping Cart', it might have properties like price, productType, etc.
+ */
+ public track(event: string, properties: JsonMap = {}) {
+ return this.wrapper.call(() => Bridge.track(event, properties))
+ }
- /**
- * Record the screens or views your users see.
- *
- * When a user views a screen in your app, you'll want to record that here.
- * For some tools like Google Analytics and Flurry, screen views are treated specially, and are different
- * from "events" kind of like "page views" on the web. For services that don't treat "screen views" specially,
- * we map "screen" straight to "track" with the same parameters. For example, Mixpanel doesn't treat "screen views" any differently.
- * So a call to "screen" will be tracked as a normal event in Mixpanel, but get sent to Google Analytics and Flurry as a "screen".
- *
- * @param name The title of the screen being viewed.
- * We recommend using human-readable names like 'Photo Feed' or 'Completed Purchase Screen'.
- * @param properties A dictionary of properties for the screen view event.
- * If the event was 'Added to Shopping Cart', it might have properties like price, productType, etc.
- */
- public screen(name: string, properties: JsonMap = {}) {
- return this.wrapper.call(() => Bridge.screen(name, properties))
- }
+ /**
+ * Record the screens or views your users see.
+ *
+ * When a user views a screen in your app, you'll want to record that here.
+ * For some tools like Google Analytics and Flurry, screen views are treated specially, and are different
+ * from "events" kind of like "page views" on the web. For services that don't treat "screen views" specially,
+ * we map "screen" straight to "track" with the same parameters. For example, Mixpanel doesn't treat "screen views" any differently.
+ * So a call to "screen" will be tracked as a normal event in Mixpanel, but get sent to Google Analytics and Flurry as a "screen".
+ *
+ * @param name The title of the screen being viewed.
+ * We recommend using human-readable names like 'Photo Feed' or 'Completed Purchase Screen'.
+ * @param properties A dictionary of properties for the screen view event.
+ * If the event was 'Added to Shopping Cart', it might have properties like price, productType, etc.
+ */
+ public screen(name: string, properties: JsonMap = {}) {
+ return this.wrapper.call(() => Bridge.screen(name, properties))
+ }
- /**
- * Associate a user with their unique ID and record traits about them.
- *
- * When you learn more about who your user is, you can record that information with identify.
- *
- * @param userId database ID (or email address) for this user.
- * If you don't have a userId but want to record traits, you should pass nil.
- * For more information on how we generate the UUID and Apple's policies on IDs, see https://segment.io/libraries/ios#ids
- * @param traits A dictionary of traits you know about the user. Things like: email, name, plan, etc.
- */
- public identify(userId: string, traits: JsonMap = {}) {
- return this.wrapper.call(() => Bridge.identify(userId, traits))
- }
+ /**
+ * Associate a user with their unique ID and record traits about them.
+ *
+ * When you learn more about who your user is, you can record that information with identify.
+ *
+ * @param userId database ID (or email address) for this user.
+ * If you don't have a userId but want to record traits, you should pass nil.
+ * For more information on how we generate the UUID and Apple's policies on IDs, see https://segment.io/libraries/ios#ids
+ * @param traits A dictionary of traits you know about the user. Things like: email, name, plan, etc.
+ */
+ public identify(userId: string, traits: JsonMap = {}) {
+ return this.wrapper.call(() => Bridge.identify(userId, traits))
+ }
- /**
- * Associate a user with a group, organization, company, project, or w/e *you* call them.
- *
- * When you learn more about who the group is, you can record that information with group.
- *
- * @param groupId A database ID for this group.
- * @param traits A dictionary of traits you know about the group. Things like: name, employees, etc.
- */
- public group(groupId: string, traits: JsonMap = {}) {
- return this.wrapper.call(() => Bridge.group(groupId, traits))
- }
+ /**
+ * Associate a user with a group, organization, company, project, or w/e *you* call them.
+ *
+ * When you learn more about who the group is, you can record that information with group.
+ *
+ * @param groupId A database ID for this group.
+ * @param traits A dictionary of traits you know about the group. Things like: name, employees, etc.
+ */
+ public group(groupId: string, traits: JsonMap = {}) {
+ return this.wrapper.call(() => Bridge.group(groupId, traits))
+ }
- /**
- * Merge two user identities, effectively connecting two sets of user data as one.
- * This may not be supported by all integrations.
- *
- * When you learn more about who the group is, you can record that information with group.
- *
- * @param newId The new ID you want to alias the existing ID to.
- * The existing ID will be either the previousId if you have called identify, or the anonymous ID.
- */
- public alias(newId: string) {
- return this.wrapper.call(() => Bridge.alias(newId))
- }
+ /**
+ * Merge two user identities, effectively connecting two sets of user data as one.
+ * This may not be supported by all integrations.
+ *
+ * When you learn more about who the group is, you can record that information with group.
+ *
+ * @param newId The new ID you want to alias the existing ID to.
+ * The existing ID will be either the previousId if you have called identify, or the anonymous ID.
+ */
+ public alias(newId: string) {
+ return this.wrapper.call(() => Bridge.alias(newId))
+ }
- /**
- * Reset any user state that is cached on the device.
- *
- * This is useful when a user logs out and you want to clear the identity.
- * It will clear any traits or userId's cached on the device.
- */
- public reset() {
- return this.wrapper.call(Bridge.reset)
- }
+ /**
+ * Reset any user state that is cached on the device.
+ *
+ * This is useful when a user logs out and you want to clear the identity.
+ * It will clear any traits or userId's cached on the device.
+ */
+ public reset() {
+ return this.wrapper.call(Bridge.reset)
+ }
- /**
- * Trigger an upload of all queued events.
- *
- * This is useful when you want to force all messages queued on the device to be uploaded.
- * Please note that not all integrations respond to this method.
- */
- public flush() {
- return this.wrapper.call(Bridge.flush)
- }
+ /**
+ * Trigger an upload of all queued events.
+ *
+ * This is useful when you want to force all messages queued on the device to be uploaded.
+ * Please note that not all integrations respond to this method.
+ */
+ public flush() {
+ return this.wrapper.call(Bridge.flush)
+ }
- /**
- * Enable the sending of analytics data. Enabled by default.
- *
- * Occasionally used in conjunction with disable user opt-out handling.
- */
- public enable() {
- return this.wrapper.call(Bridge.enable)
- }
+ /**
+ * Enable the sending of analytics data. Enabled by default.
+ *
+ * Occasionally used in conjunction with disable user opt-out handling.
+ */
+ public enable() {
+ return this.wrapper.call(Bridge.enable)
+ }
- /**
- * Completely disable the sending of any analytics data.
- *
- * If you have a way for users to actively or passively (sometimes based on location) opt-out of
- * analytics data collection, you can use this method to turn off all data collection.
- */
- public disable() {
- return this.wrapper.call(Bridge.disable)
- }
+ /**
+ * Completely disable the sending of any analytics data.
+ *
+ * If you have a way for users to actively or passively (sometimes based on location) opt-out of
+ * analytics data collection, you can use this method to turn off all data collection.
+ */
+ public disable() {
+ return this.wrapper.call(Bridge.disable)
+ }
- private handleError(error: Error) {
- const {handlers} = this
+ private handleError(error: Error) {
+ const { handlers } = this
- if(!handlers.length) {
- console.error('Uncaught Analytics error', error)
- throw error
- }
- else {
- handlers.forEach(handler => handler(error))
- }
- }
- }
+ if (!handlers.length) {
+ console.error('Uncaught Analytics error', error)
+ throw error
+ } else {
+ handlers.forEach(handler => handler(error))
+ }
+ }
+ }
- export type Integration =
- | (() => PromiseLike)
- | {disabled: true}
+ export type Integration = (() => PromiseLike) | { disabled: true }
- export type WriteKey =
- | string
- | {
- android: string
- ios: string
- }
+ export type WriteKey =
+ | string
+ | {
+ android: string
+ ios: string
+ }
- export namespace ChainedConfiguration {
- export interface Base {
- /**
- * Finalize the configuration and initialize the Analytics client.
- * @param writeKey your Segment.io write key
- */
- setup(writeKey: WriteKey): Promise
- /**
- * Access iOS specific settings
- */
- ios(): iOS
- /**
- * Access Android specific settings
- */
- android(): Android
- }
- export interface Configuration extends Base {
- /**
- * Whether the analytics client should automatically make a screen call when a
- * view controller is added to a view hierarchy.
- * Because the iOS underlying implementation uses method swizzling,
- * we recommend initializing the analytics client as early as possible (before any screens are displayed).
- */
- recordScreenViews(): this
- /**
- * Enable the automatic tracking of application lifecycle events, such as
- * "Application Installed", "Application Updated" and "Application Opened".
- */
- trackAppLifecycleEvents(): this
- /**
- * Whether the analytics client should automatically track attribution data from enabled providers using the mobile service.
- */
- trackAttributionData(): this
- /**
- * The number of queued events that the analytics client should flush at.
- *
- * Setting this to `1` will not queue any events and will use more battery.
- * `20` by default.
- */
- flushAt(at: number): this
- /**
- * Register a set of integrations to be used with this Analytics instance.
- */
- using(...integrations: Integration[]): this
- debug(): this
- }
- export interface iOS extends Base {
- /**
- * Whether the analytics client should record bluetooth information.
- *
- * When enabled please make sure to add a description for `NSBluetoothPeripheralUsageDescription` in
- * your `Info.plist` explaining explaining why your app is accessing Bluetooth APIs.
- */
- recordBluetooth(): this
- /**
- * Whether the analytics client should track advertisting info.
- */
- trackAdvertising(): this
- /**
- * Whether the analytics client should automatically track deep links.
- *
- * You'll still need to call the continueUserActivity and openURL methods on the analytics client.
- */
- trackDeepLinks(): this
- }
- export interface Android extends Base {
- /**
- * Disable the collection of the device identifier. Enabled by default.
- *
- * The device identifier is obtained using :
- * - `android.provider.Settings.Secure.ANDROID_ID`
- * - `android.os.Build.SERIAL`
- * - or Telephony Identifier retrieved via TelephonyManager as available
- */
- disableDeviceId(): this
- }
- }
+ export namespace ChainedConfiguration {
+ export interface Base {
+ /**
+ * Finalize the configuration and initialize the Analytics client.
+ * @param writeKey your Segment.io write key
+ */
+ setup(writeKey: WriteKey): Promise
+ /**
+ * Access iOS specific settings
+ */
+ ios(): iOS
+ /**
+ * Access Android specific settings
+ */
+ android(): Android
+ }
+ export interface Configuration extends Base {
+ /**
+ * Whether the analytics client should automatically make a screen call when a
+ * view controller is added to a view hierarchy.
+ * Because the iOS underlying implementation uses method swizzling,
+ * we recommend initializing the analytics client as early as possible (before any screens are displayed).
+ */
+ recordScreenViews(): this
+ /**
+ * Enable the automatic tracking of application lifecycle events, such as
+ * "Application Installed", "Application Updated" and "Application Opened".
+ */
+ trackAppLifecycleEvents(): this
+ /**
+ * Whether the analytics client should automatically track attribution data from enabled providers using the mobile service.
+ */
+ trackAttributionData(): this
+ /**
+ * The number of queued events that the analytics client should flush at.
+ *
+ * Setting this to `1` will not queue any events and will use more battery.
+ * `20` by default.
+ */
+ flushAt(at: number): this
+ /**
+ * Register a set of integrations to be used with this Analytics instance.
+ */
+ using(...integrations: Integration[]): this
+ debug(): this
+ }
+ // tslint:disable-next-line
+ export interface iOS extends Base {
+ /**
+ * Whether the analytics client should record bluetooth information.
+ *
+ * When enabled please make sure to add a description for `NSBluetoothPeripheralUsageDescription` in
+ * your `Info.plist` explaining explaining why your app is accessing Bluetooth APIs.
+ */
+ recordBluetooth(): this
+ /**
+ * Whether the analytics client should track advertisting info.
+ */
+ trackAdvertising(): this
+ /**
+ * Whether the analytics client should automatically track deep links.
+ *
+ * You'll still need to call the continueUserActivity and openURL methods on the analytics client.
+ */
+ trackDeepLinks(): this
+ }
+ export interface Android extends Base {
+ /**
+ * Disable the collection of the device identifier. Enabled by default.
+ *
+ * The device identifier is obtained using :
+ * - `android.provider.Settings.Secure.ANDROID_ID`
+ * - `android.os.Build.SERIAL`
+ * - or Telephony Identifier retrieved via TelephonyManager as available
+ */
+ disableDeviceId(): this
+ }
+ }
}
export type JsonValue = boolean | number | string | null | JsonList | JsonMap
export interface JsonMap {
- [key: string]: JsonValue
- [index: number]: JsonValue
+ [key: string]: JsonValue
+ [index: number]: JsonValue
}
export interface JsonList extends Array {}
diff --git a/packages/core/src/bridge.ts b/packages/core/src/bridge.ts
index 0d606e3e9..805787cb8 100644
--- a/packages/core/src/bridge.ts
+++ b/packages/core/src/bridge.ts
@@ -1,3 +1,3 @@
-import {NativeModules} from 'react-native'
+import { NativeModules } from 'react-native'
export default NativeModules.RNAnalytics
diff --git a/packages/core/src/configuration.ts b/packages/core/src/configuration.ts
index b8e08ec8c..1de062ee4 100644
--- a/packages/core/src/configuration.ts
+++ b/packages/core/src/configuration.ts
@@ -1,75 +1,76 @@
+import { Analytics } from './analytics'
import Bridge from './bridge'
-import {toggle} from './utils'
-import {Analytics} from './analytics'
+import { toggle } from './utils'
-export function configure(analytics: Analytics.Client, done: () => void): Analytics.ChainedConfiguration.Configuration {
- const promises: Array> = []
- const config = {
- flushAt: 20,
+export function configure(
+ analytics: Analytics.Client,
+ done: () => void
+): Analytics.ChainedConfiguration.Configuration {
+ const promises: Array> = []
+ const config = {
+ flushAt: 20,
- recordScreenViews: false,
- trackAppLifecycleEvents: false,
- trackAttributionData: false,
- debug: false,
+ debug: false,
+ recordScreenViews: false,
+ trackAppLifecycleEvents: false,
+ trackAttributionData: false,
- ios: {
- recordBluetooth: false,
- trackAdvertising: false,
- trackDeepLinks: false,
- writeKey: ''
- },
- android: {
- writeKey: '',
- collectDeviceId: true
- }
- }
+ android: {
+ collectDeviceId: true,
+ writeKey: ''
+ },
+ ios: {
+ recordBluetooth: false,
+ trackAdvertising: false,
+ trackDeepLinks: false,
+ writeKey: ''
+ }
+ }
- const baseMatcher = {
- setup: async (writeKey: Analytics.WriteKey) => {
- if(typeof writeKey === 'string') {
- config.ios.writeKey = writeKey
- config.android.writeKey = writeKey
- }
- else {
- config.ios.writeKey = writeKey.ios
- config.android.writeKey = writeKey.android
- }
+ const baseMatcher = {
+ android: () => ({
+ ...baseMatcher,
+ disableDeviceId: toggle(config.android, 'collectDeviceId', false)
+ }),
+ ios: () => ({
+ ...baseMatcher,
+ recordBluetooth: toggle(config.ios, 'recordBluetooth', true),
+ trackAdvertising: toggle(config.ios, 'trackAdvertising', true),
+ trackDeepLinks: toggle(config.ios, 'trackDeepLinks', true)
+ }),
+ setup: async (writeKey: Analytics.WriteKey) => {
+ if (typeof writeKey === 'string') {
+ config.ios.writeKey = writeKey
+ config.android.writeKey = writeKey
+ } else {
+ config.ios.writeKey = writeKey.ios
+ config.android.writeKey = writeKey.android
+ }
- await Promise.all(promises)
- await Bridge.setup(config)
- done()
+ await Promise.all(promises)
+ await Bridge.setup(config)
+ done()
- return analytics
- },
- ios: () => ({
- ...baseMatcher,
- recordBluetooth: toggle(config.ios, 'recordBluetooth', true),
- trackAdvertising: toggle(config.ios, 'trackAdvertising', true),
- trackDeepLinks: toggle(config.ios, 'trackDeepLinks', true)
- }),
- android: () => ({
- ...baseMatcher,
- disableDeviceId: toggle(config.android, 'collectDeviceId', false)
- })
- }
+ return analytics
+ }
+ }
- return {
- ...baseMatcher,
- recordScreenViews: toggle(config, 'recordScreenViews', true),
- trackAppLifecycleEvents: toggle(config, 'trackAppLifecycleEvents', true),
- trackAttributionData: toggle(config, 'trackAttributionData', true),
- debug: toggle(config, 'debug', true),
- flushAt: toggle(config, 'flushAt'),
- using(...integrations: Analytics.Integration[]) {
- promises.push(
- ...integrations.map(async integration =>
- typeof integration === 'function'
- ? integration()
- : null
- )
- )
+ return {
+ ...baseMatcher,
+ debug: toggle(config, 'debug', true),
+ flushAt: toggle(config, 'flushAt'),
+ recordScreenViews: toggle(config, 'recordScreenViews', true),
+ trackAppLifecycleEvents: toggle(config, 'trackAppLifecycleEvents', true),
+ trackAttributionData: toggle(config, 'trackAttributionData', true),
+ using(...integrations: Analytics.Integration[]) {
+ promises.push(
+ ...integrations.map(
+ async integration =>
+ typeof integration === 'function' ? integration() : null
+ )
+ )
- return this
- }
- }
+ return this
+ }
+ }
}
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index ce997f00a..1a2054bb0 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,3 +1,3 @@
-import {Analytics} from './analytics'
+import { Analytics } from './analytics'
export const analytics = new Analytics.Client()
diff --git a/packages/core/src/modules.d.ts b/packages/core/src/modules.d.ts
index e139692e9..45cac563c 100644
--- a/packages/core/src/modules.d.ts
+++ b/packages/core/src/modules.d.ts
@@ -1,33 +1,33 @@
declare module 'react-native' {
- export namespace NativeModules.RNAnalytics {
- export interface Configuration {
- recordScreenViews: boolean
- trackAppLifecycleEvents: boolean
- trackAttributionData: boolean
- debug: boolean
- flushAt: number
+ export namespace NativeModules.RNAnalytics {
+ export interface Configuration {
+ recordScreenViews: boolean
+ trackAppLifecycleEvents: boolean
+ trackAttributionData: boolean
+ debug: boolean
+ flushAt: number
- ios: {
- recordBluetooth: boolean
- trackAdvertising: boolean
- trackDeepLinks: boolean
- writeKey: string
- }
- android: {
- writeKey: string
- collectDeviceId: boolean
- }
- }
+ ios: {
+ recordBluetooth: boolean
+ trackAdvertising: boolean
+ trackDeepLinks: boolean
+ writeKey: string
+ }
+ android: {
+ writeKey: string
+ collectDeviceId: boolean
+ }
+ }
- export function setup(configuration: Configuration): Promise
- export function track(event: string, properties: any): Promise
- export function identify(user: string, traits: any): Promise
- export function screen(name: string, properties: any): Promise
- export function group(groupId: string, traits: any): Promise
- export function alias(alias: string): Promise
- export function reset(): Promise
- export function flush(): Promise
- export function enable(): Promise
- export function disable(): Promise
- }
+ export function setup(configuration: Configuration): Promise
+ export function track(event: string, properties: any): Promise
+ export function identify(user: string, traits: any): Promise
+ export function screen(name: string, properties: any): Promise
+ export function group(groupId: string, traits: any): Promise
+ export function alias(alias: string): Promise
+ export function reset(): Promise
+ export function flush(): Promise
+ export function enable(): Promise
+ export function disable(): Promise
+ }
}
diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts
index f0f06f002..845be96e7 100644
--- a/packages/core/src/utils.ts
+++ b/packages/core/src/utils.ts
@@ -10,45 +10,40 @@ export const toggle = (
obj[key] = value
}
- return this
- } as T extends O[K]
- ? (this: S) => S
- : (this: S, a: O[K]) => S
+ return this
+ } as T extends O[K] ? (this: S) => S : (this: S, a: O[K]) => S
export interface NativeDelegate {
- ready: boolean
+ ready: boolean
}
export type ErrorHandler = (err: Error) => void
export const nativeWrapper = (
- delegate: T,
- handler: ErrorHandler,
- queue: Array<() => void> = []
+ delegate: T,
+ handler: ErrorHandler,
+ queue: Array<() => void> = []
) => ({
- call: (fn: F) => {
- async function run() {
- try {
- await fn()
- }
- catch(err) {
- return handler(err)
- }
- }
+ call: void>(fn: F) => {
+ async function run() {
+ try {
+ await fn()
+ } catch (err) {
+ return handler(err)
+ }
+ }
- if(delegate.ready) {
- run()
- }
- else {
- queue.push(run)
- }
+ if (delegate.ready) {
+ run()
+ } else {
+ queue.push(run)
+ }
- return delegate
- },
- ready() {
- delegate.ready = true
+ return delegate
+ },
+ ready() {
+ delegate.ready = true
- while(queue.length) {
- queue.shift()!()
- }
- }
+ while (queue.length) {
+ queue.shift()!()
+ }
+ }
})
-
diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json
index fe4e05d1d..04b86021e 100644
--- a/packages/core/tsconfig.json
+++ b/packages/core/tsconfig.json
@@ -1,15 +1,13 @@
{
- "compilerOptions": {
- "strict": true,
- "lib": ["es5", "es2015.promise", "dom"],
- "target": "es5",
+ "compilerOptions": {
+ "strict": true,
+ "lib": ["es5", "es2015.promise", "dom"],
+ "target": "es5",
- "sourceMap": true,
- "declaration": true,
- "outDir": "build",
- "moduleResolution": "node"
- },
- "include": [
- "src/**/*.ts"
- ]
-}
\ No newline at end of file
+ "sourceMap": true,
+ "declaration": true,
+ "outDir": "build",
+ "moduleResolution": "node"
+ },
+ "include": ["src/**/*.ts"]
+}
diff --git a/packages/core/tslint.json b/packages/core/tslint.json
new file mode 100644
index 000000000..9b035163e
--- /dev/null
+++ b/packages/core/tslint.json
@@ -0,0 +1,10 @@
+{
+ "extends": ["tslint:recommended", "tslint-config-prettier"],
+ "rulesDirectory": ["tslint-plugin-prettier"],
+ "rules": {
+ "prettier": true,
+ "no-console": false,
+ "no-namespace": false,
+ "interface-name": false
+ }
+}
diff --git a/packages/integrations/src/gen-integrations.js b/packages/integrations/src/gen-integrations.js
index 8f4580cd5..189f339f0 100644
--- a/packages/integrations/src/gen-integrations.js
+++ b/packages/integrations/src/gen-integrations.js
@@ -7,152 +7,148 @@ const root = path.resolve(__dirname, '..')
const integrations = require('./integration-list')
const safeWrite = async (file, contents) => {
- await fs.mkdirp(path.dirname(file))
- await fs.writeFile(file, contents)
+ await fs.mkdirp(path.dirname(file))
+ await fs.writeFile(file, contents)
}
-function prepareAndroid({template, name, android, nativeModule, slug}) {
- const identifier = slug('.').toLowerCase()
- const {
- maven: {
- repo,
- name: depName = `com.segment.analytics.android.integrations:${slug('-').toLowerCase()}`,
- version = '+@aar'
- } = {},
- factory: {
- class: factoryClass = `${slug()}Integration`,
- import: factoryImport = `com.segment.analytics.android.integrations.${identifier}.${factoryClass}`
- } = {}
- } = android
- const classpath = `com.segment.analytics.reactnative.integration.${identifier}`
- const dependency = `${depName}:${version}`
- const root = 'android/src/main'
+function prepareAndroid({ template, name, android, nativeModule, slug }) {
+ const identifier = slug('.').toLowerCase()
+ const {
+ maven: {
+ repo,
+ name: depName = `com.segment.analytics.android.integrations:${slug(
+ '-'
+ ).toLowerCase()}`,
+ version = '+@aar'
+ } = {},
+ factory: {
+ class: factoryClass = `${slug()}Integration`,
+ import: factoryImport = `com.segment.analytics.android.integrations.${identifier}.${factoryClass}`
+ } = {}
+ } = android
+ const classpath = `com.segment.analytics.reactnative.integration.${identifier}`
+ const dependency = `${depName}:${version}`
+ const root = 'android/src/main'
- return Promise.all([
- template(
- 'android/build.gradle',
- {dependency, maven: repo}
- ),
+ return Promise.all([
+ template('android/build.gradle', { dependency, maven: repo }),
- template(
- `${root}/AndroidManifest.xml`,
- {classpath}
- ),
+ template(`${root}/AndroidManifest.xml`, { classpath }),
- ...['Module', 'Package'].map(name =>
- template(
- `${root}/java/com/segment/analytics/reactnative/integration/${name}.kt`,
- {nativeModule, classpath, factoryClass, factoryImport},
- `${root}/java/${classpath.replace(/\./g, '/')}/Integration${name}.kt`
- )
- )
- ])
+ ...['Module', 'Package'].map(name =>
+ template(
+ `${root}/java/com/segment/analytics/reactnative/integration/${name}.kt`,
+ { nativeModule, classpath, factoryClass, factoryImport },
+ `${root}/java/${classpath.replace(/\./g, '/')}/Integration${name}.kt`
+ )
+ )
+ ])
}
-function prepareiOS({template, name, out, ios, nativeModule, slug}) {
- const xcodeProject = 'ios/RNAnalyticsIntegration.xcodeproj'
- const targetXcodeProject = `ios/${nativeModule}.xcodeproj`
- const pod_name = `RNAnalyticsIntegration-${slug('-')}`
- const {
- pod: {
- name: pod_dependency = `Segment-${slug()}`,
- version: pod_version
- } = {},
- prefix = 'SEG',
- className = `${prefix}${slug()}IntegrationFactory`,
- framework = pod_dependency,
- header = className
- } = ios
+function prepareiOS({ template, name, out, ios, nativeModule, slug }) {
+ const xcodeProject = 'ios/RNAnalyticsIntegration.xcodeproj'
+ const targetXcodeProject = `ios/${nativeModule}.xcodeproj`
+ const pod_name = `RNAnalyticsIntegration-${slug('-')}`
+ const {
+ pod: {
+ name: pod_dependency = `Segment-${slug()}`,
+ version: pod_version
+ } = {},
+ prefix = 'SEG',
+ className = `${prefix}${slug()}IntegrationFactory`,
+ framework = pod_dependency,
+ header = className
+ } = ios
- return Promise.all([
- fs.copy(
- path.resolve(root, 'template', xcodeProject, 'project.xcworkspace'),
- path.resolve(out, targetXcodeProject, 'project.xcworkspace')
- ),
- template(
- `${xcodeProject}/project.pbxproj`,
- {
- project_name: nativeModule
- },
- `${targetXcodeProject}/project.pbxproj`
- ),
- template(
- 'Pod.podspec',
- {
- name,
- pod_name,
- pod_version,
- pod_dependency,
- },
- `${pod_name}.podspec`
- ),
- template(
- 'ios/main.m',
- {
- integration_class_name: nativeModule,
- factory_header: `<${framework}/${header}.h>`,
- factory_class_name: className
- }
- )
- ])
+ return Promise.all([
+ fs.copy(
+ path.resolve(root, 'template', xcodeProject, 'project.xcworkspace'),
+ path.resolve(out, targetXcodeProject, 'project.xcworkspace')
+ ),
+ template(
+ `${xcodeProject}/project.pbxproj`,
+ {
+ project_name: nativeModule
+ },
+ `${targetXcodeProject}/project.pbxproj`
+ ),
+ template(
+ 'Pod.podspec',
+ {
+ name,
+ pod_name,
+ pod_version,
+ pod_dependency
+ },
+ `${pod_name}.podspec`
+ ),
+ template('ios/main.m', {
+ integration_class_name: nativeModule,
+ factory_header: `<${framework}/${header}.h>`,
+ factory_class_name: className
+ })
+ ])
}
-function prepareJs({name, npm, nativeModule, out, template, ios, android}) {
- return Promise.all([
- safeWrite(
- path.resolve(out, 'package.json'),
- JSON.stringify(
- {
- name: npm.package,
- main: 'index.js',
- version: pkg.version,
- license: pkg.license,
- description: `${name} Integration for Segment's React-Native analytics library.`
- },
- null,
- 2
- )
- ),
- template(
- 'index.js',
- {
- nativeModule,
- disable_ios: String(ios.disabled || false),
- disable_android: String(android.disabled || false)
- }
- )
- ])
+function prepareJs({ name, npm, nativeModule, out, template, ios, android }) {
+ return Promise.all([
+ safeWrite(
+ path.resolve(out, 'package.json'),
+ JSON.stringify(
+ {
+ name: npm.package,
+ main: 'index.js',
+ version: pkg.version,
+ license: pkg.license,
+ description: `${name} Integration for Segment's React-Native analytics library.`
+ },
+ null,
+ 2
+ )
+ ),
+ template('index.js', {
+ nativeModule,
+ disable_ios: String(ios.disabled || false),
+ disable_android: String(android.disabled || false)
+ })
+ ])
}
-function genIntegration({name, ios, android, npm, slug}) {
- const out = path.resolve(root, 'build', npm.package)
- const nativeModule = `RNAnalyticsIntegration_${slug('_')}`
- const template = async (template, view, dest = template) => safeWrite(
- path.resolve(out, dest),
- mustache.render(
- await fs.readFile(path.resolve(root, 'template', template), 'utf-8'),
- view
- )
- )
- const ctx = {
- name, out, nativeModule, npm, template, ios, android, slug
- }
+function genIntegration({ name, ios, android, npm, slug }) {
+ const out = path.resolve(root, 'build', npm.package)
+ const nativeModule = `RNAnalyticsIntegration_${slug('_')}`
+ const template = async (template, view, dest = template) =>
+ safeWrite(
+ path.resolve(out, dest),
+ mustache.render(
+ await fs.readFile(path.resolve(root, 'template', template), 'utf-8'),
+ view
+ )
+ )
+ const ctx = {
+ name,
+ out,
+ nativeModule,
+ npm,
+ template,
+ ios,
+ android,
+ slug
+ }
- const tasks = [prepareJs(ctx)]
+ const tasks = [prepareJs(ctx)]
- if(!ios.disabled) {
- tasks.push(prepareiOS(ctx))
- }
- if(!android.disabled) {
- tasks.push(prepareAndroid(ctx))
- }
+ if (!ios.disabled) {
+ tasks.push(prepareiOS(ctx))
+ }
+ if (!android.disabled) {
+ tasks.push(prepareAndroid(ctx))
+ }
- return Promise.all(tasks)
+ return Promise.all(tasks)
}
-Promise
- .all(integrations.map(genIntegration))
- .catch(err => {
- console.error(err)
- process.exit(2)
- })
+Promise.all(integrations.map(genIntegration)).catch(err => {
+ console.error(err)
+ process.exit(2)
+})
diff --git a/packages/integrations/src/gen-readme.js b/packages/integrations/src/gen-readme.js
index 8df0410d2..a8cb349ce 100644
--- a/packages/integrations/src/gen-readme.js
+++ b/packages/integrations/src/gen-readme.js
@@ -8,29 +8,25 @@ const YES = ':white_check_mark:'
const NO = ':x:'
const table = mdtable([
- ['Name', 'iOS', 'Android', 'npm package'],
- ...integrations
- .sort((a, b) => a.name.localeCompare(b.name))
- .map(({name, npm, android, ios}) => [
- `[${name}](https://www.npmjs.com/package/${npm.package})`,
- ios.disabled
- ? NO
- : YES,
- android.disabled
- ? NO
- : YES,
- '`' + npm.package + '`'
- ])
+ ['Name', 'iOS', 'Android', 'npm package'],
+ ...integrations
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map(({ name, npm, android, ios }) => [
+ `[${name}](https://www.npmjs.com/package/${npm.package})`,
+ ios.disabled ? NO : YES,
+ android.disabled ? NO : YES,
+ '`' + npm.package + '`'
+ ])
])
const readme = path.resolve(__dirname, '../../../README.md')
fs.writeFileSync(
- readme,
- fs
- .readFileSync(readme, 'utf-8')
- .replace(
- /(.*)/s,
- `\n${table}\n`
- )
+ readme,
+ fs
+ .readFileSync(readme, 'utf-8')
+ .replace(
+ /(.*)/s,
+ `\n${table}\n`
+ )
)
diff --git a/packages/integrations/src/integration-list.js b/packages/integrations/src/integration-list.js
index 819528455..a5e843d0e 100644
--- a/packages/integrations/src/integration-list.js
+++ b/packages/integrations/src/integration-list.js
@@ -1,29 +1,26 @@
-const {parse} = require('yaml').default
-const {readFileSync} = require('fs')
-const {resolve} = require('path')
+const { parse } = require('yaml').default
+const { readFileSync } = require('fs')
+const { resolve } = require('path')
-module.exports =
- parse(
- readFileSync(resolve(__dirname, '../integrations.yml'), 'utf-8')
- )
- .map(({name, ios = {}, android = {}}) => {
- if(ios.disabled && android.disabled) {
- return null
- }
+module.exports = parse(
+ readFileSync(resolve(__dirname, '../integrations.yml'), 'utf-8')
+)
+ .map(({ name, ios = {}, android = {} }) => {
+ if (ios.disabled && android.disabled) {
+ return null
+ }
- const slug = (sep = '') => name.replace(/-|_| /g, sep)
- const suffix = ios.disabled
- ? '-android'
- : android.disabled
- ? '-ios'
- : ''
-
- return {
- name, slug,
- ios, android,
- npm: {
- package: `@segment/react-native-${slug('-').toLowerCase()}${suffix}`
- }
- }
- })
- .filter(integration => integration !== null)
+ const slug = (sep = '') => name.replace(/-|_| /g, sep)
+ const suffix = ios.disabled ? '-android' : android.disabled ? '-ios' : ''
+
+ return {
+ name,
+ slug,
+ ios,
+ android,
+ npm: {
+ package: `@segment/react-native-${slug('-').toLowerCase()}${suffix}`
+ }
+ }
+ })
+ .filter(integration => integration !== null)
diff --git a/packages/integrations/template/index.js b/packages/integrations/template/index.js
index ebfecb208..54ae27a34 100644
--- a/packages/integrations/template/index.js
+++ b/packages/integrations/template/index.js
@@ -1,11 +1,11 @@
var ReactNative = require('react-native')
var disabled =
- ReactNative.Platform.OS === 'ios'
- ? '{{disable_ios}}' === 'true'
- : ReactNative.Platform.OS === 'android'
- ? '{{disable_android}}' === 'true'
- : true
+ ReactNative.Platform.OS === 'ios'
+ ? '{{disable_ios}}' === 'true'
+ : ReactNative.Platform.OS === 'android'
+ ? '{{disable_android}}' === 'true'
+ : true
module.exports = disabled
- ? {disabled: true}
- : ReactNative.NativeModules['{{{nativeModule}}}'].setup
+ ? { disabled: true }
+ : ReactNative.NativeModules['{{{nativeModule}}}'].setup
diff --git a/packages/test-app/App.js b/packages/test-app/App.js
index d7783080f..b222c61b9 100644
--- a/packages/test-app/App.js
+++ b/packages/test-app/App.js
@@ -1,89 +1,69 @@
-import React, {Component} from 'react'
-import {StyleSheet, Text, View, Image, TouchableOpacity} from 'react-native'
+import React, { Component } from 'react'
+import { StyleSheet, Text, View, Image, TouchableOpacity } from 'react-native'
import analytics from '@segment/react-native'
-const Button = ({title, onPress}) => (
-
-
- {title}
-
-
+const Button = ({ title, onPress }) => (
+
+ {title}
+
)
-const screenHome = () =>
- analytics.screen('Home')
+const screenHome = () => analytics.screen('Home')
-const flush = () =>
- analytics.flush()
+const flush = () => analytics.flush()
-const pizzaEaten = () =>
- analytics.track('Pizza Eaten')
+const pizzaEaten = () => analytics.track('Pizza Eaten')
const trackOrder = () =>
- analytics
- .track('Order Completed')
- .track('Order Cancelled', {
- order_id: 323
- })
- .identify('userIdOnly')
- .identify('userId', {
- age: 32
- })
- .alias('newlyAliasedId')
- .screen('User Login Screen', {
- method: 'google'
- })
+ analytics
+ .track('Order Completed')
+ .track('Order Cancelled', {
+ order_id: 323
+ })
+ .identify('userIdOnly')
+ .identify('userId', {
+ age: 32
+ })
+ .alias('newlyAliasedId')
+ .screen('User Login Screen', {
+ method: 'google'
+ })
export default class App extends Component {
- render() {
- return (
-
-
-
-
-
-
-
- );
- }
+ render() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
}
const styles = StyleSheet.create({
- logo: {
- height: 150,
- margin: 50,
- width: 240,
- height: 160
- },
- button: {
- margin: 20
- },
- text: {
- color: '#FBFAF9'
- },
- container: {
- flex: 1,
- justifyContent: 'flex-start',
- alignItems: 'center',
- backgroundColor: '#32A75D',
- }
+ logo: {
+ height: 150,
+ margin: 50,
+ width: 240,
+ height: 160
+ },
+ button: {
+ margin: 20
+ },
+ text: {
+ color: '#FBFAF9'
+ },
+ container: {
+ flex: 1,
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ backgroundColor: '#32A75D'
+ }
})
diff --git a/yarn.lock b/yarn.lock
index 969d32d6f..328eee412 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -454,7 +454,7 @@ aws4@^1.6.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
-babel-code-frame@^6.26.0:
+babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
dependencies:
@@ -695,7 +695,7 @@ buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
-builtin-modules@^1.0.0:
+builtin-modules@^1.0.0, builtin-modules@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@@ -784,7 +784,7 @@ chalk@2.3.1:
escape-string-regexp "^1.0.5"
supports-color "^5.2.0"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
@@ -904,7 +904,7 @@ combined-stream@1.0.6, combined-stream@~1.0.5:
dependencies:
delayed-stream "~1.0.0"
-commander@^2.14.1, commander@^2.9.0:
+commander@^2.12.1, commander@^2.14.1, commander@^2.9.0:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
@@ -1301,6 +1301,13 @@ escodegen@^1.9.1:
optionalDependencies:
source-map "~0.6.1"
+eslint-plugin-prettier@^2.2.0:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.2.tgz#71998c60aedfa2141f7bfcbf9d1c459bf98b4fad"
+ dependencies:
+ fast-diff "^1.1.1"
+ jest-docblock "^21.0.0"
+
esprima@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
@@ -1488,6 +1495,10 @@ fast-deep-equal@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
+fast-diff@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
+
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@@ -2409,6 +2420,10 @@ jest-diff@^23.2.0:
jest-get-type "^22.1.0"
pretty-format "^23.2.0"
+jest-docblock@^21.0.0:
+ version "21.2.0"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414"
+
jest-docblock@^23.2.0:
version "23.2.0"
resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7"
@@ -3676,6 +3691,10 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+prettier@^1.14.2:
+ version "1.14.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.14.2.tgz#0ac1c6e1a90baa22a62925f41963c841983282f9"
+
pretty-format@^23.2.0:
version "23.2.0"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.2.0.tgz#3b0aaa63c018a53583373c1cb3a5d96cc5e83017"
@@ -3975,7 +3994,7 @@ resolve@1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
-resolve@^1.1.6:
+resolve@^1.1.6, resolve@^1.3.2:
version "1.8.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26"
dependencies:
@@ -4548,10 +4567,44 @@ ts-jest@^23.1.3:
fs-extra "6.0.1"
lodash "^4.17.10"
-tslib@^1.9.0, tslib@^1.9.3:
+tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
+tslint-config-prettier@^1.14.0:
+ version "1.14.0"
+ resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.14.0.tgz#860b36634e53f4c70c64c51ff3ef7fd9bbab7676"
+
+tslint-plugin-prettier@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/tslint-plugin-prettier/-/tslint-plugin-prettier-1.3.0.tgz#7eb65d19ea786a859501a42491b78c5de2031a3f"
+ dependencies:
+ eslint-plugin-prettier "^2.2.0"
+ tslib "^1.7.1"
+
+tslint@^5.11.0:
+ version "5.11.0"
+ resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed"
+ dependencies:
+ babel-code-frame "^6.22.0"
+ builtin-modules "^1.1.1"
+ chalk "^2.3.0"
+ commander "^2.12.1"
+ diff "^3.2.0"
+ glob "^7.1.1"
+ js-yaml "^3.7.0"
+ minimatch "^3.0.4"
+ resolve "^1.3.2"
+ semver "^5.3.0"
+ tslib "^1.8.0"
+ tsutils "^2.27.2"
+
+tsutils@^2.27.2:
+ version "2.29.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
+ dependencies:
+ tslib "^1.8.1"
+
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"