@@ -21,6 +21,7 @@ const EXTRACTION_STRATEGIES = {
2121 googleanalytics : extractGoogleAnalyticsEvent ,
2222 snowplow : extractSnowplowEvent ,
2323 mparticle : extractMparticleEvent ,
24+ gtm : extractGTMEvent ,
2425 custom : extractCustomEvent ,
2526 default : extractDefaultEvent
2627} ;
@@ -126,6 +127,60 @@ function extractMparticleEvent(node, checker, sourceFile) {
126127 return { eventName, propertiesNode } ;
127128}
128129
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+
129184/**
130185 * Custom extraction
131186 * @param {Object } node - CallExpression node
0 commit comments