@flisk/analyze-tracking 0.8.6 → 0.8.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -12
- package/package.json +1 -1
- package/schema.json +1 -0
- package/src/analyze/javascript/constants.js +6 -0
- package/src/analyze/javascript/extractors/event-extractor.js +38 -0
- package/src/analyze/typescript/constants.js +6 -0
- package/src/analyze/typescript/extractors/event-extractor.js +55 -0
package/README.md
CHANGED
|
@@ -101,18 +101,19 @@ See [schema.json](schema.json) for a JSON Schema of the output.
|
|
|
101
101
|
|
|
102
102
|
| Library | JavaScript/TypeScript | Python | Ruby | Go |
|
|
103
103
|
|---------|:---------------------:|:------:|:----:|:--:|
|
|
104
|
-
| Google Analytics
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
104
|
+
| Google Analytics | ✅ | ❌ | ❌ | ❌ |
|
|
105
|
+
| Google Tag Manager | ✅ | ❌ | ❌ | ❌ |
|
|
106
|
+
| Segment | ✅ | ✅ | ✅ | ✅ |
|
|
107
|
+
| Mixpanel | ✅ | ✅ | ✅ | ✅ |
|
|
108
|
+
| Amplitude | ✅ | ✅ | ❌ | ✅ |
|
|
109
|
+
| Rudderstack | ✅ | ✅ | ✳️ | ✳️ |
|
|
110
|
+
| mParticle | ✅ | ❌ | ❌ | ❌ |
|
|
111
|
+
| PostHog | ✅ | ✅ | ✅ | ✅ |
|
|
112
|
+
| Pendo | ✅ | ❌ | ❌ | ❌ |
|
|
113
|
+
| Heap | ✅ | ❌ | ❌ | ❌ |
|
|
114
|
+
| Snowplow | ✅ | ✅ | ✅ | ✅ |
|
|
115
|
+
| Datadog RUM | ✅ | ❌ | ❌ | ❌ |
|
|
116
|
+
| Custom Function | ✅ | ✅ | ✅ | ✅ |
|
|
116
117
|
|
|
117
118
|
✳️ Rudderstack's SDKs often use the same format as Segment, so Rudderstack events may be detected as Segment events.
|
|
118
119
|
|
|
@@ -130,6 +131,24 @@ See [schema.json](schema.json) for a JSON Schema of the output.
|
|
|
130
131
|
```
|
|
131
132
|
</details>
|
|
132
133
|
|
|
134
|
+
<details>
|
|
135
|
+
<summary>Google Tag Manager</summary>
|
|
136
|
+
|
|
137
|
+
**JavaScript/TypeScript**
|
|
138
|
+
```js
|
|
139
|
+
dataLayer.push({
|
|
140
|
+
event: '<event_name>',
|
|
141
|
+
'<property_name>': '<property_value>'
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// Or via window
|
|
145
|
+
window.dataLayer.push({
|
|
146
|
+
event: '<event_name>',
|
|
147
|
+
'<property_name>': '<property_value>'
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
</details>
|
|
151
|
+
|
|
133
152
|
<details>
|
|
134
153
|
<summary>Segment</summary>
|
|
135
154
|
|
package/package.json
CHANGED
package/schema.json
CHANGED
|
@@ -20,6 +20,7 @@ const EXTRACTION_STRATEGIES = {
|
|
|
20
20
|
googleanalytics: extractGoogleAnalyticsEvent,
|
|
21
21
|
snowplow: extractSnowplowEvent,
|
|
22
22
|
mparticle: extractMparticleEvent,
|
|
23
|
+
gtm: extractGTMEvent,
|
|
23
24
|
custom: extractCustomEvent,
|
|
24
25
|
default: extractDefaultEvent
|
|
25
26
|
};
|
|
@@ -105,6 +106,43 @@ function extractMparticleEvent(node, constantMap) {
|
|
|
105
106
|
return { eventName, propertiesNode };
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Extracts Google Tag Manager event data
|
|
111
|
+
* @param {Object} node - CallExpression node
|
|
112
|
+
* @param {Object} constantMap - Collected constant map
|
|
113
|
+
* @returns {EventData}
|
|
114
|
+
*/
|
|
115
|
+
function extractGTMEvent(node, constantMap) {
|
|
116
|
+
if (!node.arguments || node.arguments.length === 0) {
|
|
117
|
+
return { eventName: null, propertiesNode: null };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// dataLayer.push({ event: 'event_name', property1: 'value1', property2: 'value2' })
|
|
121
|
+
const firstArg = node.arguments[0];
|
|
122
|
+
|
|
123
|
+
if (firstArg.type !== NODE_TYPES.OBJECT_EXPRESSION) {
|
|
124
|
+
return { eventName: null, propertiesNode: null };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Find the 'event' property
|
|
128
|
+
const eventProperty = findPropertyByKey(firstArg, 'event');
|
|
129
|
+
if (!eventProperty) {
|
|
130
|
+
return { eventName: null, propertiesNode: null };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const eventName = getStringValue(eventProperty.value, constantMap);
|
|
134
|
+
|
|
135
|
+
// Create a modified properties node without the 'event' property
|
|
136
|
+
const modifiedPropertiesNode = {
|
|
137
|
+
...firstArg,
|
|
138
|
+
properties: firstArg.properties.filter(prop =>
|
|
139
|
+
prop.key && (prop.key.name !== 'event' && prop.key.value !== 'event')
|
|
140
|
+
)
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
return { eventName, propertiesNode: modifiedPropertiesNode };
|
|
144
|
+
}
|
|
145
|
+
|
|
108
146
|
/**
|
|
109
147
|
* Default event extraction for standard providers
|
|
110
148
|
* @param {Object} node - CallExpression node
|
|
@@ -21,6 +21,7 @@ const EXTRACTION_STRATEGIES = {
|
|
|
21
21
|
googleanalytics: extractGoogleAnalyticsEvent,
|
|
22
22
|
snowplow: extractSnowplowEvent,
|
|
23
23
|
mparticle: extractMparticleEvent,
|
|
24
|
+
gtm: extractGTMEvent,
|
|
24
25
|
custom: extractCustomEvent,
|
|
25
26
|
default: extractDefaultEvent
|
|
26
27
|
};
|
|
@@ -126,6 +127,60 @@ function extractMparticleEvent(node, checker, sourceFile) {
|
|
|
126
127
|
return { eventName, propertiesNode };
|
|
127
128
|
}
|
|
128
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Extracts Google Tag Manager event data
|
|
132
|
+
* @param {Object} node - CallExpression node
|
|
133
|
+
* @param {Object} checker - TypeScript type checker
|
|
134
|
+
* @param {Object} sourceFile - TypeScript source file
|
|
135
|
+
* @returns {EventData}
|
|
136
|
+
*/
|
|
137
|
+
function extractGTMEvent(node, checker, sourceFile) {
|
|
138
|
+
if (!node.arguments || node.arguments.length === 0) {
|
|
139
|
+
return { eventName: null, propertiesNode: null };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// dataLayer.push({ event: 'event_name', property1: 'value1', property2: 'value2' })
|
|
143
|
+
const firstArg = node.arguments[0];
|
|
144
|
+
|
|
145
|
+
if (!ts.isObjectLiteralExpression(firstArg)) {
|
|
146
|
+
return { eventName: null, propertiesNode: null };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Find the 'event' property
|
|
150
|
+
const eventProperty = findPropertyByKey(firstArg, 'event');
|
|
151
|
+
if (!eventProperty) {
|
|
152
|
+
return { eventName: null, propertiesNode: null };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const eventName = getStringValue(eventProperty.initializer, checker, sourceFile);
|
|
156
|
+
|
|
157
|
+
// Create a modified properties node without the 'event' property
|
|
158
|
+
const modifiedProperties = firstArg.properties.filter(prop => {
|
|
159
|
+
if (ts.isPropertyAssignment(prop) && prop.name) {
|
|
160
|
+
if (ts.isIdentifier(prop.name)) {
|
|
161
|
+
return prop.name.escapedText !== 'event';
|
|
162
|
+
}
|
|
163
|
+
if (ts.isStringLiteral(prop.name)) {
|
|
164
|
+
return prop.name.text !== 'event';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Create a synthetic object literal with the filtered properties
|
|
171
|
+
const modifiedPropertiesNode = ts.factory.createObjectLiteralExpression(modifiedProperties);
|
|
172
|
+
|
|
173
|
+
// Copy source positions for proper analysis
|
|
174
|
+
if (firstArg.pos !== undefined) {
|
|
175
|
+
modifiedPropertiesNode.pos = firstArg.pos;
|
|
176
|
+
}
|
|
177
|
+
if (firstArg.end !== undefined) {
|
|
178
|
+
modifiedPropertiesNode.end = firstArg.end;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return { eventName, propertiesNode: modifiedPropertiesNode };
|
|
182
|
+
}
|
|
183
|
+
|
|
129
184
|
/**
|
|
130
185
|
* Custom extraction
|
|
131
186
|
* @param {Object} node - CallExpression node
|