@eventcatalog/sdk 0.0.3 → 0.0.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.
@@ -0,0 +1,133 @@
1
+ // src/services.ts
2
+ import matter from "gray-matter";
3
+
4
+ // src/internal/utils.ts
5
+ import { glob } from "glob";
6
+ import fs from "fs/promises";
7
+ import { copy } from "fs-extra";
8
+ import { join } from "path";
9
+ var versionExists = async (catalogDir, id, version) => {
10
+ const files = await getFiles(`${catalogDir}/**/index.md`);
11
+ const matchedFiles = await searchFilesForId(files, id, version) || [];
12
+ return matchedFiles.length > 0;
13
+ };
14
+ var findFileById = async (catalogDir, id, version) => {
15
+ const files = await getFiles(`${catalogDir}/**/index.md`);
16
+ const matchedFiles = await searchFilesForId(files, id) || [];
17
+ if (!version) {
18
+ return matchedFiles.find((path) => !path.includes("versioned"));
19
+ }
20
+ return matchedFiles.find((path) => path.includes(`versioned/${version}`));
21
+ };
22
+ var getFiles = async (pattern) => {
23
+ try {
24
+ const files = await glob(pattern, { ignore: "node_modules/**" });
25
+ return files;
26
+ } catch (error) {
27
+ throw new Error(`Error finding files: ${error}`);
28
+ }
29
+ };
30
+ var searchFilesForId = async (files, id, version) => {
31
+ const idRegex = new RegExp(`^id:\\s*['"]?${id}['"]?\\s*$`, "m");
32
+ const versionRegex = new RegExp(`^version:\\s*['"]?${version}['"]?\\s*$`, "m");
33
+ const matches = await Promise.all(
34
+ files.map(async (file) => {
35
+ const content = await fs.readFile(file, "utf-8");
36
+ const hasIdMatch = content.match(idRegex);
37
+ if (version && !content.match(versionRegex)) {
38
+ return void 0;
39
+ }
40
+ if (hasIdMatch) {
41
+ return file;
42
+ }
43
+ })
44
+ );
45
+ return matches.filter(Boolean).filter((file) => file !== void 0);
46
+ };
47
+ var copyDir = async (catalogDir, source, target, filter) => {
48
+ const tmpDirectory = join(catalogDir, "tmp");
49
+ await fs.mkdir(tmpDirectory, { recursive: true });
50
+ await copy(source, tmpDirectory, {
51
+ overwrite: true,
52
+ filter
53
+ });
54
+ await copy(tmpDirectory, target, {
55
+ overwrite: true,
56
+ filter
57
+ });
58
+ await fs.rm(tmpDirectory, { recursive: true });
59
+ };
60
+
61
+ // src/services.ts
62
+ import fs2 from "fs/promises";
63
+ import { dirname, join as join2 } from "path";
64
+ var getService = (directory) => async (id, version) => {
65
+ const file = await findFileById(directory, id, version);
66
+ if (!file) throw new Error(`No service found for the given id: ${id}` + (version ? ` and version ${version}` : ""));
67
+ const { data, content } = matter.read(file);
68
+ return {
69
+ ...data,
70
+ markdown: content.trim()
71
+ };
72
+ };
73
+ var writeService = (directory) => async (service, options = { path: "" }) => {
74
+ const path = options.path || `/${service.id}`;
75
+ const exists = await versionExists(directory, service.id, service.version);
76
+ if (exists) {
77
+ throw new Error(`Failed to write service as the version ${service.version} already exists`);
78
+ }
79
+ const { markdown, ...frontmatter } = service;
80
+ const document = matter.stringify(markdown.trim(), frontmatter);
81
+ await fs2.mkdir(join2(directory, path), { recursive: true });
82
+ await fs2.writeFile(join2(directory, path, "index.md"), document);
83
+ };
84
+ var versionService = (directory) => async (id) => {
85
+ const files = await getFiles(`${directory}/**/index.md`);
86
+ const matchedFiles = await searchFilesForId(files, id);
87
+ if (matchedFiles.length === 0) {
88
+ throw new Error(`No service found with id: ${id}`);
89
+ }
90
+ const file = matchedFiles[0];
91
+ const eventDirectory = dirname(file);
92
+ const { data: { version = "0.0.1" } = {} } = matter.read(file);
93
+ const targetDirectory = join2(eventDirectory, "versioned", version);
94
+ await fs2.mkdir(targetDirectory, { recursive: true });
95
+ await copyDir(directory, eventDirectory, targetDirectory, (src) => {
96
+ return !src.includes("versioned");
97
+ });
98
+ await fs2.readdir(eventDirectory).then(async (resourceFiles) => {
99
+ await Promise.all(
100
+ resourceFiles.map(async (file2) => {
101
+ if (file2 !== "versioned") {
102
+ await fs2.rm(join2(eventDirectory, file2), { recursive: true });
103
+ }
104
+ })
105
+ );
106
+ });
107
+ };
108
+ var rmService = (directory) => async (path) => {
109
+ await fs2.rm(join2(directory, path), { recursive: true });
110
+ };
111
+ var rmServiceById = (directory) => async (id, version) => {
112
+ const files = await getFiles(`${directory}/**/index.md`);
113
+ const matchedFiles = await searchFilesForId(files, id, version);
114
+ if (matchedFiles.length === 0) {
115
+ throw new Error(`No service found with id: ${id}`);
116
+ }
117
+ await Promise.all(matchedFiles.map((file) => fs2.rm(file)));
118
+ };
119
+ var addFileToService = (directory) => async (id, file, version) => {
120
+ const pathToEvent = await findFileById(directory, id, version);
121
+ if (!pathToEvent) throw new Error("Cannot find directory to write file to");
122
+ const contentDirectory = dirname(pathToEvent);
123
+ await fs2.writeFile(join2(contentDirectory, file.fileName), file.content);
124
+ };
125
+ export {
126
+ addFileToService,
127
+ getService,
128
+ rmService,
129
+ rmServiceById,
130
+ versionService,
131
+ writeService
132
+ };
133
+ //# sourceMappingURL=services.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/services.ts","../src/internal/utils.ts"],"sourcesContent":["import matter from 'gray-matter';\nimport { copyDir, findFileById, getFiles, searchFilesForId, versionExists } from './internal/utils';\nimport type { Service } from './types';\nimport fs from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\n/**\n * Returns a service from EventCatalog.\n *\n * You can optionally specify a version to get a specific version of the service\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { getService } = utils('/path/to/eventcatalog');\n *\n * // Gets the latest version of the event\n * cont event = await getService('InventoryService');\n *\n * // Gets a version of the event\n * cont event = await getService('InventoryService', '0.0.1');\n * ```\n */\nexport const getService =\n (directory: string) =>\n async (id: string, version?: string): Promise<Service> => {\n const file = await findFileById(directory, id, version);\n\n if (!file) throw new Error(`No service found for the given id: ${id}` + (version ? ` and version ${version}` : ''));\n\n const { data, content } = matter.read(file);\n\n return {\n ...data,\n markdown: content.trim(),\n } as Service;\n };\n\n/**\n * Write an event to EventCatalog.\n *\n * You can optionally overide the path of the event.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { writeService } = utils('/path/to/eventcatalog');\n *\n * // Write a service\n * // Event would be written to services/InventoryService\n * await writeService({\n * id: 'InventoryService',\n * name: 'Inventory Service',\n * version: '0.0.1',\n * summary: 'Service that handles the inventory',\n * markdown: '# Hello world',\n * });\n *\n * // Write an event to the catalog but override the path\n * // Event would be written to services/Inventory/InventoryService\n * await writeService({\n * id: 'InventoryService',\n * name: 'Inventory Adjusted',\n * version: '0.0.1',\n * summary: 'This is a summary',\n * markdown: '# Hello world',\n * }, { path: \"/Inventory/InventoryService\"});\n * ```\n */\nexport const writeService =\n (directory: string) =>\n async (service: Service, options: { path: string } = { path: '' }) => {\n // Get the path\n const path = options.path || `/${service.id}`;\n const exists = await versionExists(directory, service.id, service.version);\n\n if (exists) {\n throw new Error(`Failed to write service as the version ${service.version} already exists`);\n }\n\n const { markdown, ...frontmatter } = service;\n const document = matter.stringify(markdown.trim(), frontmatter);\n await fs.mkdir(join(directory, path), { recursive: true });\n await fs.writeFile(join(directory, path, 'index.md'), document);\n };\n\n/**\n * Version a service by it's id.\n *\n * Takes the latest service and moves it to a versioned directory.\n * All files with this service are also versioned. (e.g /services/InventoryService/openapi.yml)\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { versionService } = utils('/path/to/eventcatalog');\n *\n * // moves the latest InventoryService service to a versioned directory\n * // the version within that service is used as the version number.\n * await versionService('InventoryService');\n *\n * ```\n */\nexport const versionService = (directory: string) => async (id: string) => {\n // Find all the events in the directory\n const files = await getFiles(`${directory}/**/index.md`);\n const matchedFiles = await searchFilesForId(files, id);\n\n if (matchedFiles.length === 0) {\n throw new Error(`No service found with id: ${id}`);\n }\n\n // Service that is in the route of the project\n const file = matchedFiles[0];\n const eventDirectory = dirname(file);\n const { data: { version = '0.0.1' } = {} } = matter.read(file);\n const targetDirectory = join(eventDirectory, 'versioned', version);\n\n await fs.mkdir(targetDirectory, { recursive: true });\n\n // Copy the service to the versioned directory\n await copyDir(directory, eventDirectory, targetDirectory, (src) => {\n return !src.includes('versioned');\n });\n\n // Remove all the files in the root of the resource as they have now been versioned\n await fs.readdir(eventDirectory).then(async (resourceFiles) => {\n await Promise.all(\n resourceFiles.map(async (file) => {\n if (file !== 'versioned') {\n await fs.rm(join(eventDirectory, file), { recursive: true });\n }\n })\n );\n });\n};\n\n/**\n * Delete a service at it's given path.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmService } = utils('/path/to/eventcatalog');\n *\n * // Removes the service at services/InventoryService\n * await rmService('/InventoryService');\n * ```\n */\nexport const rmService = (directory: string) => async (path: string) => {\n await fs.rm(join(directory, path), { recursive: true });\n};\n\n/**\n * Delete a service by it's id.\n *\n * Optionally specify a version to delete a specific version of the service.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { rmServiceById } = utils('/path/to/eventcatalog');\n *\n * // deletes the latest InventoryService event\n * await rmServiceById('InventoryService');\n *\n * // deletes a specific version of the InventoryService event\n * await rmServiceById('InventoryService', '0.0.1');\n * ```\n */\nexport const rmServiceById = (directory: string) => async (id: string, version?: string) => {\n // Find all the events in the directory\n const files = await getFiles(`${directory}/**/index.md`);\n\n const matchedFiles = await searchFilesForId(files, id, version);\n\n if (matchedFiles.length === 0) {\n throw new Error(`No service found with id: ${id}`);\n }\n\n await Promise.all(matchedFiles.map((file) => fs.rm(file)));\n};\n\n/**\n * Add a file to a service by it's id.\n *\n * Optionally specify a version to add a file to a specific version of the service.\n *\n * @example\n * ```ts\n * import utils from '@eventcatalog/utils';\n *\n * const { addFileToService } = utils('/path/to/eventcatalog');\n *\n * // adds a file to the latest InventoryService event\n * await addFileToService('InventoryService', { content: 'Hello world', fileName: 'hello.txt' });\n *\n * // adds a file to a specific version of the InventoryService event\n * await addFileToService('InventoryService', { content: 'Hello world', fileName: 'hello.txt' }, '0.0.1');\n *\n * ```\n */\nexport const addFileToService =\n (directory: string) => async (id: string, file: { content: string; fileName: string }, version?: string) => {\n const pathToEvent = await findFileById(directory, id, version);\n if (!pathToEvent) throw new Error('Cannot find directory to write file to');\n const contentDirectory = dirname(pathToEvent);\n await fs.writeFile(join(contentDirectory, file.fileName), file.content);\n };\n","import { glob } from 'glob';\nimport fs from 'node:fs/promises';\nimport { copy, CopyFilterAsync, CopyFilterSync } from 'fs-extra';\nimport { join } from 'node:path';\n\n/**\n * Returns true if a given version of a resource id exists in the catalog\n */\nexport const versionExists = async (catalogDir: string, id: string, version: string) => {\n const files = await getFiles(`${catalogDir}/**/index.md`);\n const matchedFiles = (await searchFilesForId(files, id, version)) || [];\n return matchedFiles.length > 0;\n};\n\nexport const findFileById = async (catalogDir: string, id: string, version?: string): Promise<string | undefined> => {\n const files = await getFiles(`${catalogDir}/**/index.md`);\n const matchedFiles = (await searchFilesForId(files, id)) || [];\n\n // Return the latest one\n if (!version) {\n return matchedFiles.find((path) => !path.includes('versioned'));\n }\n\n // Find the versioned event\n return matchedFiles.find((path) => path.includes(`versioned/${version}`));\n};\n\nexport const getFiles = async (pattern: string) => {\n try {\n const files = await glob(pattern, { ignore: 'node_modules/**' });\n return files;\n } catch (error) {\n throw new Error(`Error finding files: ${error}`);\n }\n};\n\nexport const searchFilesForId = async (files: string[], id: string, version?: string) => {\n const idRegex = new RegExp(`^id:\\\\s*['\"]?${id}['\"]?\\\\s*$`, 'm');\n const versionRegex = new RegExp(`^version:\\\\s*['\"]?${version}['\"]?\\\\s*$`, 'm');\n\n const matches = await Promise.all(\n files.map(async (file) => {\n const content = await fs.readFile(file, 'utf-8');\n const hasIdMatch = content.match(idRegex);\n\n // Check version if provided\n if (version && !content.match(versionRegex)) {\n return undefined;\n }\n\n if (hasIdMatch) {\n return file;\n }\n })\n );\n\n return matches.filter(Boolean).filter((file) => file !== undefined);\n};\n\n/**\n * Function to copy a directory from source to target, uses a tmp directory\n * @param catalogDir\n * @param source\n * @param target\n * @param filter\n */\nexport const copyDir = async (catalogDir: string, source: string, target: string, filter?: CopyFilterAsync | CopyFilterSync) => {\n const tmpDirectory = join(catalogDir, 'tmp');\n await fs.mkdir(tmpDirectory, { recursive: true });\n\n // Copy everything over\n await copy(source, tmpDirectory, {\n overwrite: true,\n filter,\n });\n\n await copy(tmpDirectory, target, {\n overwrite: true,\n filter,\n });\n\n // Remove the tmp directory\n await fs.rm(tmpDirectory, { recursive: true });\n};\n"],"mappings":"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","names":["fs","join","file"]}
@@ -16066,7 +16066,7 @@ var VitestIndex = /* @__PURE__ */ Object.freeze({
16066
16066
  var expectTypeOf = dist.expectTypeOf;
16067
16067
 
16068
16068
  // src/index.ts
16069
- var import_node_path4 = require("path");
16069
+ var import_node_path5 = require("path");
16070
16070
 
16071
16071
  // src/events.ts
16072
16072
  var import_gray_matter = __toESM(require("gray-matter"));
@@ -16197,6 +16197,72 @@ var addSchemaToEvent = (directory) => async (id, schema, version) => {
16197
16197
  await addFileToEvent(directory)(id, { content: schema.schema, fileName: schema.fileName }, version);
16198
16198
  };
16199
16199
 
16200
+ // src/services.ts
16201
+ var import_gray_matter2 = __toESM(require("gray-matter"));
16202
+ var import_promises3 = __toESM(require("fs/promises"));
16203
+ var import_node_path4 = require("path");
16204
+ var getService = (directory) => async (id, version) => {
16205
+ const file = await findFileById(directory, id, version);
16206
+ if (!file) throw new Error(`No service found for the given id: ${id}` + (version ? ` and version ${version}` : ""));
16207
+ const { data, content } = import_gray_matter2.default.read(file);
16208
+ return {
16209
+ ...data,
16210
+ markdown: content.trim()
16211
+ };
16212
+ };
16213
+ var writeService = (directory) => async (service, options = { path: "" }) => {
16214
+ const path3 = options.path || `/${service.id}`;
16215
+ const exists = await versionExists(directory, service.id, service.version);
16216
+ if (exists) {
16217
+ throw new Error(`Failed to write service as the version ${service.version} already exists`);
16218
+ }
16219
+ const { markdown, ...frontmatter } = service;
16220
+ const document = import_gray_matter2.default.stringify(markdown.trim(), frontmatter);
16221
+ await import_promises3.default.mkdir((0, import_node_path4.join)(directory, path3), { recursive: true });
16222
+ await import_promises3.default.writeFile((0, import_node_path4.join)(directory, path3, "index.md"), document);
16223
+ };
16224
+ var versionService = (directory) => async (id) => {
16225
+ const files = await getFiles(`${directory}/**/index.md`);
16226
+ const matchedFiles = await searchFilesForId(files, id);
16227
+ if (matchedFiles.length === 0) {
16228
+ throw new Error(`No service found with id: ${id}`);
16229
+ }
16230
+ const file = matchedFiles[0];
16231
+ const eventDirectory = (0, import_node_path4.dirname)(file);
16232
+ const { data: { version = "0.0.1" } = {} } = import_gray_matter2.default.read(file);
16233
+ const targetDirectory = (0, import_node_path4.join)(eventDirectory, "versioned", version);
16234
+ await import_promises3.default.mkdir(targetDirectory, { recursive: true });
16235
+ await copyDir(directory, eventDirectory, targetDirectory, (src) => {
16236
+ return !src.includes("versioned");
16237
+ });
16238
+ await import_promises3.default.readdir(eventDirectory).then(async (resourceFiles) => {
16239
+ await Promise.all(
16240
+ resourceFiles.map(async (file2) => {
16241
+ if (file2 !== "versioned") {
16242
+ await import_promises3.default.rm((0, import_node_path4.join)(eventDirectory, file2), { recursive: true });
16243
+ }
16244
+ })
16245
+ );
16246
+ });
16247
+ };
16248
+ var rmService = (directory) => async (path3) => {
16249
+ await import_promises3.default.rm((0, import_node_path4.join)(directory, path3), { recursive: true });
16250
+ };
16251
+ var rmServiceById = (directory) => async (id, version) => {
16252
+ const files = await getFiles(`${directory}/**/index.md`);
16253
+ const matchedFiles = await searchFilesForId(files, id, version);
16254
+ if (matchedFiles.length === 0) {
16255
+ throw new Error(`No service found with id: ${id}`);
16256
+ }
16257
+ await Promise.all(matchedFiles.map((file) => import_promises3.default.rm(file)));
16258
+ };
16259
+ var addFileToService = (directory) => async (id, file, version) => {
16260
+ const pathToEvent = await findFileById(directory, id, version);
16261
+ if (!pathToEvent) throw new Error("Cannot find directory to write file to");
16262
+ const contentDirectory = (0, import_node_path4.dirname)(pathToEvent);
16263
+ await import_promises3.default.writeFile((0, import_node_path4.join)(contentDirectory, file.fileName), file.content);
16264
+ };
16265
+
16200
16266
  // src/index.ts
16201
16267
  var src_default = (path3) => {
16202
16268
  return {
@@ -16206,7 +16272,7 @@ var src_default = (path3) => {
16206
16272
  * @param version - Optional id of the version to get
16207
16273
  * @returns
16208
16274
  */
16209
- getEvent: getEvent((0, import_node_path4.join)(path3, "events")),
16275
+ getEvent: getEvent((0, import_node_path5.join)(path3, "events")),
16210
16276
  /**
16211
16277
  * Adds an event to EventCatalog
16212
16278
  *
@@ -16214,26 +16280,26 @@ var src_default = (path3) => {
16214
16280
  * @param options - Optional options to write the event
16215
16281
  *
16216
16282
  */
16217
- writeEvent: writeEvent((0, import_node_path4.join)(path3, "events")),
16283
+ writeEvent: writeEvent((0, import_node_path5.join)(path3, "events")),
16218
16284
  /**
16219
16285
  * Remove an event to EventCatalog (modeled on the standard POSIX rm utility)
16220
16286
  *
16221
16287
  * @param path - The path to your event, e.g. `/Inventory/InventoryAdjusted`
16222
16288
  *
16223
16289
  */
16224
- rmEvent: rmEvent((0, import_node_path4.join)(path3, "events")),
16290
+ rmEvent: rmEvent((0, import_node_path5.join)(path3, "events")),
16225
16291
  /**
16226
16292
  * Remove an event by an Event id
16227
16293
  *
16228
16294
  * @param id - The id of the event you want to remove
16229
16295
  *
16230
16296
  */
16231
- rmEventById: rmEventById((0, import_node_path4.join)(path3, "events")),
16297
+ rmEventById: rmEventById((0, import_node_path5.join)(path3, "events")),
16232
16298
  /**
16233
16299
  * Moves a given event id to the version directory
16234
16300
  * @param directory
16235
16301
  */
16236
- versionEvent: versionEvent((0, import_node_path4.join)(path3, "events")),
16302
+ versionEvent: versionEvent((0, import_node_path5.join)(path3, "events")),
16237
16303
  /**
16238
16304
  * Adds a file to the given event
16239
16305
  * @param id - The id of the event to add the file to
@@ -16241,7 +16307,7 @@ var src_default = (path3) => {
16241
16307
  * @param version - Optional version of the event to add the file to
16242
16308
  * @returns
16243
16309
  */
16244
- addFileToEvent: addFileToEvent((0, import_node_path4.join)(path3, "events")),
16310
+ addFileToEvent: addFileToEvent((0, import_node_path5.join)(path3, "events")),
16245
16311
  /**
16246
16312
  * Adds a schema to the given event
16247
16313
  * @param id - The id of the event to add the schema to
@@ -16249,20 +16315,68 @@ var src_default = (path3) => {
16249
16315
  * @param version - Optional version of the event to add the schema to
16250
16316
  * @returns
16251
16317
  */
16252
- addSchemaToEvent: addSchemaToEvent((0, import_node_path4.join)(path3, "events"))
16318
+ addSchemaToEvent: addSchemaToEvent((0, import_node_path5.join)(path3, "events")),
16319
+ /**
16320
+ * ================================
16321
+ * SERVICES
16322
+ * ================================
16323
+ */
16324
+ /**
16325
+ * Adds a service to EventCatalog
16326
+ *
16327
+ * @param service - The service to write
16328
+ * @param options - Optional options to write the event
16329
+ *
16330
+ */
16331
+ writeService: writeService((0, import_node_path5.join)(path3, "services")),
16332
+ /**
16333
+ * Returns a service from EventCatalog
16334
+ * @param id - The id of the service to retrieve
16335
+ * @param version - Optional id of the version to get
16336
+ * @returns
16337
+ */
16338
+ getService: getService((0, import_node_path5.join)(path3, "services")),
16339
+ /**
16340
+ * Moves a given service id to the version directory
16341
+ * @param directory
16342
+ */
16343
+ versionService: versionService((0, import_node_path5.join)(path3, "services")),
16344
+ /**
16345
+ * Remove a service from EventCatalog (modeled on the standard POSIX rm utility)
16346
+ *
16347
+ * @param path - The path to your service, e.g. `/InventoryService`
16348
+ *
16349
+ */
16350
+ rmService: rmService((0, import_node_path5.join)(path3, "services")),
16351
+ /**
16352
+ * Remove an service by an service id
16353
+ *
16354
+ * @param id - The id of the service you want to remove
16355
+ *
16356
+ */
16357
+ rmServiceById: rmServiceById((0, import_node_path5.join)(path3, "services")),
16358
+ /**
16359
+ * Adds a file to the given service
16360
+ * @param id - The id of the service to add the file to
16361
+ * @param file - File contents to add including the content and the file name
16362
+ * @param version - Optional version of the service to add the file to
16363
+ * @returns
16364
+ */
16365
+ addFileToService: addFileToService((0, import_node_path5.join)(path3, "services"))
16253
16366
  };
16254
16367
  };
16255
16368
 
16256
16369
  // src/test/events.test.ts
16257
- var import_node_path5 = __toESM(require("path"));
16370
+ var import_node_path6 = __toESM(require("path"));
16258
16371
  var import_node_fs = __toESM(require("fs"));
16259
- var CATALOG_PATH = import_node_path5.default.join(__dirname, "catalog");
16372
+ var CATALOG_PATH = import_node_path6.default.join(__dirname, "catalog-events");
16260
16373
  var { writeEvent: writeEvent2, getEvent: getEvent2, rmEvent: rmEvent2, rmEventById: rmEventById2, versionEvent: versionEvent2, addFileToEvent: addFileToEvent2, addSchemaToEvent: addSchemaToEvent2 } = src_default(CATALOG_PATH);
16261
16374
  beforeEach(() => {
16262
16375
  import_node_fs.default.rmSync(CATALOG_PATH, { recursive: true, force: true });
16263
16376
  import_node_fs.default.mkdirSync(CATALOG_PATH, { recursive: true });
16264
16377
  });
16265
16378
  afterEach(() => {
16379
+ import_node_fs.default.rmSync(CATALOG_PATH, { recursive: true, force: true });
16266
16380
  });
16267
16381
  describe("Events SDK", () => {
16268
16382
  describe("getEvent", () => {
@@ -16334,7 +16448,7 @@ describe("Events SDK", () => {
16334
16448
  markdown: "# Hello world"
16335
16449
  });
16336
16450
  const event = await getEvent2("InventoryAdjusted");
16337
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16451
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16338
16452
  globalExpect(event).toEqual({
16339
16453
  id: "InventoryAdjusted",
16340
16454
  name: "Inventory Adjusted",
@@ -16354,7 +16468,7 @@ describe("Events SDK", () => {
16354
16468
  },
16355
16469
  { path: "/Inventory/InventoryAdjusted" }
16356
16470
  );
16357
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/Inventory/InventoryAdjusted", "index.md"))).toBe(true);
16471
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/Inventory/InventoryAdjusted", "index.md"))).toBe(true);
16358
16472
  });
16359
16473
  it("throws an error when trying to write an event that already exists", async () => {
16360
16474
  const createEvent = async () => writeEvent2({
@@ -16385,9 +16499,9 @@ describe("Events SDK", () => {
16385
16499
  summary: "This is a summary",
16386
16500
  markdown: "# Hello world"
16387
16501
  });
16388
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16502
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16389
16503
  await rmEvent2("/InventoryAdjusted");
16390
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16504
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16391
16505
  });
16392
16506
  });
16393
16507
  describe("rmEventById", () => {
@@ -16399,9 +16513,9 @@ describe("Events SDK", () => {
16399
16513
  summary: "This is a summary",
16400
16514
  markdown: "# Hello world"
16401
16515
  });
16402
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16516
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16403
16517
  await rmEventById2("InventoryAdjusted");
16404
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16518
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16405
16519
  });
16406
16520
  it("removes an event from eventcatalog by id and version", async () => {
16407
16521
  await writeEvent2({
@@ -16411,9 +16525,9 @@ describe("Events SDK", () => {
16411
16525
  summary: "This is a summary",
16412
16526
  markdown: "# Hello world"
16413
16527
  });
16414
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16528
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16415
16529
  await rmEventById2("InventoryAdjusted", "0.0.1");
16416
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16530
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16417
16531
  });
16418
16532
  it("if version is given, only removes that version and not any other versions of the event", async () => {
16419
16533
  await writeEvent2({
@@ -16431,11 +16545,11 @@ describe("Events SDK", () => {
16431
16545
  summary: "This is a summary",
16432
16546
  markdown: "# Hello world"
16433
16547
  });
16434
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16435
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.1", "index.md"))).toBe(true);
16548
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16549
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.1", "index.md"))).toBe(true);
16436
16550
  await rmEventById2("InventoryAdjusted", "0.0.1");
16437
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16438
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "index.md"))).toBe(false);
16551
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(true);
16552
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "index.md"))).toBe(false);
16439
16553
  });
16440
16554
  });
16441
16555
  describe("versionEvent", () => {
@@ -16448,8 +16562,8 @@ describe("Events SDK", () => {
16448
16562
  markdown: "# Hello world"
16449
16563
  });
16450
16564
  await versionEvent2("InventoryAdjusted");
16451
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "index.md"))).toBe(true);
16452
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16565
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "index.md"))).toBe(true);
16566
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16453
16567
  });
16454
16568
  it("adds the given event to the versioned directory and all files that are associated to it", async () => {
16455
16569
  await writeEvent2({
@@ -16459,12 +16573,12 @@ describe("Events SDK", () => {
16459
16573
  summary: "This is a summary",
16460
16574
  markdown: "# Hello world"
16461
16575
  });
16462
- await import_node_fs.default.writeFileSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "schema.json"), "SCHEMA!");
16576
+ await import_node_fs.default.writeFileSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "schema.json"), "SCHEMA!");
16463
16577
  await versionEvent2("InventoryAdjusted");
16464
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "index.md"))).toBe(true);
16465
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "schema.json"))).toBe(true);
16466
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16467
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "schema.json"))).toBe(false);
16578
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "index.md"))).toBe(true);
16579
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.2", "schema.json"))).toBe(true);
16580
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "index.md"))).toBe(false);
16581
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "schema.json"))).toBe(false);
16468
16582
  });
16469
16583
  });
16470
16584
  describe("addFileToEvent", () => {
@@ -16478,7 +16592,7 @@ describe("Events SDK", () => {
16478
16592
  markdown: "# Hello world"
16479
16593
  });
16480
16594
  await addFileToEvent2("InventoryAdjusted", file);
16481
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "test.txt"))).toBe(true);
16595
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "test.txt"))).toBe(true);
16482
16596
  });
16483
16597
  it("takes a given file and version and writes the file to the correct location", async () => {
16484
16598
  const file = { content: "hello", fileName: "test.txt" };
@@ -16491,7 +16605,7 @@ describe("Events SDK", () => {
16491
16605
  });
16492
16606
  await versionEvent2("InventoryAdjusted");
16493
16607
  await addFileToEvent2("InventoryAdjusted", file, "0.0.1");
16494
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.1", "test.txt"))).toBe(true);
16608
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.1", "test.txt"))).toBe(true);
16495
16609
  });
16496
16610
  it("throws an error when trying to write to a event that does not exist", () => {
16497
16611
  const file = { content: "hello", fileName: "test.txt" };
@@ -16520,7 +16634,7 @@ describe("Events SDK", () => {
16520
16634
  markdown: "# Hello world"
16521
16635
  });
16522
16636
  await addSchemaToEvent2("InventoryAdjusted", file);
16523
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted", "schema.json"))).toBe(true);
16637
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted", "schema.json"))).toBe(true);
16524
16638
  });
16525
16639
  it("takes a given file and version and writes the file to the correct location", async () => {
16526
16640
  const schema = `{
@@ -16544,7 +16658,7 @@ describe("Events SDK", () => {
16544
16658
  });
16545
16659
  await versionEvent2("InventoryAdjusted");
16546
16660
  await addSchemaToEvent2("InventoryAdjusted", file, "0.0.1");
16547
- globalExpect(import_node_fs.default.existsSync(import_node_path5.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.1", "schema.json"))).toBe(true);
16661
+ globalExpect(import_node_fs.default.existsSync(import_node_path6.default.join(CATALOG_PATH, "events/InventoryAdjusted/versioned/0.0.1", "schema.json"))).toBe(true);
16548
16662
  });
16549
16663
  it("throws an error when trying to write to a event that does not exist", () => {
16550
16664
  const file = { schema: "hello", fileName: "test.txt" };