@flisk/analyze-tracking 0.7.2 → 0.7.4

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.
Files changed (66) hide show
  1. package/README.md +4 -0
  2. package/bin/cli.js +30 -2
  3. package/package.json +12 -8
  4. package/src/analyze/go/astTraversal.js +121 -0
  5. package/src/analyze/go/constants.js +20 -0
  6. package/src/analyze/go/eventDeduplicator.js +47 -0
  7. package/src/analyze/go/eventExtractor.js +156 -0
  8. package/src/analyze/go/goAstParser/constants.js +39 -0
  9. package/src/analyze/go/goAstParser/expressionParser.js +281 -0
  10. package/src/analyze/go/goAstParser/index.js +52 -0
  11. package/src/analyze/go/goAstParser/statementParser.js +387 -0
  12. package/src/analyze/go/goAstParser/tokenizer.js +196 -0
  13. package/src/analyze/go/goAstParser/typeParser.js +202 -0
  14. package/src/analyze/go/goAstParser/utils.js +99 -0
  15. package/src/analyze/go/index.js +55 -0
  16. package/src/analyze/go/propertyExtractor.js +670 -0
  17. package/src/analyze/go/trackingDetector.js +71 -0
  18. package/src/analyze/go/trackingExtractor.js +54 -0
  19. package/src/analyze/go/typeContext.js +88 -0
  20. package/src/analyze/go/utils.js +215 -0
  21. package/src/analyze/index.js +11 -6
  22. package/src/analyze/javascript/constants.js +115 -0
  23. package/src/analyze/javascript/detectors/analytics-source.js +119 -0
  24. package/src/analyze/javascript/detectors/index.js +10 -0
  25. package/src/analyze/javascript/extractors/event-extractor.js +179 -0
  26. package/src/analyze/javascript/extractors/index.js +13 -0
  27. package/src/analyze/javascript/extractors/property-extractor.js +172 -0
  28. package/src/analyze/javascript/index.js +38 -0
  29. package/src/analyze/javascript/parser.js +126 -0
  30. package/src/analyze/javascript/utils/function-finder.js +123 -0
  31. package/src/analyze/python/index.js +111 -0
  32. package/src/analyze/python/pythonTrackingAnalyzer.py +814 -0
  33. package/src/analyze/ruby/detectors.js +46 -0
  34. package/src/analyze/ruby/extractors.js +258 -0
  35. package/src/analyze/ruby/index.js +51 -0
  36. package/src/analyze/ruby/traversal.js +123 -0
  37. package/src/analyze/ruby/types.js +30 -0
  38. package/src/analyze/ruby/visitor.js +66 -0
  39. package/src/analyze/typescript/constants.js +109 -0
  40. package/src/analyze/typescript/detectors/analytics-source.js +125 -0
  41. package/src/analyze/typescript/detectors/index.js +10 -0
  42. package/src/analyze/typescript/extractors/event-extractor.js +269 -0
  43. package/src/analyze/typescript/extractors/index.js +14 -0
  44. package/src/analyze/typescript/extractors/property-extractor.js +427 -0
  45. package/src/analyze/typescript/index.js +48 -0
  46. package/src/analyze/typescript/parser.js +131 -0
  47. package/src/analyze/typescript/utils/function-finder.js +139 -0
  48. package/src/analyze/typescript/utils/type-resolver.js +208 -0
  49. package/src/generateDescriptions/index.js +81 -0
  50. package/src/generateDescriptions/llmUtils.js +33 -0
  51. package/src/generateDescriptions/promptUtils.js +62 -0
  52. package/src/generateDescriptions/schemaUtils.js +61 -0
  53. package/src/index.js +13 -4
  54. package/src/{fileProcessor.js → utils/fileProcessor.js} +5 -0
  55. package/src/{repoDetails.js → utils/repoDetails.js} +5 -0
  56. package/src/utils/yamlGenerator.js +47 -0
  57. package/src/analyze/analyzeGoFile.js +0 -1164
  58. package/src/analyze/analyzeJsFile.js +0 -87
  59. package/src/analyze/analyzePythonFile.js +0 -42
  60. package/src/analyze/analyzeRubyFile.js +0 -419
  61. package/src/analyze/analyzeTsFile.js +0 -192
  62. package/src/analyze/go2json.js +0 -1069
  63. package/src/analyze/helpers.js +0 -656
  64. package/src/analyze/pythonTrackingAnalyzer.py +0 -541
  65. package/src/generateDescriptions.js +0 -196
  66. package/src/yamlGenerator.js +0 -23
@@ -1,192 +0,0 @@
1
- const ts = require('typescript');
2
- const { detectSourceTs, findWrappingFunctionTs, extractTsProperties, resolveIdentifierToInitializer, extractInterfaceProperties } = require('./helpers');
3
-
4
- function resolveUnresolvedTypes(properties, checker, sourceFile) {
5
- const resolved = {};
6
-
7
- for (const [key, value] of Object.entries(properties)) {
8
- if (value && typeof value === 'object') {
9
- if (value.__unresolved) {
10
- // Try to find and resolve the type
11
- const typeName = value.__unresolved;
12
- delete value.__unresolved;
13
-
14
- // This is a simplified approach - in practice, you'd need to find the actual type declaration
15
- // For now, we'll keep the object type but remove the unresolved marker
16
- resolved[key] = value;
17
- } else if (value.type === 'array' && value.items && value.items.__unresolved) {
18
- // Handle unresolved array element types
19
- const itemTypeName = value.items.__unresolved;
20
- delete value.items.__unresolved;
21
- resolved[key] = value;
22
- } else if (value.type === 'array' && value.items && typeof value.items.type === 'string' && value.items.type.includes(' ')) {
23
- // Handle types like "readonly Product" - extract the actual type name
24
- const typeString = value.items.type;
25
- const actualType = typeString.replace(/^readonly\s+/, '').trim();
26
-
27
- // If it looks like a custom type, mark it as object
28
- if (actualType[0] === actualType[0].toUpperCase() && !actualType.includes('<')) {
29
- resolved[key] = {
30
- ...value,
31
- items: {
32
- type: 'object'
33
- }
34
- };
35
- } else {
36
- resolved[key] = value;
37
- }
38
- } else if (value.type === 'object' && value.properties) {
39
- // Recursively resolve nested properties
40
- resolved[key] = {
41
- ...value,
42
- properties: resolveUnresolvedTypes(value.properties, checker, sourceFile)
43
- };
44
- } else if (value.type === 'array' && value.items && value.items.properties) {
45
- // Recursively resolve array item properties
46
- resolved[key] = {
47
- ...value,
48
- items: {
49
- ...value.items,
50
- properties: value.items.properties ? resolveUnresolvedTypes(value.items.properties, checker, sourceFile) : undefined
51
- }
52
- };
53
- } else {
54
- resolved[key] = value;
55
- }
56
- } else {
57
- resolved[key] = value;
58
- }
59
- }
60
-
61
- return resolved;
62
- }
63
-
64
- function analyzeTsFile(filePath, program, customFunction) {
65
- let events = [];
66
- try {
67
- const sourceFile = program.getSourceFile(filePath);
68
- if (!sourceFile) {
69
- console.error(`Error: Unable to get source file for ${filePath}`);
70
- return events;
71
- }
72
-
73
- const checker = program.getTypeChecker();
74
-
75
- function visit(node) {
76
- try {
77
- if (ts.isCallExpression(node)) {
78
- const source = detectSourceTs(node, customFunction);
79
- if (source === 'unknown') return;
80
-
81
- let eventName = null;
82
- let propertiesNode = null;
83
-
84
- if (source === 'googleanalytics' && node.arguments.length >= 3) {
85
- eventName = node.arguments[1]?.text || null;
86
- propertiesNode = node.arguments[2];
87
- } else if (source === 'snowplow' && node.arguments.length > 0) {
88
- // Snowplow pattern: tracker.track(buildStructEvent({...})) or tracker.track(payload)
89
- const firstArg = node.arguments[0];
90
-
91
- // Check if it's a direct buildStructEvent call
92
- if (ts.isCallExpression(firstArg) &&
93
- ts.isIdentifier(firstArg.expression) &&
94
- firstArg.expression.escapedText === 'buildStructEvent' &&
95
- firstArg.arguments.length > 0) {
96
- const structEventArg = firstArg.arguments[0];
97
- if (ts.isObjectLiteralExpression(structEventArg)) {
98
- // Find the action property for event name
99
- const actionProp = structEventArg.properties.find(
100
- prop => prop.name && prop.name.escapedText === 'action'
101
- );
102
- if (actionProp && actionProp.initializer && ts.isStringLiteral(actionProp.initializer)) {
103
- eventName = actionProp.initializer.text;
104
- propertiesNode = structEventArg;
105
- }
106
- }
107
- }
108
- // Check if it's a variable reference (e.g., const payload = buildStructEvent({...}))
109
- else if (ts.isIdentifier(firstArg)) {
110
- const resolvedNode = resolveIdentifierToInitializer(checker, firstArg, sourceFile);
111
- if (resolvedNode && ts.isCallExpression(resolvedNode) &&
112
- ts.isIdentifier(resolvedNode.expression) &&
113
- resolvedNode.expression.escapedText === 'buildStructEvent' &&
114
- resolvedNode.arguments.length > 0) {
115
- const structEventArg = resolvedNode.arguments[0];
116
- if (ts.isObjectLiteralExpression(structEventArg)) {
117
- const actionProp = structEventArg.properties.find(
118
- prop => prop.name && prop.name.escapedText === 'action'
119
- );
120
- if (actionProp && actionProp.initializer && ts.isStringLiteral(actionProp.initializer)) {
121
- eventName = actionProp.initializer.text;
122
- propertiesNode = structEventArg;
123
- }
124
- }
125
- }
126
- }
127
- } else if (source === 'mparticle' && node.arguments.length >= 3) {
128
- // mParticle: first param is event name, second is event type (ignored), third is properties
129
- eventName = node.arguments[0]?.text || null;
130
- propertiesNode = node.arguments[2];
131
- } else if (node.arguments.length >= 2) {
132
- eventName = node.arguments[0]?.text || null;
133
- propertiesNode = node.arguments[1];
134
- }
135
-
136
- const line = sourceFile.getLineAndCharacterOfPosition(node.getStart()).line + 1;
137
- const functionName = findWrappingFunctionTs(node);
138
-
139
- if (eventName && propertiesNode) {
140
- try {
141
- let properties = null;
142
-
143
- // Check if properties is an object literal
144
- if (ts.isObjectLiteralExpression(propertiesNode)) {
145
- properties = extractTsProperties(checker, propertiesNode);
146
- }
147
- // Check if properties is an identifier (variable reference)
148
- else if (ts.isIdentifier(propertiesNode)) {
149
- const resolvedNode = resolveIdentifierToInitializer(checker, propertiesNode, sourceFile);
150
- if (resolvedNode && ts.isObjectLiteralExpression(resolvedNode)) {
151
- properties = extractTsProperties(checker, resolvedNode);
152
- }
153
- }
154
-
155
- if (properties) {
156
- // For Snowplow, remove 'action' from properties since it's used as the event name
157
- if (source === 'snowplow' && properties.action) {
158
- delete properties.action;
159
- }
160
-
161
- // Clean up any unresolved type markers
162
- const cleanedProperties = resolveUnresolvedTypes(properties, checker, sourceFile);
163
-
164
- events.push({
165
- eventName,
166
- source,
167
- properties: cleanedProperties,
168
- filePath,
169
- line,
170
- functionName
171
- });
172
- }
173
- } catch (propertyError) {
174
- console.error(`Error extracting properties in ${filePath} at line ${line}`);
175
- }
176
- }
177
- }
178
- ts.forEachChild(node, visit);
179
- } catch (nodeError) {
180
- console.error(`Error processing node in ${filePath}`);
181
- }
182
- }
183
-
184
- ts.forEachChild(sourceFile, visit);
185
- } catch (fileError) {
186
- console.error(`Error analyzing TypeScript file ${filePath}`);
187
- }
188
-
189
- return events;
190
- }
191
-
192
- module.exports = { analyzeTsFile };