@eventvisor/core 0.0.2

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 (165) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +9 -0
  3. package/jest.config.js +4 -0
  4. package/lib/builder/buildProject.d.ts +21 -0
  5. package/lib/builder/buildProject.js +153 -0
  6. package/lib/builder/buildProject.js.map +1 -0
  7. package/lib/builder/hashes.d.ts +2 -0
  8. package/lib/builder/hashes.js +59 -0
  9. package/lib/builder/hashes.js.map +1 -0
  10. package/lib/builder/index.d.ts +1 -0
  11. package/lib/builder/index.js +18 -0
  12. package/lib/builder/index.js.map +1 -0
  13. package/lib/cli/cli.d.ts +26 -0
  14. package/lib/cli/cli.js +69 -0
  15. package/lib/cli/cli.js.map +1 -0
  16. package/lib/cli/index.d.ts +1 -0
  17. package/lib/cli/index.js +18 -0
  18. package/lib/cli/index.js.map +1 -0
  19. package/lib/cli/plugins.d.ts +4 -0
  20. package/lib/cli/plugins.js +12 -0
  21. package/lib/cli/plugins.js.map +1 -0
  22. package/lib/config/index.d.ts +2 -0
  23. package/lib/config/index.js +19 -0
  24. package/lib/config/index.js.map +1 -0
  25. package/lib/config/parsers.d.ts +15 -0
  26. package/lib/config/parsers.js +65 -0
  27. package/lib/config/parsers.js.map +1 -0
  28. package/lib/config/projectConfig.d.ts +42 -0
  29. package/lib/config/projectConfig.js +137 -0
  30. package/lib/config/projectConfig.js.map +1 -0
  31. package/lib/datasource/adapter.d.ts +16 -0
  32. package/lib/datasource/adapter.js +7 -0
  33. package/lib/datasource/adapter.js.map +1 -0
  34. package/lib/datasource/datasource.d.ts +48 -0
  35. package/lib/datasource/datasource.js +117 -0
  36. package/lib/datasource/datasource.js.map +1 -0
  37. package/lib/datasource/filesystemAdapter.d.ts +29 -0
  38. package/lib/datasource/filesystemAdapter.js +192 -0
  39. package/lib/datasource/filesystemAdapter.js.map +1 -0
  40. package/lib/datasource/index.d.ts +3 -0
  41. package/lib/datasource/index.js +20 -0
  42. package/lib/datasource/index.js.map +1 -0
  43. package/lib/dependencies.d.ts +11 -0
  44. package/lib/dependencies.js +3 -0
  45. package/lib/dependencies.js.map +1 -0
  46. package/lib/index.d.ts +4 -0
  47. package/lib/index.js +21 -0
  48. package/lib/index.js.map +1 -0
  49. package/lib/index.spec.d.ts +0 -0
  50. package/lib/index.spec.js +6 -0
  51. package/lib/index.spec.js.map +1 -0
  52. package/lib/init/index.d.ts +8 -0
  53. package/lib/init/index.js +90 -0
  54. package/lib/init/index.js.map +1 -0
  55. package/lib/linter/attributeSchema.d.ts +5 -0
  56. package/lib/linter/attributeSchema.js +55 -0
  57. package/lib/linter/attributeSchema.js.map +1 -0
  58. package/lib/linter/conditionsSchema.d.ts +303 -0
  59. package/lib/linter/conditionsSchema.js +106 -0
  60. package/lib/linter/conditionsSchema.js.map +1 -0
  61. package/lib/linter/destinationSchema.d.ts +5 -0
  62. package/lib/linter/destinationSchema.js +57 -0
  63. package/lib/linter/destinationSchema.js.map +1 -0
  64. package/lib/linter/effectSchema.d.ts +1257 -0
  65. package/lib/linter/effectSchema.js +77 -0
  66. package/lib/linter/effectSchema.js.map +1 -0
  67. package/lib/linter/eventSchema.d.ts +5 -0
  68. package/lib/linter/eventSchema.js +70 -0
  69. package/lib/linter/eventSchema.js.map +1 -0
  70. package/lib/linter/index.d.ts +1 -0
  71. package/lib/linter/index.js +18 -0
  72. package/lib/linter/index.js.map +1 -0
  73. package/lib/linter/jsonSchema.d.ts +25 -0
  74. package/lib/linter/jsonSchema.js +487 -0
  75. package/lib/linter/jsonSchema.js.map +1 -0
  76. package/lib/linter/jsonSchema.spec.d.ts +1 -0
  77. package/lib/linter/jsonSchema.spec.js +875 -0
  78. package/lib/linter/jsonSchema.spec.js.map +1 -0
  79. package/lib/linter/lintProject.d.ts +2 -0
  80. package/lib/linter/lintProject.js +141 -0
  81. package/lib/linter/lintProject.js.map +1 -0
  82. package/lib/linter/persistSchema.d.ts +609 -0
  83. package/lib/linter/persistSchema.js +52 -0
  84. package/lib/linter/persistSchema.js.map +1 -0
  85. package/lib/linter/printError.d.ts +9 -0
  86. package/lib/linter/printError.js +75 -0
  87. package/lib/linter/printError.js.map +1 -0
  88. package/lib/linter/sampleSchema.d.ts +331 -0
  89. package/lib/linter/sampleSchema.js +70 -0
  90. package/lib/linter/sampleSchema.js.map +1 -0
  91. package/lib/linter/sourceSchema.d.ts +11 -0
  92. package/lib/linter/sourceSchema.js +73 -0
  93. package/lib/linter/sourceSchema.js.map +1 -0
  94. package/lib/linter/tagsSchema.d.ts +3 -0
  95. package/lib/linter/tagsSchema.js +44 -0
  96. package/lib/linter/tagsSchema.js.map +1 -0
  97. package/lib/linter/testSchema.d.ts +5 -0
  98. package/lib/linter/testSchema.js +44 -0
  99. package/lib/linter/testSchema.js.map +1 -0
  100. package/lib/linter/transformsSchema.d.ts +29 -0
  101. package/lib/linter/transformsSchema.js +66 -0
  102. package/lib/linter/transformsSchema.js.map +1 -0
  103. package/lib/tester/createTestInstance.d.ts +16 -0
  104. package/lib/tester/createTestInstance.js +158 -0
  105. package/lib/tester/createTestInstance.js.map +1 -0
  106. package/lib/tester/executeTest.d.ts +24 -0
  107. package/lib/tester/executeTest.js +305 -0
  108. package/lib/tester/executeTest.js.map +1 -0
  109. package/lib/tester/index.d.ts +1 -0
  110. package/lib/tester/index.js +18 -0
  111. package/lib/tester/index.js.map +1 -0
  112. package/lib/tester/printTestResult.d.ts +10 -0
  113. package/lib/tester/printTestResult.js +80 -0
  114. package/lib/tester/printTestResult.js.map +1 -0
  115. package/lib/tester/testProject.d.ts +12 -0
  116. package/lib/tester/testProject.js +93 -0
  117. package/lib/tester/testProject.js.map +1 -0
  118. package/lib/utils/index.d.ts +1 -0
  119. package/lib/utils/index.js +18 -0
  120. package/lib/utils/index.js.map +1 -0
  121. package/lib/utils/prettyDuration.d.ts +1 -0
  122. package/lib/utils/prettyDuration.js +27 -0
  123. package/lib/utils/prettyDuration.js.map +1 -0
  124. package/package.json +42 -0
  125. package/src/builder/buildProject.ts +222 -0
  126. package/src/builder/hashes.ts +30 -0
  127. package/src/builder/index.ts +1 -0
  128. package/src/cli/cli.ts +110 -0
  129. package/src/cli/index.ts +1 -0
  130. package/src/cli/plugins.ts +13 -0
  131. package/src/config/index.ts +2 -0
  132. package/src/config/parsers.ts +40 -0
  133. package/src/config/projectConfig.ts +158 -0
  134. package/src/datasource/adapter.ts +23 -0
  135. package/src/datasource/datasource.ts +164 -0
  136. package/src/datasource/filesystemAdapter.ts +206 -0
  137. package/src/datasource/index.ts +3 -0
  138. package/src/dependencies.ts +13 -0
  139. package/src/index.spec.ts +5 -0
  140. package/src/index.ts +4 -0
  141. package/src/init/index.ts +65 -0
  142. package/src/linter/attributeSchema.ts +23 -0
  143. package/src/linter/conditionsSchema.ts +89 -0
  144. package/src/linter/destinationSchema.ts +25 -0
  145. package/src/linter/effectSchema.ts +49 -0
  146. package/src/linter/eventSchema.ts +40 -0
  147. package/src/linter/index.ts +1 -0
  148. package/src/linter/jsonSchema.spec.ts +934 -0
  149. package/src/linter/jsonSchema.ts +533 -0
  150. package/src/linter/lintProject.ts +182 -0
  151. package/src/linter/persistSchema.ts +21 -0
  152. package/src/linter/printError.ts +50 -0
  153. package/src/linter/sampleSchema.ts +45 -0
  154. package/src/linter/sourceSchema.ts +42 -0
  155. package/src/linter/tagsSchema.ts +12 -0
  156. package/src/linter/testSchema.ts +9 -0
  157. package/src/linter/transformsSchema.ts +35 -0
  158. package/src/tester/createTestInstance.ts +209 -0
  159. package/src/tester/executeTest.ts +436 -0
  160. package/src/tester/index.ts +1 -0
  161. package/src/tester/printTestResult.ts +60 -0
  162. package/src/tester/testProject.ts +129 -0
  163. package/src/utils/index.ts +1 -0
  164. package/src/utils/prettyDuration.ts +27 -0
  165. package/tsconfig.cjs.json +11 -0
@@ -0,0 +1,21 @@
1
+ import * as z from "zod";
2
+
3
+ import { Dependencies } from "../dependencies";
4
+ import { getConditionsSchema } from "./conditionsSchema";
5
+
6
+ export function getPersistSchema(deps: Dependencies) {
7
+ const conditionsSchema = getConditionsSchema(deps);
8
+
9
+ const simplePersist = z.string();
10
+
11
+ const complexPersist = z.object({
12
+ storage: z.string(),
13
+ conditions: conditionsSchema.optional(),
14
+ });
15
+
16
+ return z.union([
17
+ simplePersist,
18
+ complexPersist,
19
+ z.array(z.union([simplePersist, complexPersist])),
20
+ ]);
21
+ }
@@ -0,0 +1,50 @@
1
+ import * as path from "path";
2
+
3
+ import * as z from "zod";
4
+ import chalk from "chalk";
5
+
6
+ import { ProjectConfig, CustomParser } from "../config";
7
+
8
+ export interface PrintErrorOptions {
9
+ entityType: string;
10
+ entityKey: string;
11
+ error: z.ZodError;
12
+ projectConfig: ProjectConfig;
13
+ }
14
+
15
+ function getFilePath(options: PrintErrorOptions) {
16
+ const { entityType, entityKey, projectConfig } = options;
17
+
18
+ const extension = (projectConfig.parser as CustomParser).extension;
19
+
20
+ let directoryPath = "";
21
+ if (entityType === "event") {
22
+ directoryPath = projectConfig.eventsDirectoryPath;
23
+ } else if (entityType === "attribute") {
24
+ directoryPath = projectConfig.attributesDirectoryPath;
25
+ } else if (entityType === "destination") {
26
+ } else if (entityType === "test") {
27
+ directoryPath = projectConfig.testsDirectoryPath;
28
+ } else {
29
+ throw new Error(`Unknown entity type: ${entityType}`);
30
+ }
31
+
32
+ return path.join(directoryPath, entityKey + "." + extension);
33
+ }
34
+
35
+ function prefixLines(str: string, prefix: string) {
36
+ return str
37
+ .split("\n")
38
+ .map((line) => prefix + line)
39
+ .join("\n");
40
+ }
41
+
42
+ export function printError(options: PrintErrorOptions) {
43
+ const { error } = options;
44
+
45
+ console.log("\n");
46
+
47
+ console.log(chalk.bold.red.underline(getFilePath(options)));
48
+
49
+ console.log(prefixLines(z.prettifyError(error), " "));
50
+ }
@@ -0,0 +1,45 @@
1
+ import * as z from "zod";
2
+
3
+ import { Dependencies } from "../dependencies";
4
+ import { getSourceBaseSchema, getSourceBaseRefine } from "./sourceSchema";
5
+ import { getConditionsSchema } from "./conditionsSchema";
6
+
7
+ export function getSampleSchema(deps: Dependencies) {
8
+ const sampleByString = z.string();
9
+ const sampleBySource = getSourceBaseSchema(deps).refine(...getSourceBaseRefine());
10
+
11
+ const sampleBySingle = z.union([sampleByString, sampleBySource]);
12
+ const sampleByMultiple = z.array(sampleBySingle);
13
+ const sampleByOr = z.object({ or: sampleByMultiple });
14
+
15
+ const sampleBy = z.union([sampleBySingle, sampleByMultiple, sampleByOr]);
16
+
17
+ return z
18
+ .object({
19
+ by: sampleBy,
20
+ conditions: getConditionsSchema(deps).optional(),
21
+
22
+ // one of them below is required
23
+ percentage: z.number().min(0).max(100).optional(),
24
+ range: z.array(z.number().min(0).max(100)).min(2).max(2).optional(),
25
+ })
26
+ .refine(
27
+ (data) => {
28
+ // both missing
29
+ if (data.percentage === undefined && data.range === undefined) {
30
+ return false;
31
+ }
32
+
33
+ // both provided
34
+ if (data.percentage !== undefined && data.range !== undefined) {
35
+ return false;
36
+ }
37
+
38
+ return true;
39
+ },
40
+ {
41
+ message: "Either `percentage` or `range` must be provided",
42
+ path: [],
43
+ },
44
+ );
45
+ }
@@ -0,0 +1,42 @@
1
+ import * as z from "zod";
2
+ import { Dependencies } from "../dependencies";
3
+
4
+ // eslint-disable-next-line
5
+ export function getSourceBaseSchema(deps: Dependencies) {
6
+ const source = z.string();
7
+ const sourceUnion = z.union([source, z.array(source)]);
8
+
9
+ // need .shape API from Zod, so cannot do .union() here
10
+ return z.object({
11
+ // one of them is required
12
+ source: sourceUnion.optional(),
13
+ attribute: sourceUnion.optional(),
14
+ state: sourceUnion.optional(),
15
+ effect: sourceUnion.optional(),
16
+ payload: sourceUnion.optional(),
17
+ lookup: sourceUnion.optional(),
18
+ });
19
+ }
20
+
21
+ const needOneOf = ["source", "attribute", "state", "effect", "payload", "lookup"];
22
+
23
+ // @TODO: make return type better
24
+ export function getSourceBaseRefine(): [any, any] {
25
+ return [
26
+ (data) => {
27
+ const keys = Object.keys(data);
28
+
29
+ for (const key of keys) {
30
+ if (needOneOf.includes(key)) {
31
+ return true;
32
+ }
33
+ }
34
+
35
+ return false;
36
+ },
37
+ {
38
+ message: "At least one source is required",
39
+ path: [],
40
+ },
41
+ ];
42
+ }
@@ -0,0 +1,12 @@
1
+ import * as z from "zod";
2
+ import { Dependencies } from "../dependencies";
3
+
4
+ export function getTagsSchema(deps: Dependencies) {
5
+ const { projectConfig } = deps;
6
+
7
+ return z.array(
8
+ z.string().refine((tag) => projectConfig.tags.indexOf(tag) > -1, {
9
+ message: `Tag must be one of: ${projectConfig.tags.join(", ")}`,
10
+ }),
11
+ );
12
+ }
@@ -0,0 +1,9 @@
1
+ import * as z from "zod";
2
+ import { Dependencies } from "../dependencies";
3
+
4
+ // eslint-disable-next-line
5
+ export function getTestSchema(deps: Dependencies) {
6
+ return z.object({
7
+ archived: z.boolean().optional(),
8
+ });
9
+ }
@@ -0,0 +1,35 @@
1
+ import * as z from "zod";
2
+
3
+ import { Dependencies } from "../dependencies";
4
+ import { getSourceBaseSchema } from "./sourceSchema";
5
+
6
+ export function getTransformsSchema(deps: Dependencies) {
7
+ return z.array(
8
+ z.object({
9
+ // .refine() is intentionally not called here for now, since not all transforms need sources
10
+ // @TODO: make it stricter based on transform types
11
+ ...getSourceBaseSchema(deps).shape,
12
+ type: z.enum([
13
+ "increment",
14
+ "decrement",
15
+ "concat", // @TODO: rename to `join`?
16
+ "remove",
17
+ "rename",
18
+ "set",
19
+ "trim",
20
+ "toInteger",
21
+ "toDouble",
22
+ "toString",
23
+ "toBoolean",
24
+ "spread",
25
+ "append",
26
+ ]),
27
+ target: z.string().optional(),
28
+ targetMap: z.record(z.string(), z.any()).optional(),
29
+ value: z.any().optional(),
30
+
31
+ // transform type specific params
32
+ separator: z.string().optional(),
33
+ }), // do NOT call .strict() here
34
+ );
35
+ }
@@ -0,0 +1,209 @@
1
+ import type { DatafileContent, WithLookups, Value, Step } from "@eventvisor/types";
2
+
3
+ import { Eventvisor, LogLevel, getComplexPersists } from "@eventvisor/sdk";
4
+ import type { Module } from "@eventvisor/sdk";
5
+
6
+ import type { TestProjectOptions } from "./testProject";
7
+
8
+ export interface CreateTestInstanceResult {
9
+ e: Eventvisor;
10
+ getBodiesByDestination: () => Record<string, Value[]>;
11
+ getBodiesBySingleDestination: (destinationName: string) => Value[] | undefined;
12
+ getCalledStepsByEffect: () => Record<string, Step[]>;
13
+ getCalledStepsBySingleEffect: (effectName: string) => Step[] | undefined;
14
+ }
15
+
16
+ export interface CreateTestInstanceOptions {
17
+ datafile: DatafileContent;
18
+ cliOptions: TestProjectOptions;
19
+ withLookups?: WithLookups;
20
+ }
21
+
22
+ export function createTestInstance(options: CreateTestInstanceOptions): CreateTestInstanceResult {
23
+ const { datafile, cliOptions, withLookups } = options;
24
+
25
+ /**
26
+ * Log level
27
+ */
28
+ let logLevel: LogLevel = "error";
29
+
30
+ if (cliOptions.verbose) {
31
+ logLevel = "debug";
32
+ } else if (cliOptions.quiet) {
33
+ logLevel = "fatal";
34
+ }
35
+
36
+ /**
37
+ * Transport names
38
+ */
39
+ const transportNames = new Set<string>();
40
+ const destinationNames = Object.keys(datafile.destinations);
41
+ for (const destinationName of destinationNames) {
42
+ const destination = datafile.destinations[destinationName];
43
+ if (destination.transport) {
44
+ transportNames.add(destination.transport);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Storage names
50
+ */
51
+ const storageNames = new Set<string>();
52
+
53
+ const attributes = Object.keys(datafile.attributes);
54
+ for (const attributeName of attributes) {
55
+ const attribute = datafile.attributes[attributeName];
56
+ if (attribute.persist) {
57
+ const persists = getComplexPersists(attribute.persist);
58
+
59
+ for (const persist of persists) {
60
+ storageNames.add(persist.storage);
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Handler names
67
+ */
68
+ const handlerNames = new Set<string>();
69
+
70
+ const effects = Object.keys(datafile.effects);
71
+ for (const effectName of effects) {
72
+ const effect = datafile.effects[effectName];
73
+
74
+ // handler
75
+ if (effect.steps) {
76
+ for (const step of effect.steps) {
77
+ if (step.handler) {
78
+ handlerNames.add(step.handler);
79
+ }
80
+ }
81
+ }
82
+
83
+ // storage
84
+ if (effect.persist) {
85
+ const persists = getComplexPersists(effect.persist);
86
+
87
+ for (const persist of persists) {
88
+ storageNames.add(persist.storage);
89
+ }
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Modules
95
+ */
96
+ const modules: Module[] = [];
97
+ const bodiesByDestination: Record<string, any[]> = {};
98
+ const calledStepsByEffect: Record<string, Step[]> = {};
99
+
100
+ const lookupsMap = {};
101
+ for (const [key, value] of Object.entries(withLookups || {})) {
102
+ const [moduleName, ...keyParts] = key.split(".");
103
+ const lookupKey = keyParts.join(".");
104
+ if (typeof lookupsMap[moduleName] === "undefined") {
105
+ lookupsMap[moduleName] = {};
106
+ }
107
+ lookupsMap[moduleName][lookupKey] = value;
108
+ }
109
+
110
+ const allModuleNames = Array.from(handlerNames)
111
+ .concat(Array.from(transportNames))
112
+ .concat(Object.keys(lookupsMap))
113
+ .concat(Array.from(storageNames));
114
+
115
+ for (const moduleName of allModuleNames) {
116
+ const moduleObj: Module = { name: moduleName };
117
+
118
+ // transport
119
+ if (transportNames.has(moduleName)) {
120
+ moduleObj.transport = (options) => {
121
+ const { destinationName, payload } = options;
122
+
123
+ if (typeof bodiesByDestination[destinationName] === "undefined") {
124
+ bodiesByDestination[destinationName] = [];
125
+ }
126
+
127
+ bodiesByDestination[destinationName].push(payload);
128
+
129
+ return Promise.resolve();
130
+ };
131
+ }
132
+
133
+ // storage
134
+ if (storageNames.has(moduleName)) {
135
+ const storageData = {};
136
+
137
+ moduleObj.readFromStorage = (options) => {
138
+ const { key } = options;
139
+
140
+ return Promise.resolve(storageData[key]);
141
+ };
142
+
143
+ moduleObj.writeToStorage = (options) => {
144
+ const { key, value } = options;
145
+
146
+ storageData[key] = value;
147
+
148
+ return Promise.resolve();
149
+ };
150
+ }
151
+
152
+ // handler
153
+ if (handlerNames.has(moduleName)) {
154
+ moduleObj.handle = (options) => {
155
+ const { effectName, step } = options;
156
+
157
+ if (typeof calledStepsByEffect[effectName] === "undefined") {
158
+ calledStepsByEffect[effectName] = [];
159
+ }
160
+
161
+ calledStepsByEffect[effectName].push(step);
162
+
163
+ return Promise.resolve();
164
+ };
165
+ }
166
+
167
+ // lookup
168
+ Object.keys(lookupsMap).forEach((moduleName) => {
169
+ if (moduleName === moduleObj.name) {
170
+ moduleObj.lookup = (options) => {
171
+ const { key } = options;
172
+
173
+ return Promise.resolve(lookupsMap[moduleName][key]);
174
+ };
175
+ }
176
+ });
177
+
178
+ modules.push(moduleObj);
179
+ }
180
+
181
+ /**
182
+ * Instance
183
+ */
184
+ const e = new Eventvisor({
185
+ datafile,
186
+ logLevel,
187
+ modules,
188
+ });
189
+
190
+ return {
191
+ e,
192
+
193
+ // destinations
194
+ getBodiesByDestination: () => {
195
+ return bodiesByDestination;
196
+ },
197
+ getBodiesBySingleDestination: (destinationName: string) => {
198
+ return bodiesByDestination[destinationName];
199
+ },
200
+
201
+ // effects
202
+ getCalledStepsByEffect: () => {
203
+ return calledStepsByEffect;
204
+ },
205
+ getCalledStepsBySingleEffect: (effectName: string) => {
206
+ return calledStepsByEffect[effectName];
207
+ },
208
+ };
209
+ }