@eventvisor/core 0.14.0 → 0.15.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.
@@ -0,0 +1,89 @@
1
+ import { JSONSchema } from "@eventvisor/types";
2
+
3
+ export function generateInterface(schema: JSONSchema, interfaceName: string): string {
4
+ function generateType(schema: JSONSchema, indent: number = 0): string {
5
+ const indentStr = " ".repeat(indent);
6
+
7
+ // Handle const
8
+ if (schema.const !== undefined) {
9
+ return JSON.stringify(schema.const);
10
+ }
11
+
12
+ // Handle enum
13
+ if (schema.enum && schema.enum.length > 0) {
14
+ const enumValues = schema.enum.map((val) => JSON.stringify(val));
15
+ return enumValues.join(" | ");
16
+ }
17
+
18
+ // Handle array
19
+ if (schema.type === "array") {
20
+ if (schema.items) {
21
+ if (Array.isArray(schema.items)) {
22
+ // Tuple type
23
+ const tupleTypes = schema.items.map((item) => generateType(item, indent));
24
+ return `[${tupleTypes.join(", ")}]`;
25
+ } else {
26
+ // Array type
27
+ const itemType = generateType(schema.items, indent);
28
+ return `${itemType}[]`;
29
+ }
30
+ }
31
+ return "any[]";
32
+ }
33
+
34
+ // Handle object
35
+ if (schema.type === "object" || (schema.properties && !schema.type)) {
36
+ if (!schema.properties || Object.keys(schema.properties).length === 0) {
37
+ return "Record<string, any>";
38
+ }
39
+
40
+ const required = schema.required || [];
41
+ const properties = Object.entries(schema.properties).map(([key, propSchema]) => {
42
+ const isRequired = required.includes(key);
43
+ const optionalMarker = isRequired ? "" : "?";
44
+ const propType = generateType(propSchema, indent + 1);
45
+ return `${indentStr} ${key}${optionalMarker}: ${propType};`;
46
+ });
47
+
48
+ return `{\n${properties.join("\n")}\n${indentStr}}`;
49
+ }
50
+
51
+ // Handle primitives
52
+ switch (schema.type) {
53
+ case "string":
54
+ return "string";
55
+ case "number":
56
+ case "integer":
57
+ return "number";
58
+ case "boolean":
59
+ return "boolean";
60
+ case "null":
61
+ return "null";
62
+ default:
63
+ return "any";
64
+ }
65
+ }
66
+
67
+ const typeDefinition = generateType(schema);
68
+
69
+ // Use 'type' for primitives, arrays, tuples, enums, const, and Record types
70
+ // Use 'interface' for object types with properties
71
+ // Object types have property declarations (contain ': ' or '?: ' followed by type)
72
+ // Const objects are JSON stringified and don't have property declarations
73
+ const trimmed = typeDefinition.trim();
74
+ const isArrayType = trimmed.endsWith("[]");
75
+ const isObjectType =
76
+ !isArrayType &&
77
+ trimmed.startsWith("{") &&
78
+ !trimmed.startsWith('{"') &&
79
+ (trimmed.includes(":\n") ||
80
+ trimmed.includes("?:\n") ||
81
+ trimmed.includes(": ") ||
82
+ trimmed.includes("?: "));
83
+ const declarationType = isObjectType ? "interface" : "type";
84
+ const separator = isObjectType ? " " : " = ";
85
+
86
+ const description = schema.description ? `/** ${schema.description} */\n` : "";
87
+
88
+ return `${description}export ${declarationType} ${interfaceName}${separator}${typeDefinition}`;
89
+ }
@@ -0,0 +1,199 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ import { Dependencies } from "../../dependencies";
5
+ import { generateInterface } from "./generateInterface";
6
+
7
+ export function getInterfaceName(entityName: string, suffix: string = ""): string {
8
+ return (
9
+ entityName
10
+ .replace(/[^a-zA-Z0-9]+/g, " ") // Replace all special characters with spaces
11
+ .split(" ")
12
+ .filter((word) => word.length > 0) // Remove empty strings
13
+ .map((word) => {
14
+ // Check if word already has mixed case (camelCase/PascalCase pattern)
15
+ // This detects if there are both lowercase and uppercase letters in the word
16
+ const hasLowercase = /[a-z]/.test(word);
17
+ const hasUppercase = /[A-Z]/.test(word);
18
+ const hasMixedCase = hasLowercase && hasUppercase;
19
+
20
+ if (hasMixedCase) {
21
+ // Preserve existing casing structure, just ensure first letter is uppercase
22
+ return word.charAt(0).toUpperCase() + word.slice(1);
23
+ }
24
+ // Normal PascalCase transformation for words without mixed case
25
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
26
+ })
27
+ .join("") + suffix
28
+ );
29
+ }
30
+
31
+ export async function generateTypeScriptCodeForProject(deps: Dependencies, outputPath: string) {
32
+ const { datasource } = deps;
33
+
34
+ /**
35
+ * Attributes
36
+ */
37
+ const generatedAttributes: {
38
+ entityName: string;
39
+ interfaceName: string;
40
+ code: string;
41
+ }[] = [];
42
+
43
+ const attributes = await datasource.listAttributes();
44
+ for (const attribute of attributes) {
45
+ const parsedAttribute = await datasource.readAttribute(attribute);
46
+ if (!parsedAttribute) {
47
+ continue;
48
+ }
49
+ const interfaceName = getInterfaceName(attribute, "Attribute");
50
+ const interfaceCode = generateInterface(parsedAttribute, interfaceName);
51
+
52
+ generatedAttributes.push({
53
+ entityName: attribute,
54
+ interfaceName,
55
+ code: interfaceCode,
56
+ });
57
+ }
58
+
59
+ const attributesCodePath = path.resolve(outputPath, "attributes.ts");
60
+ let attributesContent = generatedAttributes
61
+ .map(
62
+ ({ entityName, code }) => `/**
63
+ * ${entityName}
64
+ */
65
+ ${code}
66
+ `,
67
+ )
68
+ .join("\n");
69
+
70
+ const allAttributesContent = `
71
+ /**
72
+ * Attributes
73
+ */
74
+ export interface Attributes {
75
+ ${generatedAttributes.map(({ entityName, interfaceName }) => ` ${entityName}: ${interfaceName};`).join("\n")}
76
+ }
77
+ `;
78
+
79
+ attributesContent += allAttributesContent;
80
+
81
+ fs.writeFileSync(attributesCodePath, attributesContent);
82
+
83
+ /**
84
+ * Events
85
+ */
86
+ const generatedEvents: {
87
+ entityName: string;
88
+ interfaceName: string;
89
+ code: string;
90
+ }[] = [];
91
+
92
+ const events = await datasource.listEvents();
93
+ for (const event of events) {
94
+ const parsedEvent = await datasource.readEvent(event);
95
+ if (!parsedEvent) {
96
+ continue;
97
+ }
98
+ const interfaceName = getInterfaceName(event, "Event");
99
+ const interfaceCode = generateInterface(parsedEvent, interfaceName);
100
+
101
+ generatedEvents.push({
102
+ entityName: event,
103
+ interfaceName,
104
+ code: interfaceCode,
105
+ });
106
+ }
107
+
108
+ const eventsCodePath = path.resolve(outputPath, "events.ts");
109
+ let eventsContent = generatedEvents
110
+ .map(
111
+ ({ entityName, code }) => `/**
112
+ * ${entityName}
113
+ */
114
+ ${code}
115
+ `,
116
+ )
117
+ .join("\n");
118
+
119
+ const allEventsContent = `
120
+ /**
121
+ * Events
122
+ */
123
+ export interface Events {
124
+ ${generatedEvents.map(({ entityName, interfaceName }) => ` ${entityName}: ${interfaceName};`).join("\n")}
125
+ }
126
+ `;
127
+
128
+ eventsContent += allEventsContent;
129
+
130
+ fs.writeFileSync(eventsCodePath, eventsContent);
131
+
132
+ /**
133
+ * Index
134
+ */
135
+ let indexContent = `import type { Eventvisor } from "@eventvisor/sdk";
136
+ import type { Value } from "@eventvisor/types";
137
+
138
+ import type { Events } from "./events";
139
+ import type { Attributes } from "./attributes";
140
+
141
+ /**
142
+ * Instance
143
+ */
144
+ let instance: Eventvisor | null = null;
145
+
146
+ export function setInstance(instance: Eventvisor) {
147
+ instance = instance;
148
+ }
149
+
150
+ /**
151
+ * Event
152
+ */
153
+ type TrackHandler = (eventName: string, payload: Value) => void;
154
+
155
+ let trackHandler: TrackHandler | null = null;
156
+
157
+ export function setTrackHandler(handler: TrackHandler | null) {
158
+ trackHandler = handler;
159
+ }
160
+
161
+ export function track<K extends keyof Events>(eventName: K, payload: Events[K]): void {
162
+ if (instance) {
163
+ instance.track(eventName, payload as unknown as Value);
164
+ }
165
+
166
+ if (trackHandler) {
167
+ trackHandler(eventName, payload as unknown as Value);
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Attribute
173
+ */
174
+
175
+ type SetAttributeHandler = (attributeName: string, value: Value) => void;
176
+
177
+ let setAttributeHandler: SetAttributeHandler | null = null;
178
+
179
+ export function setSetAttributeHandler(handler: SetAttributeHandler | null) {
180
+ setAttributeHandler = handler;
181
+ }
182
+
183
+ export function setAttribute<K extends keyof Attributes>(
184
+ attributeName: K,
185
+ value: Attributes[K],
186
+ ): void {
187
+ if (instance) {
188
+ instance.setAttribute(attributeName, value as unknown as Value);
189
+ }
190
+
191
+ if (setAttributeHandler) {
192
+ setAttributeHandler(attributeName, value as unknown as Value);
193
+ }
194
+ }
195
+ `;
196
+
197
+ const indexCodePath = path.resolve(outputPath, "index.ts");
198
+ fs.writeFileSync(indexCodePath, indexContent);
199
+ }