@flisk/analyze-tracking 0.1.2 → 0.2.0

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 CHANGED
@@ -11,7 +11,6 @@ npx @flisk/analyze-tracking /path/to/project [options]
11
11
  ```
12
12
 
13
13
  Optional arguments:
14
- - `--repository <repository_url>`: URL of the repository where the code is hosted (defaults to git remote origin in project directory)
15
14
  - `--output <output_file>`: Name of the output file (default: `tracking-schema.yaml`)
16
15
 
17
16
 
@@ -19,16 +18,18 @@ Optional arguments:
19
18
  A YAML file with the following structure is generated:
20
19
 
21
20
  ```yaml
22
- version: 1.0
21
+ version: 1
22
+ source:
23
+ repository: <repository_url>
24
+ commit: <commit_sha>
25
+ timestamp: <commit_timestamp>
23
26
  events:
24
27
  <event_name>:
25
- sources:
26
- - repository: <repository_name>
27
- path: <path_to_file>
28
+ implementations:
29
+ - path: <path_to_file>
28
30
  line: <line_number>
29
31
  function: <function_name>
30
- destinations:
31
- - <destination_name>
32
+ destination: <platform_name>
32
33
  properties:
33
34
  <property_name>:
34
35
  type: <property_type>
@@ -89,6 +90,14 @@ mParticle.logEvent('<event_name>', {
89
90
  ```
90
91
 
91
92
 
93
+ #### PostHog
94
+ ```js
95
+ posthog.capture('<event_name>', {
96
+ <event_parameters>
97
+ });
98
+ ```
99
+
100
+
92
101
  #### Snowplow
93
102
  ```js
94
103
  snowplow('trackStructEvent', {
package/bin/cli.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const path = require('path');
4
- const { execSync } = require('child_process');
5
4
  const commandLineArgs = require('command-line-args')
6
5
  const { run } = require('../src/index');
7
6
 
@@ -12,11 +11,6 @@ const optionDefinitions = [
12
11
  type: String,
13
12
  defaultOption: true,
14
13
  },
15
- {
16
- name: 'repository',
17
- alias: 'r',
18
- type: String,
19
- },
20
14
  {
21
15
  name: 'output',
22
16
  alias: 'o',
@@ -25,24 +19,11 @@ const optionDefinitions = [
25
19
  },
26
20
  ]
27
21
  const options = commandLineArgs(optionDefinitions);
28
- const { targetDir, output, repository } = options;
22
+ const { targetDir, output } = options;
29
23
 
30
24
  if (!targetDir) {
31
25
  console.error('Please provide the path to the repository.');
32
26
  process.exit(1);
33
27
  }
34
28
 
35
- // Get the repository URL using Git
36
- function getRepositoryUrl() {
37
- try {
38
- const repoUrl = execSync('git config --get remote.origin.url', { cwd: targetDir, encoding: 'utf8' });
39
- return repoUrl.trim();
40
- } catch (error) {
41
- console.warn('Could not retrieve repository URL. Using default value "unknown".');
42
- return 'unknown';
43
- }
44
- }
45
-
46
- const repositoryUrl = repository || getRepositoryUrl();
47
-
48
- run(path.resolve(targetDir), repositoryUrl, output);
29
+ run(path.resolve(targetDir), output);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flisk/analyze-tracking",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Analyzes tracking code in a project and generates data schemas",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/schema.json CHANGED
@@ -1,30 +1,47 @@
1
1
  {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
2
+ "$schema": "http://json-schema.org/draft-07/schema",
3
3
  "title": "@flisk/analyze-tracking output schema",
4
4
  "type": "object",
5
5
  "properties": {
6
6
  "version": {
7
7
  "type": "number",
8
8
  "enum": [
9
- 1.0
9
+ 1
10
10
  ],
11
11
  "description": "Version of the schema"
12
12
  },
13
+ "source": {
14
+ "type": "object",
15
+ "properties": {
16
+ "repository": {
17
+ "type": "string",
18
+ "description": "URL of git repository that was used to generate the schema"
19
+ },
20
+ "commit": {
21
+ "type": "string",
22
+ "description": "Git commit hash when this schema was generated"
23
+ },
24
+ "timestamp": {
25
+ "type": "string",
26
+ "description": "Git commit timestamp when this schema was generated"
27
+ }
28
+ },
29
+ "required": [
30
+ "timestamp"
31
+ ],
32
+ "additionalProperties": false
33
+ },
13
34
  "events": {
14
35
  "type": "object",
15
36
  "patternProperties": {
16
37
  "^[a-zA-Z0-9_-]+$": {
17
38
  "type": "object",
18
39
  "properties": {
19
- "sources": {
40
+ "implementations": {
20
41
  "type": "array",
21
42
  "items": {
22
43
  "type": "object",
23
44
  "properties": {
24
- "repository": {
25
- "type": "string",
26
- "description": "Repository URL or name"
27
- },
28
45
  "path": {
29
46
  "type": "string",
30
47
  "description": "Relative path to the file where the event is tracked"
@@ -36,71 +53,84 @@
36
53
  "function": {
37
54
  "type": "string",
38
55
  "description": "Name of the function where the event is tracked"
56
+ },
57
+ "destination": {
58
+ "type": "string",
59
+ "enum": [
60
+ "googleanalytics",
61
+ "segment",
62
+ "mixpanel",
63
+ "amplitude",
64
+ "rudderstack",
65
+ "mparticle",
66
+ "posthog",
67
+ "snowplow",
68
+ "unknown"
69
+ ],
70
+ "description": "Name of the platform where the event is sent"
39
71
  }
40
72
  },
41
73
  "required": [
42
- "repository",
43
74
  "path",
44
75
  "line",
45
- "function"
46
- ]
47
- }
48
- },
49
- "destinations": {
50
- "type": "array",
51
- "items": {
52
- "type": "string",
53
- "enum": [
54
- "googleanalytics",
55
- "segment",
56
- "mixpanel",
57
- "amplitude",
58
- "rudderstack",
59
- "mparticle",
60
- "snowplow",
61
- "unknown"
76
+ "function",
77
+ "destination"
62
78
  ],
63
- "description": "Destination analytics platform"
79
+ "additionalProperties": false
64
80
  }
65
81
  },
66
82
  "properties": {
67
83
  "type": "object",
68
84
  "patternProperties": {
69
85
  "^[a-zA-Z0-9_-]+$": {
70
- "type": "object",
71
- "properties": {
72
- "type": {
73
- "type": "string",
74
- "description": "Data type of the property (e.g., string, number)"
75
- },
76
- "required": {
77
- "type": "boolean",
78
- "description": "Whether this property is required"
79
- },
80
- "description": {
81
- "type": "string",
82
- "description": "Description of the property"
83
- }
84
- },
85
- "required": [
86
- "type"
87
- ]
86
+ "$ref": "#/definitions/property"
88
87
  }
89
88
  }
90
89
  }
91
90
  },
92
91
  "required": [
93
- "sources",
94
- "destinations",
92
+ "implementations",
95
93
  "properties"
96
- ]
94
+ ],
95
+ "additionalProperties": false
97
96
  }
98
- },
99
- "additionalProperties": false
97
+ }
100
98
  }
101
99
  },
102
100
  "required": [
103
101
  "version",
102
+ "source",
104
103
  "events"
105
- ]
104
+ ],
105
+ "definitions": {
106
+ "property": {
107
+ "type": "object",
108
+ "properties": {
109
+ "type": {
110
+ "type": "string",
111
+ "description": "Data type of the property (e.g., string, number, any)"
112
+ },
113
+ "required": {
114
+ "type": "boolean",
115
+ "description": "Whether this property is required"
116
+ },
117
+ "description": {
118
+ "type": "string",
119
+ "description": "Description of the property"
120
+ },
121
+ "properties": {
122
+ "type": "object",
123
+ "patternProperties": {
124
+ "^[a-zA-Z0-9_-]+$": {
125
+ "$ref": "#/definitions/property"
126
+ }
127
+ }
128
+ }
129
+ },
130
+ "required": [
131
+ "type"
132
+ ],
133
+ "additionalProperties": false
134
+ }
135
+ }
106
136
  }
@@ -14,6 +14,7 @@ function detectSourceJs(node) {
14
14
  if (objectName === 'amplitude' && methodName === 'logEvent') return 'amplitude';
15
15
  if (objectName === 'rudderanalytics' && methodName === 'track') return 'rudderstack';
16
16
  if (objectName === 'mParticle' && methodName === 'logEvent') return 'mparticle';
17
+ if (objectName === 'posthog' && methodName === 'capture') return 'posthog';
17
18
  } else if (node.callee.type === 'Identifier' && node.callee.name === 'snowplow') {
18
19
  return 'snowplow';
19
20
  }
@@ -35,6 +36,7 @@ function detectSourceTs(node) {
35
36
  if (objectName === 'amplitude' && methodName === 'logEvent') return 'amplitude';
36
37
  if (objectName === 'rudderanalytics' && methodName === 'track') return 'rudderstack';
37
38
  if (objectName === 'mParticle' && methodName === 'logEvent') return 'mparticle';
39
+ if (objectName === 'posthog' && methodName === 'capture') return 'posthog';
38
40
  } else if (ts.isIdentifier(node.expression) && node.expression.escapedText === 'snowplow') {
39
41
  return 'snowplow';
40
42
  }
@@ -4,7 +4,7 @@ const { getAllFiles } = require('../fileProcessor');
4
4
  const ts = require('typescript');
5
5
  const path = require('path');
6
6
 
7
- function analyzeDirectory(dirPath, repository) {
7
+ function analyzeDirectory(dirPath) {
8
8
  const files = getAllFiles(dirPath);
9
9
  const allEvents = {};
10
10
 
@@ -23,27 +23,22 @@ function analyzeDirectory(dirPath, repository) {
23
23
 
24
24
  if (!allEvents[event.eventName]) {
25
25
  allEvents[event.eventName] = {
26
- sources: [{
27
- repository: repository,
26
+ implementations: [{
28
27
  path: relativeFilePath,
29
28
  line: event.line,
30
- function: event.functionName
29
+ function: event.functionName,
30
+ destination: event.source
31
31
  }],
32
- destinations: [event.source],
33
32
  properties: event.properties,
34
33
  };
35
34
  } else {
36
- allEvents[event.eventName].sources.push({
37
- repository: repository,
35
+ allEvents[event.eventName].implementations.push({
38
36
  path: relativeFilePath,
39
37
  line: event.line,
40
- function: event.functionName
38
+ function: event.functionName,
39
+ destination: event.source
41
40
  });
42
41
 
43
- if (!allEvents[event.eventName].destinations.includes(event.source)) {
44
- allEvents[event.eventName].destinations.push(event.source);
45
- }
46
-
47
42
  allEvents[event.eventName].properties = {
48
43
  ...allEvents[event.eventName].properties,
49
44
  ...event.properties,
package/src/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  const { analyzeDirectory } = require('./analyze');
2
+ const { getRepoDetails } = require('./repoDetails');
2
3
  const { generateYamlSchema } = require('./yamlGenerator');
3
4
 
4
- function run(targetDir, repository, outputPath) {
5
- const events = analyzeDirectory(targetDir, repository);
6
- generateYamlSchema(events, outputPath);
5
+ function run(targetDir, outputPath) {
6
+ const events = analyzeDirectory(targetDir);
7
+ const repoDetails = getRepoDetails(targetDir);
8
+ generateYamlSchema(events, repoDetails, outputPath);
7
9
  }
8
10
 
9
11
  module.exports = { run };
@@ -0,0 +1,61 @@
1
+ const { execSync } = require('child_process');
2
+
3
+ function getRepositoryUrl(targetDir) {
4
+ try {
5
+ const repoUrl = execSync('git config --get remote.origin.url', { cwd: targetDir, encoding: 'utf8' });
6
+ return repoUrl.trim();
7
+ } catch (error) {
8
+ console.warn('Could not determine repository URL. Will exclude.');
9
+ return null;
10
+ }
11
+ }
12
+
13
+ function getCommitHash(targetDir) {
14
+ try {
15
+ const commitHash = execSync('git rev-parse HEAD', { cwd: targetDir, encoding: 'utf8' });
16
+ return commitHash.trim();
17
+ } catch (error) {
18
+ console.warn('Could not determine latest commit hash. Will exclude.');
19
+ return null;
20
+ }
21
+ }
22
+
23
+ function getCommitTimestamp(targetDir, commitHash) {
24
+ try {
25
+ const commitTimestamp = execSync(`git --no-pager show -s --format=%ct ${commitHash}`, { cwd: targetDir, encoding: 'utf8' });
26
+ const unixTimeSeconds = commitTimestamp.trim();
27
+ return new Date(unixTimeSeconds * 1000);
28
+ } catch (error) {
29
+ console.warn('Could not retrieve commit timestamp. Using current timestamp as default.')
30
+ return new Date();
31
+ }
32
+ }
33
+
34
+ function pad(n) {
35
+ return n<10 ? '0'+n : n
36
+ }
37
+
38
+ function toISODateString(date) {
39
+ return date.getUTCFullYear()+'-'
40
+ + pad(date.getUTCMonth()+1)+'-'
41
+ + pad(date.getUTCDate())+'T'
42
+ + pad(date.getUTCHours())+':'
43
+ + pad(date.getUTCMinutes())+':'
44
+ + pad(date.getUTCSeconds())+'Z'
45
+ }
46
+
47
+ function getRepoDetails(targetDir) {
48
+ const repoUrl = getRepositoryUrl(targetDir);
49
+ const commitHash = getCommitHash(targetDir);
50
+ const commitEpochTime = getCommitTimestamp(targetDir, commitHash);
51
+ const commitTimestamp = toISODateString(commitEpochTime);
52
+
53
+ const repoDetails = {};
54
+ if (!!repoUrl) repoDetails.repository = repoUrl;
55
+ if (!!commitHash) repoDetails.commit = commitHash;
56
+ repoDetails.timestamp = commitTimestamp
57
+
58
+ return repoDetails;
59
+ }
60
+
61
+ module.exports = { getRepoDetails };
@@ -1,14 +1,21 @@
1
1
  const fs = require('fs');
2
2
  const yaml = require('js-yaml');
3
3
 
4
- function generateYamlSchema(events, outputPath) {
4
+ const VERSION = 1
5
+ const SCHEMA_URL = "https://raw.githubusercontent.com/fliskdata/analyze-tracking/main/schema.json";
6
+
7
+ function generateYamlSchema(events, repository, outputPath) {
5
8
  const schema = {
6
- version: 1.0,
9
+ version: VERSION,
10
+ source: repository,
7
11
  events,
8
12
  };
9
-
10
- const yamlOutput = yaml.dump(schema, { noRefs: true });
11
- fs.writeFileSync(outputPath, yamlOutput, 'utf8');
13
+ const options = {
14
+ noRefs: true,
15
+ };
16
+ const yamlOutput = yaml.dump(schema, options);
17
+ const yamlFile = `# yaml-language-server: $schema=${SCHEMA_URL}\n${yamlOutput}`;
18
+ fs.writeFileSync(outputPath, yamlFile, 'utf8');
12
19
  console.log(`Tracking schema YAML file generated: ${outputPath}`);
13
20
  }
14
21