@eventra_dev/eventra-cli 0.2.3 → 0.3.1

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 (89) hide show
  1. package/README.md +154 -32
  2. package/dist/analysis/cache/evaluationCache.js +21 -0
  3. package/dist/analysis/cache/resolvedCallCache.js +21 -0
  4. package/dist/analysis/cache/resolvedExportCache.js +21 -0
  5. package/dist/analysis/cache/semanticDependencyGraph.js +25 -0
  6. package/dist/analysis/cache/symbolInvalidation.js +20 -0
  7. package/dist/analysis/extractor/extractor.js +47 -0
  8. package/dist/analysis/extractor/propagationExtractor.js +52 -0
  9. package/dist/analysis/pipeline/semanticPass.js +2 -0
  10. package/dist/analysis/resolver/callResolver.js +125 -0
  11. package/dist/analysis/resolver/exportResolver.js +75 -0
  12. package/dist/analysis/resolver/resolver.js +133 -0
  13. package/dist/analysis/scanner/analyzer/propagationAnalyzer.js +193 -0
  14. package/dist/analysis/scanner/analyzer/returnPropagationAnalyzer.js +105 -0
  15. package/dist/analysis/scanner/scanner.js +117 -0
  16. package/dist/analysis/scanner/sinkDetector.js +91 -0
  17. package/dist/analysis/shared/evaluationContext.js +9 -0
  18. package/dist/analysis/shared/propagation.js +3 -0
  19. package/dist/analysis/shared/returnPropagation.js +2 -0
  20. package/dist/analysis/shared/types.js +2 -0
  21. package/dist/analysis/shared/utils.js +62 -0
  22. package/dist/analysis/symbols/symbolUtils.js +68 -0
  23. package/dist/analysis/symbols/wrapperRegistry.js +55 -0
  24. package/dist/cli/check.js +73 -0
  25. package/dist/{commands → cli}/init.js +1 -1
  26. package/dist/{commands → cli}/send.js +1 -1
  27. package/dist/cli/sync.js +56 -0
  28. package/dist/{commands → cli}/watch.js +41 -25
  29. package/dist/compiler/compilerContext.js +204 -0
  30. package/dist/compiler/documentRegistry.js +78 -0
  31. package/dist/compiler/importGraph.js +83 -0
  32. package/dist/compiler/scheduler.js +29 -0
  33. package/dist/core/EventraEngine.js +234 -0
  34. package/dist/core/projectScanner.js +73 -0
  35. package/dist/{utils → filesystem}/getVirtualFile.js +1 -3
  36. package/dist/filesystem/processFile.js +38 -0
  37. package/dist/index.js +5 -5
  38. package/dist/shared/buildSyntheticTsx.js +20 -0
  39. package/dist/shared/templateExpressionExtractor.js +22 -0
  40. package/package.json +32 -9
  41. package/.github/workflows/release.yml +0 -43
  42. package/ARCHITECTURE.md +0 -88
  43. package/assets/eventra-icon-animated.svg +0 -19
  44. package/dist/commands/check.js +0 -78
  45. package/dist/commands/sync.js +0 -79
  46. package/dist/engine/boundary.js +0 -14
  47. package/dist/engine/callResolver.js +0 -58
  48. package/dist/engine/engine.js +0 -154
  49. package/dist/engine/exportResolver.js +0 -46
  50. package/dist/engine/functionAnalyzer.js +0 -71
  51. package/dist/engine/graph.js +0 -168
  52. package/dist/engine/languageService.js +0 -162
  53. package/dist/engine/resolver.js +0 -149
  54. package/dist/engine/scanner.js +0 -230
  55. package/dist/utils/processFile.js +0 -28
  56. package/dist/utils/universal.js +0 -190
  57. package/src/commands/check.ts +0 -91
  58. package/src/commands/init.ts +0 -174
  59. package/src/commands/send.ts +0 -213
  60. package/src/commands/sync.ts +0 -106
  61. package/src/commands/watch.ts +0 -144
  62. package/src/engine/boundary.ts +0 -12
  63. package/src/engine/callResolver.ts +0 -65
  64. package/src/engine/engine.ts +0 -227
  65. package/src/engine/exportResolver.ts +0 -56
  66. package/src/engine/functionAnalyzer.ts +0 -81
  67. package/src/engine/graph.ts +0 -193
  68. package/src/engine/hash.ts +0 -5
  69. package/src/engine/languageService.ts +0 -209
  70. package/src/engine/resolver.ts +0 -177
  71. package/src/engine/scanner.ts +0 -298
  72. package/src/index.ts +0 -49
  73. package/src/types.ts +0 -35
  74. package/src/utils/config.ts +0 -53
  75. package/src/utils/getVirtualFile.ts +0 -5
  76. package/src/utils/processFile.ts +0 -29
  77. package/src/utils/universal.ts +0 -249
  78. package/tests/fixtures/backend/express/app.ts +0 -233
  79. package/tests/fixtures/backend/nest/service.ts +0 -70
  80. package/tests/fixtures/backend/node/index.ts +0 -63
  81. package/tests/fixtures/frontend/next/page.tsx +0 -101
  82. package/tests/fixtures/frontend/react/App.tsx +0 -104
  83. package/tests/fixtures/frontend/vue/App.vue +0 -83
  84. package/tests/fixtures/wrappers/component/test.tsx +0 -62
  85. package/tests/fixtures/wrappers/function/test.ts +0 -60
  86. package/tests/run.ts +0 -106
  87. package/tsconfig.json +0 -14
  88. /package/dist/{utils → config}/config.js +0 -0
  89. /package/dist/{engine → shared}/hash.js +0 -0
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ // src/analysis/resolver/exportResolver.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.resolveExportedSymbol = resolveExportedSymbol;
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ function isConcreteDeclaration(node) {
10
+ return (typescript_1.default.isFunctionDeclaration(node)
11
+ || typescript_1.default.isVariableDeclaration(node)
12
+ || typescript_1.default.isClassDeclaration(node)
13
+ || typescript_1.default.isEnumDeclaration(node)
14
+ || typescript_1.default.isInterfaceDeclaration(node)
15
+ || typescript_1.default.isTypeAliasDeclaration(node)
16
+ || typescript_1.default.isMethodDeclaration(node)
17
+ || typescript_1.default.isPropertyDeclaration(node));
18
+ }
19
+ function resolveExportedSymbol(symbol, checker, cache, visited) {
20
+ const seen = visited
21
+ ?? new Set();
22
+ const cached = cache.get(symbol);
23
+ if (cached !== undefined) {
24
+ return cached;
25
+ }
26
+ //
27
+ // cycle guard
28
+ //
29
+ if (seen.has(symbol)) {
30
+ cache.set(symbol, null);
31
+ return null;
32
+ }
33
+ seen.add(symbol);
34
+ //
35
+ // alias unwrap
36
+ //
37
+ if (symbol.flags
38
+ & typescript_1.default.SymbolFlags.Alias) {
39
+ const aliased = checker.getAliasedSymbol(symbol);
40
+ const resolved = resolveExportedSymbol(aliased, checker, cache, seen);
41
+ cache.set(symbol, resolved);
42
+ return resolved;
43
+ }
44
+ //
45
+ // export unwrap
46
+ //
47
+ const exportSymbol = checker.getExportSymbolOfSymbol(symbol);
48
+ if (exportSymbol
49
+ && exportSymbol !== symbol) {
50
+ const resolved = resolveExportedSymbol(exportSymbol, checker, cache, seen);
51
+ cache.set(symbol, resolved);
52
+ return resolved;
53
+ }
54
+ //
55
+ // declaration existence
56
+ //
57
+ const declarations = symbol.getDeclarations()
58
+ ?? [];
59
+ for (const declaration of declarations) {
60
+ if (isConcreteDeclaration(declaration)) {
61
+ cache.set(symbol, symbol);
62
+ return symbol;
63
+ }
64
+ }
65
+ //
66
+ // final validation
67
+ //
68
+ const valid = declarations.some(isConcreteDeclaration);
69
+ if (valid) {
70
+ cache.set(symbol, symbol);
71
+ return symbol;
72
+ }
73
+ cache.set(symbol, null);
74
+ return null;
75
+ }
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ // src/analysis/resolver/resolver.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.resolveNodeValue = resolveNodeValue;
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ const exportResolver_1 = require("./exportResolver");
10
+ const returnPropagationAnalyzer_1 = require("../scanner/analyzer/returnPropagationAnalyzer");
11
+ const callResolver_1 = require("./callResolver");
12
+ const resolvedCallCache_1 = require("../cache/resolvedCallCache");
13
+ function unique(values) {
14
+ return [
15
+ ...new Set(values),
16
+ ];
17
+ }
18
+ function empty() {
19
+ return {
20
+ values: [],
21
+ dynamic: true,
22
+ };
23
+ }
24
+ function concat(left, right) {
25
+ const result = [];
26
+ for (const l of left) {
27
+ for (const r of right) {
28
+ result.push(l + r);
29
+ }
30
+ }
31
+ return unique(result);
32
+ }
33
+ function resolveIdentifier(node, checker, context, visited, evaluationCache, exportCache) {
34
+ const boundSymbol = checker.getSymbolAtLocation(node);
35
+ if (boundSymbol
36
+ && context.parameterBindings.has(boundSymbol)) {
37
+ const bound = context.parameterBindings.get(boundSymbol);
38
+ if (bound) {
39
+ return resolveNodeValue(bound, checker, context, visited, evaluationCache, undefined, exportCache);
40
+ }
41
+ }
42
+ let symbol = checker.getSymbolAtLocation(node);
43
+ if (!symbol) {
44
+ return empty();
45
+ }
46
+ symbol =
47
+ (0, exportResolver_1.resolveExportedSymbol)(symbol, checker, exportCache)
48
+ ?? symbol;
49
+ const cached = evaluationCache.get(symbol);
50
+ if (cached) {
51
+ return cached;
52
+ }
53
+ const resolving = empty();
54
+ evaluationCache.set(symbol, resolving);
55
+ const declarations = symbol.getDeclarations()
56
+ ?? [];
57
+ for (const declaration of declarations) {
58
+ if (typescript_1.default.isVariableDeclaration(declaration)
59
+ && declaration.initializer) {
60
+ const resolved = resolveNodeValue(declaration.initializer, checker, context, visited, evaluationCache, undefined, exportCache);
61
+ evaluationCache.set(symbol, resolved);
62
+ return resolved;
63
+ }
64
+ }
65
+ return resolving;
66
+ }
67
+ function resolveCallExpression(node, checker, context, visited, evaluationCache, resolvedCallCache, exportCache) {
68
+ const resolved = (0, callResolver_1.resolveFunctionFromCall)(node.expression, checker, resolvedCallCache
69
+ ?? new resolvedCallCache_1.ResolvedCallCache(), exportCache);
70
+ if (!resolved) {
71
+ return empty();
72
+ }
73
+ const semantic = (0, returnPropagationAnalyzer_1.analyzeReturnPropagation)(resolved);
74
+ if (!semantic) {
75
+ return empty();
76
+ }
77
+ const values = [];
78
+ for (const propagation of semantic.propagations) {
79
+ const argument = node.arguments[propagation.parameterIndex];
80
+ if (!argument) {
81
+ continue;
82
+ }
83
+ const nextContext = {
84
+ parameterBindings: new Map(context.parameterBindings),
85
+ };
86
+ const parameterSymbol = checker.getSymbolAtLocation(propagation.parameter.name);
87
+ if (parameterSymbol) {
88
+ nextContext.parameterBindings.set(parameterSymbol, argument);
89
+ }
90
+ const resolvedValue = resolveNodeValue(propagation.returnExpression, checker, nextContext, new Set(visited), evaluationCache, resolvedCallCache, exportCache);
91
+ values.push(...resolvedValue.values);
92
+ }
93
+ return {
94
+ values: unique(values),
95
+ dynamic: true,
96
+ };
97
+ }
98
+ function resolveNodeValue(node, checker, context, visited, evaluationCache, resolvedCallCache, exportCache) {
99
+ if (visited.has(node)) {
100
+ return empty();
101
+ }
102
+ visited.add(node);
103
+ try {
104
+ if (typescript_1.default.isStringLiteral(node)) {
105
+ return {
106
+ values: [
107
+ node.text,
108
+ ],
109
+ dynamic: false,
110
+ };
111
+ }
112
+ if (typescript_1.default.isIdentifier(node)) {
113
+ return resolveIdentifier(node, checker, context, visited, evaluationCache, exportCache);
114
+ }
115
+ if (typescript_1.default.isBinaryExpression(node)
116
+ && node.operatorToken.kind
117
+ === typescript_1.default.SyntaxKind.PlusToken) {
118
+ const left = resolveNodeValue(node.left, checker, context, visited, evaluationCache, resolvedCallCache, exportCache);
119
+ const right = resolveNodeValue(node.right, checker, context, visited, evaluationCache, resolvedCallCache, exportCache);
120
+ return {
121
+ values: concat(left.values, right.values),
122
+ dynamic: true,
123
+ };
124
+ }
125
+ if (typescript_1.default.isCallExpression(node)) {
126
+ return resolveCallExpression(node, checker, context, visited, evaluationCache, resolvedCallCache, exportCache);
127
+ }
128
+ return empty();
129
+ }
130
+ finally {
131
+ visited.delete(node);
132
+ }
133
+ }
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ // src/analysis/scanner/propagationAnalyzer.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.analyzeWrapperPropagation = analyzeWrapperPropagation;
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ const symbolUtils_1 = require("../../symbols/symbolUtils");
10
+ function extractPropertyPath(expression) {
11
+ const result = [];
12
+ let current = expression;
13
+ while (typescript_1.default.isPropertyAccessExpression(current)) {
14
+ result.unshift(current.name.text);
15
+ current =
16
+ current.expression;
17
+ }
18
+ if (!typescript_1.default.isIdentifier(current)) {
19
+ return null;
20
+ }
21
+ return result;
22
+ }
23
+ function resolveObjectBinding(parameter, pattern, identifier, parentPath) {
24
+ for (const element of pattern.elements) {
25
+ const propertyName = element.propertyName
26
+ && typescript_1.default.isIdentifier(element.propertyName)
27
+ ? element.propertyName.text
28
+ : typescript_1.default.isIdentifier(element.name)
29
+ ? element.name.text
30
+ : null;
31
+ if (!propertyName) {
32
+ continue;
33
+ }
34
+ const nextPath = [
35
+ ...parentPath,
36
+ propertyName,
37
+ ];
38
+ //
39
+ // alias:
40
+ // { event: name }
41
+ //
42
+ if (typescript_1.default.isIdentifier(element.name)) {
43
+ if (element.name.text
44
+ === identifier.text) {
45
+ return {
46
+ parameter,
47
+ propertyPath: nextPath,
48
+ };
49
+ }
50
+ }
51
+ //
52
+ // nested:
53
+ // { meta: { event } }
54
+ //
55
+ if (typescript_1.default.isObjectBindingPattern(element.name)) {
56
+ const nested = resolveObjectBinding(parameter, element.name, identifier, nextPath);
57
+ if (nested) {
58
+ return nested;
59
+ }
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ function resolveParameter(fn, identifier) {
65
+ for (const parameter of fn.parameters) {
66
+ //
67
+ // simple param
68
+ //
69
+ // function x(name)
70
+ //
71
+ if (typescript_1.default.isIdentifier(parameter.name)) {
72
+ if (parameter.name.text
73
+ === identifier.text) {
74
+ return {
75
+ parameter,
76
+ propertyPath: [],
77
+ };
78
+ }
79
+ continue;
80
+ }
81
+ //
82
+ // destructuring
83
+ //
84
+ // function x({ event })
85
+ //
86
+ if (typescript_1.default.isObjectBindingPattern(parameter.name)) {
87
+ const resolved = resolveObjectBinding(parameter, parameter.name, identifier, []);
88
+ if (resolved) {
89
+ return resolved;
90
+ }
91
+ }
92
+ }
93
+ return null;
94
+ }
95
+ function collectPropagations(fn, checker, sinks) {
96
+ const result = [];
97
+ for (const sink of sinks) {
98
+ for (const tracked of sink.trackedArguments) {
99
+ const argument = sink.call.arguments[tracked.index];
100
+ if (!argument) {
101
+ continue;
102
+ }
103
+ //
104
+ // direct parameter
105
+ //
106
+ // track(name)
107
+ // track(props.event)
108
+ //
109
+ if (typescript_1.default.isIdentifier(argument)
110
+ || typescript_1.default.isPropertyAccessExpression(argument)) {
111
+ let identifier = null;
112
+ let propertyPath = [];
113
+ if (typescript_1.default.isIdentifier(argument)) {
114
+ identifier =
115
+ argument;
116
+ }
117
+ else {
118
+ propertyPath =
119
+ extractPropertyPath(argument)
120
+ ?? [];
121
+ let root = argument;
122
+ while (typescript_1.default.isPropertyAccessExpression(root)) {
123
+ root =
124
+ root.expression;
125
+ }
126
+ if (typescript_1.default.isIdentifier(root)) {
127
+ identifier =
128
+ root;
129
+ }
130
+ }
131
+ if (!identifier) {
132
+ continue;
133
+ }
134
+ const parameter = resolveParameter(fn, identifier);
135
+ if (!parameter) {
136
+ continue;
137
+ }
138
+ result.push({
139
+ sourceParameter: parameter.parameter,
140
+ sourceParameterIndex: fn.parameters.indexOf(parameter.parameter),
141
+ propertyPath: [
142
+ ...parameter.propertyPath,
143
+ ...propertyPath,
144
+ ],
145
+ targetNode: argument,
146
+ });
147
+ continue;
148
+ }
149
+ //
150
+ // object literal
151
+ //
152
+ // track({ event: name })
153
+ //
154
+ if (typescript_1.default.isObjectLiteralExpression(argument)) {
155
+ for (const property of argument.properties) {
156
+ if (!typescript_1.default.isPropertyAssignment(property)) {
157
+ continue;
158
+ }
159
+ const initializer = property.initializer;
160
+ if (!typescript_1.default.isIdentifier(initializer)) {
161
+ continue;
162
+ }
163
+ const parameter = resolveParameter(fn, initializer);
164
+ if (!parameter) {
165
+ continue;
166
+ }
167
+ result.push({
168
+ sourceParameter: parameter.parameter,
169
+ sourceParameterIndex: fn.parameters.indexOf(parameter.parameter),
170
+ propertyPath: parameter.propertyPath,
171
+ targetNode: initializer,
172
+ });
173
+ }
174
+ }
175
+ }
176
+ }
177
+ return result;
178
+ }
179
+ function analyzeWrapperPropagation(fn, checker, sinks, wrapperRegistry, resolvedCallCache, exportCache) {
180
+ const symbol = (0, symbolUtils_1.getFunctionSymbol)(fn, checker);
181
+ if (!symbol) {
182
+ return null;
183
+ }
184
+ const propagations = collectPropagations(fn, checker, sinks);
185
+ if (propagations.length === 0) {
186
+ return null;
187
+ }
188
+ return {
189
+ symbol,
190
+ declaration: fn,
191
+ propagations,
192
+ };
193
+ }
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ // src/analysis/scanner/returnPropagationAnalyzer.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.analyzeReturnPropagation = analyzeReturnPropagation;
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ function resolveParameter(fn, identifier) {
10
+ for (const parameter of fn.parameters) {
11
+ if (!typescript_1.default.isIdentifier(parameter.name)) {
12
+ continue;
13
+ }
14
+ if (parameter.name.text
15
+ === identifier.text) {
16
+ return parameter;
17
+ }
18
+ }
19
+ return null;
20
+ }
21
+ function analyzeReturnPropagation(fn) {
22
+ const propagations = [];
23
+ function visit(node) {
24
+ //
25
+ // return value
26
+ //
27
+ if (typescript_1.default.isReturnStatement(node)
28
+ && node.expression) {
29
+ collectExpression(node.expression);
30
+ }
31
+ typescript_1.default.forEachChild(node, visit);
32
+ }
33
+ function collectExpression(expression) {
34
+ //
35
+ // direct return
36
+ // return event
37
+ //
38
+ if (typescript_1.default.isIdentifier(expression)) {
39
+ const parameter = resolveParameter(fn, expression);
40
+ if (!parameter) {
41
+ return;
42
+ }
43
+ propagations.push({
44
+ parameter,
45
+ parameterIndex: fn.parameters.indexOf(parameter),
46
+ returnExpression: expression,
47
+ });
48
+ return;
49
+ }
50
+ //
51
+ // object return
52
+ // return { event }
53
+ //
54
+ if (typescript_1.default.isObjectLiteralExpression(expression)) {
55
+ for (const property of expression.properties) {
56
+ if (!typescript_1.default.isPropertyAssignment(property)) {
57
+ continue;
58
+ }
59
+ const initializer = property.initializer;
60
+ if (!typescript_1.default.isIdentifier(initializer)) {
61
+ continue;
62
+ }
63
+ const parameter = resolveParameter(fn, initializer);
64
+ if (!parameter) {
65
+ continue;
66
+ }
67
+ propagations.push({
68
+ parameter,
69
+ parameterIndex: fn.parameters.indexOf(parameter),
70
+ returnExpression: initializer,
71
+ });
72
+ }
73
+ return;
74
+ }
75
+ //
76
+ // template returns
77
+ //
78
+ if (typescript_1.default.isTemplateExpression(expression)) {
79
+ for (const span of expression.templateSpans) {
80
+ if (!typescript_1.default.isIdentifier(span.expression)) {
81
+ continue;
82
+ }
83
+ const parameter = resolveParameter(fn, span.expression);
84
+ if (!parameter) {
85
+ continue;
86
+ }
87
+ propagations.push({
88
+ parameter,
89
+ parameterIndex: fn.parameters.indexOf(parameter),
90
+ returnExpression: expression,
91
+ });
92
+ }
93
+ }
94
+ }
95
+ if (fn.body) {
96
+ visit(fn.body);
97
+ }
98
+ if (propagations.length === 0) {
99
+ return null;
100
+ }
101
+ return {
102
+ declaration: fn,
103
+ propagations,
104
+ };
105
+ }
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.scanSource = scanSource;
7
+ const typescript_1 = __importDefault(require("typescript"));
8
+ const sinkDetector_1 = require("./sinkDetector");
9
+ const propagationAnalyzer_1 = require("./analyzer/propagationAnalyzer");
10
+ function scanSource(source, checker, _config, resolvedCallCache, resolvedExportCache, wrapperRegistry) {
11
+ const sinks = [];
12
+ const wrappers = [];
13
+ const trackCalls = [];
14
+ const functions = [];
15
+ function visit(node) {
16
+ //
17
+ // imports/exports are irrelevant
18
+ //
19
+ if (typescript_1.default.isImportDeclaration(node)
20
+ || typescript_1.default.isExportDeclaration(node)) {
21
+ return;
22
+ }
23
+ //
24
+ // function collection
25
+ //
26
+ if (typescript_1.default.isFunctionDeclaration(node)
27
+ || typescript_1.default.isArrowFunction(node)
28
+ || typescript_1.default.isFunctionExpression(node)
29
+ || typescript_1.default.isMethodDeclaration(node)) {
30
+ functions.push(node);
31
+ }
32
+ //
33
+ // sink detection
34
+ //
35
+ if (typescript_1.default.isCallExpression(node)) {
36
+ const sink = (0, sinkDetector_1.detectTrackSink)(node);
37
+ if (sink) {
38
+ sinks.push(sink);
39
+ const trackedArguments = sink.trackedArguments
40
+ .map(tracked => {
41
+ const argument = node.arguments[tracked.index];
42
+ if (!argument) {
43
+ return undefined;
44
+ }
45
+ //
46
+ // track({
47
+ // event: name
48
+ // })
49
+ //
50
+ if (tracked.propertyPath
51
+ .length > 0
52
+ && typescript_1.default.isObjectLiteralExpression(argument)) {
53
+ const property = argument.properties
54
+ .find(prop => {
55
+ return (typescript_1.default.isPropertyAssignment(prop)
56
+ && prop.name.getText()
57
+ === tracked
58
+ .propertyPath[0]);
59
+ });
60
+ if (property
61
+ && typescript_1.default.isPropertyAssignment(property)) {
62
+ return property.initializer;
63
+ }
64
+ }
65
+ //
66
+ // track(name)
67
+ //
68
+ return argument;
69
+ })
70
+ .filter((value) => {
71
+ return Boolean(value);
72
+ });
73
+ trackCalls.push({
74
+ node,
75
+ sourceFile: source,
76
+ trackedArguments,
77
+ });
78
+ }
79
+ }
80
+ typescript_1.default.forEachChild(node, visit);
81
+ }
82
+ visit(source);
83
+ //
84
+ // generic semantic analysis
85
+ //
86
+ for (const fn of functions) {
87
+ if (!fn.body) {
88
+ continue;
89
+ }
90
+ const localSinks = sinks.filter(sink => {
91
+ let current = sink.call;
92
+ while (current) {
93
+ if (current === fn) {
94
+ return true;
95
+ }
96
+ current =
97
+ current.parent;
98
+ }
99
+ return false;
100
+ });
101
+ //
102
+ // wrapper propagation
103
+ //
104
+ const wrapper = (0, propagationAnalyzer_1.analyzeWrapperPropagation)(fn, checker, localSinks, wrapperRegistry, resolvedCallCache, resolvedExportCache);
105
+ if (wrapper) {
106
+ wrappers.push(wrapper);
107
+ wrapperRegistry.set(wrapper, checker, resolvedExportCache);
108
+ }
109
+ }
110
+ return {
111
+ fileName: source.fileName,
112
+ sourceFile: source,
113
+ sinks,
114
+ trackCalls,
115
+ wrappers,
116
+ };
117
+ }