diff --git a/README.md b/README.md
index 332f69c..7aee5b1 100644
--- a/README.md
+++ b/README.md
@@ -111,6 +111,7 @@ See [schema.json](schema.json) for a JSON Schema of the output.
| Pendo | ✅ | ❌ | ❌ | ❌ |
| Heap | ✅ | ❌ | ❌ | ❌ |
| Snowplow | ✅ | ✅ | ✅ | ✅ |
+| Datadog RUM | ✅ | ❌ | ❌ | ❌ |
| Custom Function | ✅ | ✅ | ✅ | ✅ |
✳️ Rudderstack's SDKs often use the same format as Segment, so Rudderstack events may be detected as Segment events.
@@ -375,6 +376,27 @@ See [schema.json](schema.json) for a JSON Schema of the output.
+
+ Datadog RUM
+
+ **JavaScript/TypeScript**
+ ```js
+ datadogRum.addAction('', {
+ '': ''
+ });
+
+ // Or via window
+ window.DD_RUM.addAction('', {
+ '': ''
+ });
+
+ // Or via global DD_RUM
+ DD_RUM.addAction('', {
+ '': ''
+ });
+ ```
+
+
Snowplow (Structured Events)
diff --git a/schema.json b/schema.json
index 5dc5504..11067a4 100644
--- a/schema.json
+++ b/schema.json
@@ -67,6 +67,7 @@
"pendo",
"heap",
"snowplow",
+ "datadog",
"custom",
"unknown"
],
diff --git a/src/analyze/javascript/constants.js b/src/analyze/javascript/constants.js
index b04f95a..102673b 100644
--- a/src/analyze/javascript/constants.js
+++ b/src/analyze/javascript/constants.js
@@ -75,6 +75,12 @@ const ANALYTICS_PROVIDERS = {
name: 'googleanalytics',
functionName: 'gtag',
type: 'function'
+ },
+ DATADOG_RUM: {
+ name: 'datadog',
+ objectNames: ['datadogRum', 'DD_RUM'],
+ methodName: 'addAction',
+ type: 'member'
}
};
diff --git a/src/analyze/javascript/detectors/analytics-source.js b/src/analyze/javascript/detectors/analytics-source.js
index 26ef558..66bf85d 100644
--- a/src/analyze/javascript/detectors/analytics-source.js
+++ b/src/analyze/javascript/detectors/analytics-source.js
@@ -131,8 +131,17 @@ function detectMemberBasedProvider(node) {
return 'unknown';
}
- const objectName = node.callee.object.name;
const methodName = node.callee.property.name;
+ let objectName = node.callee.object.name;
+
+ // Handle nested member expressions like window.DD_RUM.addAction
+ if (!objectName && node.callee.object.type === NODE_TYPES.MEMBER_EXPRESSION) {
+ // For window.DD_RUM.addAction, we want to check if it matches DD_RUM.addAction pattern
+ const nestedObjectName = node.callee.object.property.name;
+ if (nestedObjectName) {
+ objectName = nestedObjectName;
+ }
+ }
if (!objectName || !methodName) {
return 'unknown';
diff --git a/src/analyze/typescript/constants.js b/src/analyze/typescript/constants.js
index 66a0706..52d7fa9 100644
--- a/src/analyze/typescript/constants.js
+++ b/src/analyze/typescript/constants.js
@@ -75,6 +75,12 @@ const ANALYTICS_PROVIDERS = {
name: 'googleanalytics',
functionName: 'gtag',
type: 'function'
+ },
+ DATADOG_RUM: {
+ name: 'datadog',
+ objectNames: ['datadogRum', 'DD_RUM'],
+ methodName: 'addAction',
+ type: 'member'
}
};
diff --git a/src/analyze/typescript/detectors/analytics-source.js b/src/analyze/typescript/detectors/analytics-source.js
index 1624421..064da8e 100644
--- a/src/analyze/typescript/detectors/analytics-source.js
+++ b/src/analyze/typescript/detectors/analytics-source.js
@@ -87,8 +87,17 @@ function detectMemberBasedProvider(node) {
return 'unknown';
}
- const objectName = node.expression.expression?.escapedText;
const methodName = node.expression.name?.escapedText;
+ let objectName = node.expression.expression?.escapedText;
+
+ // Handle nested member expressions like window.DD_RUM.addAction
+ if (!objectName && ts.isPropertyAccessExpression(node.expression.expression)) {
+ // For window.DD_RUM.addAction, we want to check if it matches DD_RUM.addAction pattern
+ const nestedObjectName = node.expression.expression.name?.escapedText;
+ if (nestedObjectName) {
+ objectName = nestedObjectName;
+ }
+ }
if (!objectName || !methodName) {
return 'unknown';
diff --git a/tests/analyzeJavaScript.test.js b/tests/analyzeJavaScript.test.js
index 7da03af..2b266b1 100644
--- a/tests/analyzeJavaScript.test.js
+++ b/tests/analyzeJavaScript.test.js
@@ -16,7 +16,7 @@ test.describe('analyzeJsFile', () => {
// Sort events by line number for consistent ordering
events.sort((a, b) => a.line - b.line);
- assert.strictEqual(events.length, 12);
+ assert.strictEqual(events.length, 15);
// Test Google Analytics event
const gaEvent = events.find(e => e.eventName === 'purchase' && e.source === 'googleanalytics');
@@ -176,7 +176,7 @@ test.describe('analyzeJsFile', () => {
assert.ok(snowplowEvent);
assert.strictEqual(snowplowEvent.source, 'snowplow');
assert.strictEqual(snowplowEvent.functionName, 'trackSnowplow');
- assert.strictEqual(snowplowEvent.line, 138);
+ assert.strictEqual(snowplowEvent.line, 157);
assert.deepStrictEqual(snowplowEvent.properties, {
category: { type: 'string' },
label: { type: 'string' },
@@ -189,7 +189,7 @@ test.describe('analyzeJsFile', () => {
assert.ok(customEvent);
assert.strictEqual(customEvent.source, 'custom');
assert.strictEqual(customEvent.functionName, 'global');
- assert.strictEqual(customEvent.line, 152);
+ assert.strictEqual(customEvent.line, 171);
assert.deepStrictEqual(customEvent.properties, {
userId: { type: 'string' },
order_id: { type: 'string' },
@@ -232,7 +232,7 @@ test.describe('analyzeJsFile', () => {
const events = analyzeJsFile(testFilePath, null);
// Should find all events except the custom one
- assert.strictEqual(events.length, 11);
+ assert.strictEqual(events.length, 14);
assert.strictEqual(events.find(e => e.source === 'custom'), undefined);
});
diff --git a/tests/analyzeTypeScript.test.js b/tests/analyzeTypeScript.test.js
index 8d6d968..693a4a2 100644
--- a/tests/analyzeTypeScript.test.js
+++ b/tests/analyzeTypeScript.test.js
@@ -37,14 +37,14 @@ test.describe('analyzeTsFile', () => {
// Sort events by line number for consistent ordering
events.sort((a, b) => a.line - b.line);
- assert.strictEqual(events.length, 20);
+ assert.strictEqual(events.length, 23);
// Test Google Analytics event
const gaEvent = events.find(e => e.eventName === 'order_completed' && e.source === 'googleanalytics');
assert.ok(gaEvent);
assert.strictEqual(gaEvent.source, 'googleanalytics');
assert.strictEqual(gaEvent.functionName, 'trackOrderCompletedGA');
- assert.strictEqual(gaEvent.line, 105);
+ assert.strictEqual(gaEvent.line, 119);
assert.deepStrictEqual(gaEvent.properties, {
order_id: { type: 'string' },
products: {
@@ -76,7 +76,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(segmentEvent);
assert.strictEqual(segmentEvent.source, 'segment');
assert.strictEqual(segmentEvent.functionName, 'checkout');
- assert.strictEqual(segmentEvent.line, 121);
+ assert.strictEqual(segmentEvent.line, 135);
assert.deepStrictEqual(segmentEvent.properties, {
stage: { type: 'string' },
method: { type: 'string' },
@@ -88,7 +88,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(mixpanelEvent);
assert.strictEqual(mixpanelEvent.source, 'mixpanel');
assert.strictEqual(mixpanelEvent.functionName, 'confirmPurchaseMixpanel');
- assert.strictEqual(mixpanelEvent.line, 130);
+ assert.strictEqual(mixpanelEvent.line, 144);
assert.deepStrictEqual(mixpanelEvent.properties, {
order_id: { type: 'string' },
items: {
@@ -111,7 +111,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(amplitudeEvent);
assert.strictEqual(amplitudeEvent.source, 'amplitude');
assert.strictEqual(amplitudeEvent.functionName, 'checkout');
- assert.strictEqual(amplitudeEvent.line, 135);
+ assert.strictEqual(amplitudeEvent.line, 149);
assert.deepStrictEqual(amplitudeEvent.properties, {
order_id: { type: 'string' },
items: {
@@ -143,7 +143,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(rudderstackEvent);
assert.strictEqual(rudderstackEvent.source, 'rudderstack');
assert.strictEqual(rudderstackEvent.functionName, 'checkout');
- assert.strictEqual(rudderstackEvent.line, 150);
+ assert.strictEqual(rudderstackEvent.line, 164);
assert.deepStrictEqual(rudderstackEvent.properties, {
order_id: { type: 'string' },
items: {
@@ -174,7 +174,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(mparticleEvent);
assert.strictEqual(mparticleEvent.source, 'mparticle');
assert.strictEqual(mparticleEvent.functionName, 'checkout2');
- assert.strictEqual(mparticleEvent.line, 176);
+ assert.strictEqual(mparticleEvent.line, 190);
assert.deepStrictEqual(mparticleEvent.properties, {
order_id: { type: 'string' },
items: {
@@ -205,7 +205,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(posthogEvent);
assert.strictEqual(posthogEvent.source, 'posthog');
assert.strictEqual(posthogEvent.functionName, 'checkout2');
- assert.strictEqual(posthogEvent.line, 195);
+ assert.strictEqual(posthogEvent.line, 209);
assert.deepStrictEqual(posthogEvent.properties, {
order_id: { type: 'string' },
retry: { type: 'number' },
@@ -237,7 +237,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(pendoEvent);
assert.strictEqual(pendoEvent.source, 'pendo');
assert.strictEqual(pendoEvent.functionName, 'checkout3');
- assert.strictEqual(pendoEvent.line, 216);
+ assert.strictEqual(pendoEvent.line, 230);
assert.deepStrictEqual(pendoEvent.properties, {
order_id: { type: 'string' },
products: {
@@ -268,7 +268,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(heapEvent);
assert.strictEqual(heapEvent.source, 'heap');
assert.strictEqual(heapEvent.functionName, 'checkout3');
- assert.strictEqual(heapEvent.line, 230);
+ assert.strictEqual(heapEvent.line, 244);
assert.deepStrictEqual(heapEvent.properties, {
user_id: { type: 'string' },
email: { type: 'string' },
@@ -284,7 +284,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(snowplowEvent1);
assert.strictEqual(snowplowEvent1.source, 'snowplow');
assert.strictEqual(snowplowEvent1.functionName, 'trackSnowplow');
- assert.strictEqual(snowplowEvent1.line, 247);
+ assert.strictEqual(snowplowEvent1.line, 282);
assert.deepStrictEqual(snowplowEvent1.properties, {
category: { type: 'string' },
label: { type: 'string' },
@@ -296,14 +296,14 @@ test.describe('analyzeTsFile', () => {
assert.ok(snowplowEvent2);
assert.strictEqual(snowplowEvent2.source, 'snowplow');
assert.strictEqual(snowplowEvent2.functionName, 'trackSnowplow2');
- assert.strictEqual(snowplowEvent2.line, 251);
+ assert.strictEqual(snowplowEvent2.line, 286);
// Test custom function event
const customEvent = events.find(e => e.eventName === 'custom_event_v2');
assert.ok(customEvent);
assert.strictEqual(customEvent.source, 'custom');
assert.strictEqual(customEvent.functionName, 'global');
- assert.strictEqual(customEvent.line, 280);
+ assert.strictEqual(customEvent.line, 315);
assert.deepStrictEqual(customEvent.properties, {
userId: { type: 'string' },
order_id: { type: 'string' },
@@ -326,7 +326,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(constantEvent);
assert.strictEqual(constantEvent.source, 'custom');
assert.strictEqual(constantEvent.functionName, 'global');
- assert.strictEqual(constantEvent.line, 291);
+ assert.strictEqual(constantEvent.line, 326);
assert.deepStrictEqual(constantEvent.properties, {
userId: { type: 'string' },
orderId: { type: 'string' },
@@ -342,7 +342,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(importedConstantEvent);
assert.strictEqual(importedConstantEvent.source, 'segment');
assert.strictEqual(importedConstantEvent.functionName, 'global');
- assert.strictEqual(importedConstantEvent.line, 293);
+ assert.strictEqual(importedConstantEvent.line, 328);
assert.deepStrictEqual(importedConstantEvent.properties, {
orderId: { type: 'string' },
total: { type: 'number' },
@@ -357,7 +357,7 @@ test.describe('analyzeTsFile', () => {
assert.ok(frozenConstantEvent);
assert.strictEqual(frozenConstantEvent.source, 'mixpanel');
assert.strictEqual(frozenConstantEvent.functionName, 'global');
- assert.strictEqual(frozenConstantEvent.line, 292);
+ assert.strictEqual(frozenConstantEvent.line, 327);
assert.deepStrictEqual(frozenConstantEvent.properties, {
orderId: { type: 'string' },
total: { type: 'number' },
@@ -405,7 +405,7 @@ test.describe('analyzeTsFile', () => {
const events = analyzeTsFile(testFilePath, program, null);
// Should find all events except the custom ones
- assert.strictEqual(events.length, 13);
+ assert.strictEqual(events.length, 16);
assert.strictEqual(events.find(e => e.source === 'custom'), undefined);
});
diff --git a/tests/fixtures/javascript/main.js b/tests/fixtures/javascript/main.js
index 8f0ba3c..6a4b06a 100644
--- a/tests/fixtures/javascript/main.js
+++ b/tests/fixtures/javascript/main.js
@@ -126,6 +126,25 @@ export const checkout3 = function() {
email: 'user123@example.com',
name: 'John Doe'
});
+
+ // datadog tracking examples - all three patterns
+ datadogRum.addAction('checkout', {
+ total: 500,
+ order_id: 'ABC123',
+ currency: 'USD'
+ });
+
+ window.DD_RUM.addAction('user_login', {
+ user_id: 'user123',
+ method: 'email',
+ success: true
+ });
+
+ DD_RUM.addAction('page_view', {
+ page: '/checkout',
+ section: 'payment',
+ user_type: 'premium'
+ });
}
class MyClass {
diff --git a/tests/fixtures/javascript/tracking-schema-javascript.yaml b/tests/fixtures/javascript/tracking-schema-javascript.yaml
index 5f79c77..c050f0f 100644
--- a/tests/fixtures/javascript/tracking-schema-javascript.yaml
+++ b/tests/fixtures/javascript/tracking-schema-javascript.yaml
@@ -55,13 +55,17 @@ events:
line: 44
function: checkout
destination: amplitude
+ - path: main.js
+ line: 131
+ function: checkout3
+ destination: datadog
properties:
order_id:
- type: any
+ type: string
products:
type: any
total:
- type: any
+ type: number
address:
type: object
properties:
@@ -69,6 +73,8 @@ events:
type: string
state:
type: string
+ currency:
+ type: string
Order Completed:
implementations:
- path: main.js
@@ -169,7 +175,7 @@ events:
someevent:
implementations:
- path: main.js
- line: 138
+ line: 157
function: trackSnowplow
destination: snowplow
properties:
@@ -184,7 +190,7 @@ events:
customEvent:
implementations:
- path: main.js
- line: 152
+ line: 171
function: global
destination: custom
properties:
@@ -201,7 +207,7 @@ events:
custom_event0:
implementations:
- path: main.js
- line: 162
+ line: 181
function: global
destination: custom
properties:
@@ -210,7 +216,7 @@ events:
custom_event1:
implementations:
- path: main.js
- line: 163
+ line: 182
function: global
destination: custom
properties:
@@ -219,7 +225,7 @@ events:
custom_event2:
implementations:
- path: main.js
- line: 164
+ line: 183
function: global
destination: custom
properties:
@@ -230,7 +236,7 @@ events:
custom_event3:
implementations:
- path: main.js
- line: 165
+ line: 184
function: global
destination: custom
properties:
@@ -241,7 +247,7 @@ events:
custom_event4:
implementations:
- path: main.js
- line: 166
+ line: 185
function: global
destination: custom
properties:
@@ -259,7 +265,7 @@ events:
custom_module_event:
implementations:
- path: main.js
- line: 178
+ line: 197
function: global
destination: custom
properties:
@@ -269,10 +275,23 @@ events:
type: string
userId:
type: string
+ page_view:
+ implementations:
+ - path: main.js
+ line: 143
+ function: checkout3
+ destination: datadog
+ properties:
+ page:
+ type: string
+ section:
+ type: string
+ user_type:
+ type: string
ecommerce_purchase_frozen:
implementations:
- path: main.js
- line: 190
+ line: 209
function: global
destination: mixpanel
properties:
@@ -284,3 +303,16 @@ events:
type: array
items:
type: string
+ user_login:
+ implementations:
+ - path: main.js
+ line: 137
+ function: checkout3
+ destination: datadog
+ properties:
+ user_id:
+ type: string
+ method:
+ type: string
+ success:
+ type: boolean
diff --git a/tests/fixtures/tracking-schema-all.yaml b/tests/fixtures/tracking-schema-all.yaml
index 9be81fc..b156ec1 100644
--- a/tests/fixtures/tracking-schema-all.yaml
+++ b/tests/fixtures/tracking-schema-all.yaml
@@ -168,7 +168,7 @@ events:
function: main
destination: custom
- path: javascript/main.js
- line: 162
+ line: 181
function: global
destination: custom
- path: python/main.py
@@ -180,7 +180,7 @@ events:
function: global
destination: custom
- path: typescript/main.ts
- line: 306
+ line: 341
function: global
destination: custom
properties:
@@ -193,7 +193,7 @@ events:
function: main
destination: custom
- path: javascript/main.js
- line: 163
+ line: 182
function: global
destination: custom
- path: python/main.py
@@ -205,7 +205,7 @@ events:
function: global
destination: custom
- path: typescript/main.ts
- line: 307
+ line: 342
function: global
destination: custom
properties:
@@ -218,7 +218,7 @@ events:
function: main
destination: custom
- path: javascript/main.js
- line: 164
+ line: 183
function: global
destination: custom
- path: python/main.py
@@ -230,7 +230,7 @@ events:
function: global
destination: custom
- path: typescript/main.ts
- line: 308
+ line: 343
function: global
destination: custom
properties:
@@ -245,7 +245,7 @@ events:
function: main
destination: custom
- path: javascript/main.js
- line: 165
+ line: 184
function: global
destination: custom
- path: python/main.py
@@ -257,7 +257,7 @@ events:
function: global
destination: custom
- path: typescript/main.ts
- line: 309
+ line: 344
function: global
destination: custom
properties:
@@ -272,7 +272,7 @@ events:
function: main
destination: custom
- path: javascript/main.js
- line: 166
+ line: 185
function: global
destination: custom
- path: python/main.py
@@ -284,7 +284,7 @@ events:
function: global
destination: custom
- path: typescript/main.ts
- line: 310
+ line: 345
function: global
destination: custom
properties:
@@ -349,13 +349,17 @@ events:
line: 44
function: checkout
destination: amplitude
+ - path: javascript/main.js
+ line: 131
+ function: checkout3
+ destination: datadog
properties:
order_id:
- type: any
+ type: string
products:
type: any
total:
- type: any
+ type: number
address:
type: object
properties:
@@ -363,6 +367,8 @@ events:
type: string
state:
type: string
+ currency:
+ type: string
Order Completed:
implementations:
- path: javascript/main.js
@@ -463,7 +469,7 @@ events:
someevent:
implementations:
- path: javascript/main.js
- line: 138
+ line: 157
function: trackSnowplow
destination: snowplow
properties:
@@ -478,7 +484,7 @@ events:
customEvent:
implementations:
- path: javascript/main.js
- line: 152
+ line: 171
function: global
destination: custom
properties:
@@ -495,7 +501,7 @@ events:
custom_module_event:
implementations:
- path: javascript/main.js
- line: 178
+ line: 197
function: global
destination: custom
- path: python/main.py
@@ -503,7 +509,7 @@ events:
function: main
destination: custom
- path: typescript/main.ts
- line: 322
+ line: 357
function: global
destination: custom
properties:
@@ -513,14 +519,27 @@ events:
type: string
userId:
type: string
+ page_view:
+ implementations:
+ - path: javascript/main.js
+ line: 143
+ function: checkout3
+ destination: datadog
+ properties:
+ page:
+ type: string
+ section:
+ type: string
+ user_type:
+ type: string
ecommerce_purchase_frozen:
implementations:
- path: javascript/main.js
- line: 190
+ line: 209
function: global
destination: mixpanel
- path: typescript/main.ts
- line: 292
+ line: 327
function: global
destination: mixpanel
properties:
@@ -532,6 +551,31 @@ events:
type: array
items:
type: string
+ user_login:
+ implementations:
+ - path: javascript/main.js
+ line: 137
+ function: checkout3
+ destination: datadog
+ - path: typescript/main.ts
+ line: 244
+ function: checkout3
+ destination: heap
+ properties:
+ user_id:
+ type: string
+ method:
+ type: string
+ success:
+ type: boolean
+ email:
+ type: string
+ name:
+ type: string
+ roles:
+ type: array
+ items:
+ type: string
User Signed Up:
implementations:
- path: python/main.py
@@ -640,7 +684,7 @@ events:
order_completed:
implementations:
- path: typescript/main.ts
- line: 105
+ line: 119
function: trackOrderCompletedGA
destination: googleanalytics
properties:
@@ -675,7 +719,7 @@ events:
user_checkout:
implementations:
- path: typescript/main.ts
- line: 121
+ line: 135
function: checkout
destination: segment
properties:
@@ -688,7 +732,7 @@ events:
purchase_confirmed:
implementations:
- path: typescript/main.ts
- line: 130
+ line: 144
function: confirmPurchaseMixpanel
destination: mixpanel
properties:
@@ -712,7 +756,7 @@ events:
checkout_initiated:
implementations:
- path: typescript/main.ts
- line: 135
+ line: 149
function: checkout
destination: amplitude
properties:
@@ -747,7 +791,7 @@ events:
order_finalized:
implementations:
- path: typescript/main.ts
- line: 150
+ line: 164
function: checkout
destination: rudderstack
properties:
@@ -780,7 +824,7 @@ events:
BuyNow:
implementations:
- path: typescript/main.ts
- line: 176
+ line: 190
function: checkout2
destination: mparticle
properties:
@@ -813,7 +857,7 @@ events:
user_action:
implementations:
- path: typescript/main.ts
- line: 195
+ line: 209
function: checkout2
destination: posthog
properties:
@@ -848,7 +892,7 @@ events:
customer_checkout:
implementations:
- path: typescript/main.ts
- line: 216
+ line: 230
function: checkout3
destination: pendo
properties:
@@ -878,27 +922,10 @@ events:
type: string
postalCode:
type: string
- user_login:
- implementations:
- - path: typescript/main.ts
- line: 230
- function: checkout3
- destination: heap
- properties:
- user_id:
- type: string
- email:
- type: string
- name:
- type: string
- roles:
- type: array
- items:
- type: string
item_view:
implementations:
- path: typescript/main.ts
- line: 247
+ line: 282
function: trackSnowplow
destination: snowplow
properties:
@@ -913,7 +940,7 @@ events:
button_click:
implementations:
- path: typescript/main.ts
- line: 251
+ line: 286
function: trackSnowplow2
destination: snowplow
properties:
@@ -928,7 +955,7 @@ events:
custom_event_v2:
implementations:
- path: typescript/main.ts
- line: 280
+ line: 315
function: global
destination: custom
properties:
@@ -952,7 +979,7 @@ events:
ecommerce_purchase:
implementations:
- path: typescript/main.ts
- line: 291
+ line: 326
function: global
destination: custom
properties:
@@ -969,7 +996,7 @@ events:
ecommerce_purchase_v2:
implementations:
- path: typescript/main.ts
- line: 293
+ line: 328
function: global
destination: segment
properties:
@@ -1118,11 +1145,11 @@ events:
FailedPayment:
implementations:
- path: typescript/main.ts
- line: 361
+ line: 396
function: global
destination: custom
- path: typescript/main.ts
- line: 417
+ line: 452
function: trackFailedPayment
destination: custom
properties:
@@ -1133,11 +1160,11 @@ events:
InitiatedPayment:
implementations:
- path: typescript/main.ts
- line: 349
+ line: 384
function: global
destination: custom
- path: typescript/main.ts
- line: 422
+ line: 457
function: trackInitiatedPayment
destination: custom
properties:
@@ -1148,7 +1175,7 @@ events:
ViewedAttorneyAgreement:
implementations:
- path: typescript/main.ts
- line: 375
+ line: 410
function: handleView
destination: custom
properties: {}
@@ -1161,6 +1188,49 @@ events:
properties:
foo:
type: string
+ checkout_completed:
+ implementations:
+ - path: typescript/main.ts
+ line: 247
+ function: checkout3
+ destination: datadog
+ properties:
+ total:
+ type: number
+ orderId:
+ type: string
+ currency:
+ type: string
+ items:
+ type: number
+ user_registration:
+ implementations:
+ - path: typescript/main.ts
+ line: 254
+ function: checkout3
+ destination: datadog
+ properties:
+ user_id:
+ type: string
+ method:
+ type: string
+ success:
+ type: boolean
+ referrer:
+ type: string
+ error_occurred:
+ implementations:
+ - path: typescript/main.ts
+ line: 261
+ function: checkout3
+ destination: datadog
+ properties:
+ error_type:
+ type: string
+ field:
+ type: string
+ page:
+ type: string
UnlessEvent:
implementations:
- path: ruby/node_types.rb
diff --git a/tests/fixtures/typescript/main.ts b/tests/fixtures/typescript/main.ts
index b3e9e6b..506e599 100644
--- a/tests/fixtures/typescript/main.ts
+++ b/tests/fixtures/typescript/main.ts
@@ -49,6 +49,20 @@ declare const heap: {
track(eventName: string, properties: Record): void;
};
+declare const datadogRum: {
+ addAction(eventName: string, properties: Record): void;
+};
+
+declare const DD_RUM: {
+ addAction(eventName: string, properties: Record): void;
+};
+
+declare const window: {
+ DD_RUM: {
+ addAction(eventName: string, properties: Record): void;
+ };
+};
+
declare const tracker: {
track(event: unknown): void;
};
@@ -228,6 +242,27 @@ export function checkout3(): void {
roles: ['admin', 'editor'],
};
heap.track('user_login', heapData);
+
+ // Datadog tracking examples - all three patterns
+ datadogRum.addAction('checkout_completed', {
+ total: 500,
+ orderId: 'ABC123',
+ currency: 'USD',
+ items: itemsList.length
+ });
+
+ window.DD_RUM.addAction('user_registration', {
+ user_id: 'user123',
+ method: 'email',
+ success: true,
+ referrer: 'organic'
+ });
+
+ DD_RUM.addAction('error_occurred', {
+ error_type: 'validation',
+ field: 'email',
+ page: '/checkout'
+ });
}
// -----------------------------------------------------------------------------
diff --git a/tests/fixtures/typescript/tracking-schema-typescript.yaml b/tests/fixtures/typescript/tracking-schema-typescript.yaml
index 2857a52..f18f826 100644
--- a/tests/fixtures/typescript/tracking-schema-typescript.yaml
+++ b/tests/fixtures/typescript/tracking-schema-typescript.yaml
@@ -8,7 +8,7 @@ events:
order_completed:
implementations:
- path: main.ts
- line: 105
+ line: 119
function: trackOrderCompletedGA
destination: googleanalytics
properties:
@@ -43,7 +43,7 @@ events:
user_checkout:
implementations:
- path: main.ts
- line: 121
+ line: 135
function: checkout
destination: segment
properties:
@@ -56,7 +56,7 @@ events:
purchase_confirmed:
implementations:
- path: main.ts
- line: 130
+ line: 144
function: confirmPurchaseMixpanel
destination: mixpanel
properties:
@@ -80,7 +80,7 @@ events:
checkout_initiated:
implementations:
- path: main.ts
- line: 135
+ line: 149
function: checkout
destination: amplitude
properties:
@@ -115,7 +115,7 @@ events:
order_finalized:
implementations:
- path: main.ts
- line: 150
+ line: 164
function: checkout
destination: rudderstack
properties:
@@ -148,7 +148,7 @@ events:
BuyNow:
implementations:
- path: main.ts
- line: 176
+ line: 190
function: checkout2
destination: mparticle
properties:
@@ -181,7 +181,7 @@ events:
user_action:
implementations:
- path: main.ts
- line: 195
+ line: 209
function: checkout2
destination: posthog
properties:
@@ -216,7 +216,7 @@ events:
customer_checkout:
implementations:
- path: main.ts
- line: 216
+ line: 230
function: checkout3
destination: pendo
properties:
@@ -249,7 +249,7 @@ events:
user_login:
implementations:
- path: main.ts
- line: 230
+ line: 244
function: checkout3
destination: heap
properties:
@@ -266,7 +266,7 @@ events:
item_view:
implementations:
- path: main.ts
- line: 247
+ line: 282
function: trackSnowplow
destination: snowplow
properties:
@@ -281,7 +281,7 @@ events:
button_click:
implementations:
- path: main.ts
- line: 251
+ line: 286
function: trackSnowplow2
destination: snowplow
properties:
@@ -296,7 +296,7 @@ events:
custom_event_v2:
implementations:
- path: main.ts
- line: 280
+ line: 315
function: global
destination: custom
properties:
@@ -320,7 +320,7 @@ events:
ecommerce_purchase:
implementations:
- path: main.ts
- line: 291
+ line: 326
function: global
destination: custom
properties:
@@ -337,7 +337,7 @@ events:
ecommerce_purchase_frozen:
implementations:
- path: main.ts
- line: 292
+ line: 327
function: global
destination: mixpanel
properties:
@@ -352,7 +352,7 @@ events:
ecommerce_purchase_v2:
implementations:
- path: main.ts
- line: 293
+ line: 328
function: global
destination: segment
properties:
@@ -367,7 +367,7 @@ events:
custom_event0:
implementations:
- path: main.ts
- line: 306
+ line: 341
function: global
destination: custom
properties:
@@ -376,7 +376,7 @@ events:
custom_event1:
implementations:
- path: main.ts
- line: 307
+ line: 342
function: global
destination: custom
properties:
@@ -385,7 +385,7 @@ events:
custom_event2:
implementations:
- path: main.ts
- line: 308
+ line: 343
function: global
destination: custom
properties:
@@ -396,7 +396,7 @@ events:
custom_event3:
implementations:
- path: main.ts
- line: 309
+ line: 344
function: global
destination: custom
properties:
@@ -407,7 +407,7 @@ events:
custom_event4:
implementations:
- path: main.ts
- line: 310
+ line: 345
function: global
destination: custom
properties:
@@ -425,7 +425,7 @@ events:
custom_module_event:
implementations:
- path: main.ts
- line: 322
+ line: 357
function: global
destination: custom
properties:
@@ -438,11 +438,11 @@ events:
FailedPayment:
implementations:
- path: main.ts
- line: 361
+ line: 396
function: global
destination: custom
- path: main.ts
- line: 417
+ line: 452
function: trackFailedPayment
destination: custom
properties:
@@ -453,11 +453,11 @@ events:
InitiatedPayment:
implementations:
- path: main.ts
- line: 349
+ line: 384
function: global
destination: custom
- path: main.ts
- line: 422
+ line: 457
function: trackInitiatedPayment
destination: custom
properties:
@@ -468,7 +468,50 @@ events:
ViewedAttorneyAgreement:
implementations:
- path: main.ts
- line: 375
+ line: 410
function: handleView
destination: custom
properties: {}
+ checkout_completed:
+ implementations:
+ - path: main.ts
+ line: 247
+ function: checkout3
+ destination: datadog
+ properties:
+ total:
+ type: number
+ orderId:
+ type: string
+ currency:
+ type: string
+ items:
+ type: number
+ user_registration:
+ implementations:
+ - path: main.ts
+ line: 254
+ function: checkout3
+ destination: datadog
+ properties:
+ user_id:
+ type: string
+ method:
+ type: string
+ success:
+ type: boolean
+ referrer:
+ type: string
+ error_occurred:
+ implementations:
+ - path: main.ts
+ line: 261
+ function: checkout3
+ destination: datadog
+ properties:
+ error_type:
+ type: string
+ field:
+ type: string
+ page:
+ type: string
diff --git a/tests/schema.test.js b/tests/schema.test.js
index 678c426..5d988df 100644
--- a/tests/schema.test.js
+++ b/tests/schema.test.js
@@ -178,7 +178,7 @@ test.describe('Schema Validation Tests', () => {
const validDestinations = [
'googleanalytics', 'segment', 'mixpanel', 'amplitude',
'rudderstack', 'mparticle', 'posthog', 'pendo',
- 'heap', 'snowplow', 'custom', 'unknown'
+ 'heap', 'snowplow', 'datadog', 'custom', 'unknown',
];
// Check that all destinations are valid