@xframework/x 0.4.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.
Files changed (46) hide show
  1. package/.turbo/turbo-build.log +46 -0
  2. package/CHANGELOG.md +7 -0
  3. package/dist/adapter.cjs +50 -0
  4. package/dist/adapter.cjs.map +1 -0
  5. package/dist/adapter.d.cts +2 -0
  6. package/dist/adapter.d.ts +2 -0
  7. package/dist/adapter.js +21 -0
  8. package/dist/adapter.js.map +1 -0
  9. package/dist/core/adapters.cjs +48 -0
  10. package/dist/core/adapters.cjs.map +1 -0
  11. package/dist/core/adapters.d.cts +19 -0
  12. package/dist/core/adapters.d.ts +19 -0
  13. package/dist/core/adapters.js +21 -0
  14. package/dist/core/adapters.js.map +1 -0
  15. package/dist/core/types.cjs +19 -0
  16. package/dist/core/types.cjs.map +1 -0
  17. package/dist/core/types.d.cts +25 -0
  18. package/dist/core/types.d.ts +25 -0
  19. package/dist/core/types.js +1 -0
  20. package/dist/core/types.js.map +1 -0
  21. package/dist/core/x.cjs +134 -0
  22. package/dist/core/x.cjs.map +1 -0
  23. package/dist/core/x.d.cts +17 -0
  24. package/dist/core/x.d.ts +17 -0
  25. package/dist/core/x.js +107 -0
  26. package/dist/core/x.js.map +1 -0
  27. package/dist/index.cjs +134 -0
  28. package/dist/index.cjs.map +1 -0
  29. package/dist/index.d.cts +2 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +107 -0
  32. package/dist/index.js.map +1 -0
  33. package/package.json +33 -0
  34. package/src/__tests__/async-adapter.test.ts +87 -0
  35. package/src/__tests__/composition.test.ts +45 -0
  36. package/src/__tests__/core.test.ts +23 -0
  37. package/src/__tests__/error-handling.test.ts +71 -0
  38. package/src/__tests__/sync-adapter.test.ts +83 -0
  39. package/src/__tests__/type-system.test.ts +78 -0
  40. package/src/adapter.ts +1 -0
  41. package/src/core/adapters.ts +26 -0
  42. package/src/core/types.ts +47 -0
  43. package/src/core/x.ts +163 -0
  44. package/src/index.ts +1 -0
  45. package/tsconfig.json +9 -0
  46. package/tsup.config.ts +3 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/adapters.ts","../../src/core/x.ts"],"sourcesContent":["import type { SyncAdapterType, AsyncAdapterType } from \"./types\";\n\nexport abstract class SyncAdapter<TExport> implements SyncAdapterType<TExport> {\n readonly __type = \"sync\" as const;\n init?(): void;\n abstract export(): TExport;\n}\n\nexport abstract class AsyncAdapter<TExport>\n implements AsyncAdapterType<TExport>\n{\n readonly __type = \"async\" as const;\n init?(): Promise<void>;\n abstract export(): Promise<TExport>;\n}\n\nexport class AdapterError extends Error {\n constructor(\n message: string,\n public readonly adapterName: string,\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"AdapterError\";\n }\n}\n","import { AdapterError } from \"./adapters\";\nimport type {\n SyncAdapterCreator,\n SyncAdapterType,\n AsyncAdapterCreator,\n AsyncAdapterType,\n AdapterRegistry,\n AdapterResult,\n BuildOutput,\n} from \"./types\";\n\ntype AdapterFactory<T extends AdapterRegistry> =\n | [(deps: AdapterResult<T>) => SyncAdapterType<unknown>, false]\n | [(deps: AdapterResult<T>) => Promise<AsyncAdapterType<unknown>>, true];\n\nclass X<\n TAdapters extends AdapterRegistry = Record<string, never>,\n TIsAsync extends boolean = false,\n> {\n constructor(\n private readonly adapterFactories: Record<\n string,\n AdapterFactory<TAdapters>\n > = {} as Record<string, AdapterFactory<TAdapters>>,\n private readonly isAsync: TIsAsync = false as TIsAsync,\n ) {}\n\n syncAdapter<TKey extends string, TExport>(\n name: TKey,\n factory: SyncAdapterCreator<TExport, TAdapters>,\n ): X<TAdapters & Record<TKey, SyncAdapterType<TExport>>, TIsAsync> {\n type NewAdapters = TAdapters & Record<TKey, SyncAdapterType<TExport>>;\n const newFactories = { ...this.adapterFactories };\n // We know this is safe because factory is a SyncAdapterCreator\n (newFactories as Record<string, unknown>)[name] = [\n factory,\n false,\n ] as AdapterFactory<NewAdapters>;\n return new X(\n newFactories as Record<string, AdapterFactory<NewAdapters>>,\n this.isAsync,\n );\n }\n\n asyncAdapter<TKey extends string, TExport>(\n name: TKey,\n factory: AsyncAdapterCreator<TExport, TAdapters>,\n ): X<TAdapters & Record<TKey, AsyncAdapterType<TExport>>, true> {\n type NewAdapters = TAdapters & Record<TKey, AsyncAdapterType<TExport>>;\n const wrappedFactory = async (deps: AdapterResult<TAdapters>) => {\n const result = factory(deps);\n return result instanceof Promise ? await result : result;\n };\n\n const newFactories = { ...this.adapterFactories };\n // We know this is safe because wrappedFactory returns a Promise<AsyncAdapterType>\n (newFactories as Record<string, unknown>)[name] = [\n wrappedFactory,\n true,\n ] as AdapterFactory<NewAdapters>;\n return new X(\n newFactories as Record<string, AdapterFactory<NewAdapters>>,\n true,\n );\n }\n\n use<TOtherAdapters extends AdapterRegistry, TOtherAsync extends boolean>(\n other: X<TOtherAdapters, TOtherAsync>,\n ): X<TAdapters & TOtherAdapters, TIsAsync | TOtherAsync> {\n type CombinedAdapters = TAdapters & TOtherAdapters;\n const newFactories = {\n ...this.adapterFactories,\n ...other[\"adapterFactories\"],\n } as Record<string, AdapterFactory<CombinedAdapters>>;\n return new X(newFactories, this.isAsync || other[\"isAsync\"]);\n }\n\n build(): BuildOutput<TAdapters, TIsAsync> {\n return this.isAsync\n ? (this.buildAsync() as BuildOutput<TAdapters, TIsAsync>)\n : (this.buildSync() as BuildOutput<TAdapters, TIsAsync>);\n }\n\n private buildSync(): AdapterResult<TAdapters> {\n const result = {\n _: { adapters: {} as TAdapters },\n } as AdapterResult<TAdapters>;\n\n for (const [key, [factory, isAsync]] of Object.entries(\n this.adapterFactories,\n )) {\n if (isAsync) {\n throw new AdapterError(\n `Cannot use async adapter \"${key}\" in sync build`,\n key,\n );\n }\n\n const adapter = factory(result) as SyncAdapterType<unknown>;\n\n if (adapter.__type !== \"sync\") {\n throw new AdapterError(\n `Factory returned async adapter \"${key}\" in sync build`,\n key,\n );\n }\n\n (result._.adapters as Record<string, SyncAdapterType<unknown>>)[key] =\n adapter;\n adapter.init?.();\n (result as Record<string, unknown>)[key] = adapter.export();\n }\n\n return result;\n }\n\n private async buildAsync(): Promise<AdapterResult<TAdapters>> {\n const result = {\n _: { adapters: {} as TAdapters },\n } as AdapterResult<TAdapters>;\n\n for (const [key, [factory, isAsync]] of Object.entries(\n this.adapterFactories,\n )) {\n const currentResult = { ...result };\n const adapter = isAsync\n ? await (\n factory as (\n deps: AdapterResult<TAdapters>,\n ) => Promise<AsyncAdapterType<unknown>>\n )(currentResult)\n : (\n factory as (\n deps: AdapterResult<TAdapters>,\n ) => SyncAdapterType<unknown>\n )(currentResult);\n\n (\n result._.adapters as Record<\n string,\n SyncAdapterType<unknown> | AsyncAdapterType<unknown>\n >\n )[key] = adapter;\n\n if (adapter.init) {\n if (adapter.__type === \"async\") {\n await adapter.init();\n } else {\n adapter.init();\n }\n }\n\n (result as Record<string, unknown>)[key] =\n adapter.__type === \"async\" ? await adapter.export() : adapter.export();\n }\n\n return result;\n }\n}\n\nexport function createX() {\n return new X();\n}\n"],"mappings":";AAgBO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACE,SACgB,aACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;ACVA,IAAM,IAAN,MAAM,GAGJ;AAAA,EACA,YACmB,mBAGb,CAAC,GACY,UAAoB,OACrC;AALiB;AAIA;AAAA,EAChB;AAAA,EAEH,YACE,MACA,SACiE;AAEjE,UAAM,eAAe,EAAE,GAAG,KAAK,iBAAiB;AAEhD,IAAC,aAAyC,IAAI,IAAI;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,aACE,MACA,SAC8D;AAE9D,UAAM,iBAAiB,OAAO,SAAmC;AAC/D,YAAM,SAAS,QAAQ,IAAI;AAC3B,aAAO,kBAAkB,UAAU,MAAM,SAAS;AAAA,IACpD;AAEA,UAAM,eAAe,EAAE,GAAG,KAAK,iBAAiB;AAEhD,IAAC,aAAyC,IAAI,IAAI;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IACE,OACuD;AAEvD,UAAM,eAAe;AAAA,MACnB,GAAG,KAAK;AAAA,MACR,GAAG,MAAM,kBAAkB;AAAA,IAC7B;AACA,WAAO,IAAI,GAAE,cAAc,KAAK,WAAW,MAAM,SAAS,CAAC;AAAA,EAC7D;AAAA,EAEA,QAA0C;AACxC,WAAO,KAAK,UACP,KAAK,WAAW,IAChB,KAAK,UAAU;AAAA,EACtB;AAAA,EAEQ,YAAsC;AAC5C,UAAM,SAAS;AAAA,MACb,GAAG,EAAE,UAAU,CAAC,EAAe;AAAA,IACjC;AAEA,eAAW,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,OAAO;AAAA,MAC7C,KAAK;AAAA,IACP,GAAG;AACD,UAAI,SAAS;AACX,cAAM,IAAI;AAAA,UACR,6BAA6B,GAAG;AAAA,UAChC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAU,QAAQ,MAAM;AAE9B,UAAI,QAAQ,WAAW,QAAQ;AAC7B,cAAM,IAAI;AAAA,UACR,mCAAmC,GAAG;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAEA,MAAC,OAAO,EAAE,SAAsD,GAAG,IACjE;AACF,cAAQ,OAAO;AACf,MAAC,OAAmC,GAAG,IAAI,QAAQ,OAAO;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,aAAgD;AAC5D,UAAM,SAAS;AAAA,MACb,GAAG,EAAE,UAAU,CAAC,EAAe;AAAA,IACjC;AAEA,eAAW,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,OAAO;AAAA,MAC7C,KAAK;AAAA,IACP,GAAG;AACD,YAAM,gBAAgB,EAAE,GAAG,OAAO;AAClC,YAAM,UAAU,UACZ,MACE,QAGA,aAAa,IAEb,QAGA,aAAa;AAEnB,MACE,OAAO,EAAE,SAIT,GAAG,IAAI;AAET,UAAI,QAAQ,MAAM;AAChB,YAAI,QAAQ,WAAW,SAAS;AAC9B,gBAAM,QAAQ,KAAK;AAAA,QACrB,OAAO;AACL,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAEA,MAAC,OAAmC,GAAG,IACrC,QAAQ,WAAW,UAAU,MAAM,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAAA,IACzE;AAEA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU;AACxB,SAAO,IAAI,EAAE;AACf;","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createX: () => createX
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/core/adapters.ts
28
+ var AdapterError = class extends Error {
29
+ constructor(message, adapterName, cause) {
30
+ super(message);
31
+ this.adapterName = adapterName;
32
+ this.cause = cause;
33
+ this.name = "AdapterError";
34
+ }
35
+ };
36
+
37
+ // src/core/x.ts
38
+ var X = class _X {
39
+ constructor(adapterFactories = {}, isAsync = false) {
40
+ this.adapterFactories = adapterFactories;
41
+ this.isAsync = isAsync;
42
+ }
43
+ syncAdapter(name, factory) {
44
+ const newFactories = { ...this.adapterFactories };
45
+ newFactories[name] = [
46
+ factory,
47
+ false
48
+ ];
49
+ return new _X(
50
+ newFactories,
51
+ this.isAsync
52
+ );
53
+ }
54
+ asyncAdapter(name, factory) {
55
+ const wrappedFactory = async (deps) => {
56
+ const result = factory(deps);
57
+ return result instanceof Promise ? await result : result;
58
+ };
59
+ const newFactories = { ...this.adapterFactories };
60
+ newFactories[name] = [
61
+ wrappedFactory,
62
+ true
63
+ ];
64
+ return new _X(
65
+ newFactories,
66
+ true
67
+ );
68
+ }
69
+ use(other) {
70
+ const newFactories = {
71
+ ...this.adapterFactories,
72
+ ...other["adapterFactories"]
73
+ };
74
+ return new _X(newFactories, this.isAsync || other["isAsync"]);
75
+ }
76
+ build() {
77
+ return this.isAsync ? this.buildAsync() : this.buildSync();
78
+ }
79
+ buildSync() {
80
+ const result = {
81
+ _: { adapters: {} }
82
+ };
83
+ for (const [key, [factory, isAsync]] of Object.entries(
84
+ this.adapterFactories
85
+ )) {
86
+ if (isAsync) {
87
+ throw new AdapterError(
88
+ `Cannot use async adapter "${key}" in sync build`,
89
+ key
90
+ );
91
+ }
92
+ const adapter = factory(result);
93
+ if (adapter.__type !== "sync") {
94
+ throw new AdapterError(
95
+ `Factory returned async adapter "${key}" in sync build`,
96
+ key
97
+ );
98
+ }
99
+ result._.adapters[key] = adapter;
100
+ adapter.init?.();
101
+ result[key] = adapter.export();
102
+ }
103
+ return result;
104
+ }
105
+ async buildAsync() {
106
+ const result = {
107
+ _: { adapters: {} }
108
+ };
109
+ for (const [key, [factory, isAsync]] of Object.entries(
110
+ this.adapterFactories
111
+ )) {
112
+ const currentResult = { ...result };
113
+ const adapter = isAsync ? await factory(currentResult) : factory(currentResult);
114
+ result._.adapters[key] = adapter;
115
+ if (adapter.init) {
116
+ if (adapter.__type === "async") {
117
+ await adapter.init();
118
+ } else {
119
+ adapter.init();
120
+ }
121
+ }
122
+ result[key] = adapter.__type === "async" ? await adapter.export() : adapter.export();
123
+ }
124
+ return result;
125
+ }
126
+ };
127
+ function createX() {
128
+ return new X();
129
+ }
130
+ // Annotate the CommonJS export names for ESM import in node:
131
+ 0 && (module.exports = {
132
+ createX
133
+ });
134
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/core/adapters.ts","../src/core/x.ts"],"sourcesContent":["export { createX } from \"./core/x\";\n","import type { SyncAdapterType, AsyncAdapterType } from \"./types\";\n\nexport abstract class SyncAdapter<TExport> implements SyncAdapterType<TExport> {\n readonly __type = \"sync\" as const;\n init?(): void;\n abstract export(): TExport;\n}\n\nexport abstract class AsyncAdapter<TExport>\n implements AsyncAdapterType<TExport>\n{\n readonly __type = \"async\" as const;\n init?(): Promise<void>;\n abstract export(): Promise<TExport>;\n}\n\nexport class AdapterError extends Error {\n constructor(\n message: string,\n public readonly adapterName: string,\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"AdapterError\";\n }\n}\n","import { AdapterError } from \"./adapters\";\nimport type {\n SyncAdapterCreator,\n SyncAdapterType,\n AsyncAdapterCreator,\n AsyncAdapterType,\n AdapterRegistry,\n AdapterResult,\n BuildOutput,\n} from \"./types\";\n\ntype AdapterFactory<T extends AdapterRegistry> =\n | [(deps: AdapterResult<T>) => SyncAdapterType<unknown>, false]\n | [(deps: AdapterResult<T>) => Promise<AsyncAdapterType<unknown>>, true];\n\nclass X<\n TAdapters extends AdapterRegistry = Record<string, never>,\n TIsAsync extends boolean = false,\n> {\n constructor(\n private readonly adapterFactories: Record<\n string,\n AdapterFactory<TAdapters>\n > = {} as Record<string, AdapterFactory<TAdapters>>,\n private readonly isAsync: TIsAsync = false as TIsAsync,\n ) {}\n\n syncAdapter<TKey extends string, TExport>(\n name: TKey,\n factory: SyncAdapterCreator<TExport, TAdapters>,\n ): X<TAdapters & Record<TKey, SyncAdapterType<TExport>>, TIsAsync> {\n type NewAdapters = TAdapters & Record<TKey, SyncAdapterType<TExport>>;\n const newFactories = { ...this.adapterFactories };\n // We know this is safe because factory is a SyncAdapterCreator\n (newFactories as Record<string, unknown>)[name] = [\n factory,\n false,\n ] as AdapterFactory<NewAdapters>;\n return new X(\n newFactories as Record<string, AdapterFactory<NewAdapters>>,\n this.isAsync,\n );\n }\n\n asyncAdapter<TKey extends string, TExport>(\n name: TKey,\n factory: AsyncAdapterCreator<TExport, TAdapters>,\n ): X<TAdapters & Record<TKey, AsyncAdapterType<TExport>>, true> {\n type NewAdapters = TAdapters & Record<TKey, AsyncAdapterType<TExport>>;\n const wrappedFactory = async (deps: AdapterResult<TAdapters>) => {\n const result = factory(deps);\n return result instanceof Promise ? await result : result;\n };\n\n const newFactories = { ...this.adapterFactories };\n // We know this is safe because wrappedFactory returns a Promise<AsyncAdapterType>\n (newFactories as Record<string, unknown>)[name] = [\n wrappedFactory,\n true,\n ] as AdapterFactory<NewAdapters>;\n return new X(\n newFactories as Record<string, AdapterFactory<NewAdapters>>,\n true,\n );\n }\n\n use<TOtherAdapters extends AdapterRegistry, TOtherAsync extends boolean>(\n other: X<TOtherAdapters, TOtherAsync>,\n ): X<TAdapters & TOtherAdapters, TIsAsync | TOtherAsync> {\n type CombinedAdapters = TAdapters & TOtherAdapters;\n const newFactories = {\n ...this.adapterFactories,\n ...other[\"adapterFactories\"],\n } as Record<string, AdapterFactory<CombinedAdapters>>;\n return new X(newFactories, this.isAsync || other[\"isAsync\"]);\n }\n\n build(): BuildOutput<TAdapters, TIsAsync> {\n return this.isAsync\n ? (this.buildAsync() as BuildOutput<TAdapters, TIsAsync>)\n : (this.buildSync() as BuildOutput<TAdapters, TIsAsync>);\n }\n\n private buildSync(): AdapterResult<TAdapters> {\n const result = {\n _: { adapters: {} as TAdapters },\n } as AdapterResult<TAdapters>;\n\n for (const [key, [factory, isAsync]] of Object.entries(\n this.adapterFactories,\n )) {\n if (isAsync) {\n throw new AdapterError(\n `Cannot use async adapter \"${key}\" in sync build`,\n key,\n );\n }\n\n const adapter = factory(result) as SyncAdapterType<unknown>;\n\n if (adapter.__type !== \"sync\") {\n throw new AdapterError(\n `Factory returned async adapter \"${key}\" in sync build`,\n key,\n );\n }\n\n (result._.adapters as Record<string, SyncAdapterType<unknown>>)[key] =\n adapter;\n adapter.init?.();\n (result as Record<string, unknown>)[key] = adapter.export();\n }\n\n return result;\n }\n\n private async buildAsync(): Promise<AdapterResult<TAdapters>> {\n const result = {\n _: { adapters: {} as TAdapters },\n } as AdapterResult<TAdapters>;\n\n for (const [key, [factory, isAsync]] of Object.entries(\n this.adapterFactories,\n )) {\n const currentResult = { ...result };\n const adapter = isAsync\n ? await (\n factory as (\n deps: AdapterResult<TAdapters>,\n ) => Promise<AsyncAdapterType<unknown>>\n )(currentResult)\n : (\n factory as (\n deps: AdapterResult<TAdapters>,\n ) => SyncAdapterType<unknown>\n )(currentResult);\n\n (\n result._.adapters as Record<\n string,\n SyncAdapterType<unknown> | AsyncAdapterType<unknown>\n >\n )[key] = adapter;\n\n if (adapter.init) {\n if (adapter.__type === \"async\") {\n await adapter.init();\n } else {\n adapter.init();\n }\n }\n\n (result as Record<string, unknown>)[key] =\n adapter.__type === \"async\" ? await adapter.export() : adapter.export();\n }\n\n return result;\n }\n}\n\nexport function createX() {\n return new X();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACgBO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACE,SACgB,aACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;ACVA,IAAM,IAAN,MAAM,GAGJ;AAAA,EACA,YACmB,mBAGb,CAAC,GACY,UAAoB,OACrC;AALiB;AAIA;AAAA,EAChB;AAAA,EAEH,YACE,MACA,SACiE;AAEjE,UAAM,eAAe,EAAE,GAAG,KAAK,iBAAiB;AAEhD,IAAC,aAAyC,IAAI,IAAI;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,aACE,MACA,SAC8D;AAE9D,UAAM,iBAAiB,OAAO,SAAmC;AAC/D,YAAM,SAAS,QAAQ,IAAI;AAC3B,aAAO,kBAAkB,UAAU,MAAM,SAAS;AAAA,IACpD;AAEA,UAAM,eAAe,EAAE,GAAG,KAAK,iBAAiB;AAEhD,IAAC,aAAyC,IAAI,IAAI;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IACE,OACuD;AAEvD,UAAM,eAAe;AAAA,MACnB,GAAG,KAAK;AAAA,MACR,GAAG,MAAM,kBAAkB;AAAA,IAC7B;AACA,WAAO,IAAI,GAAE,cAAc,KAAK,WAAW,MAAM,SAAS,CAAC;AAAA,EAC7D;AAAA,EAEA,QAA0C;AACxC,WAAO,KAAK,UACP,KAAK,WAAW,IAChB,KAAK,UAAU;AAAA,EACtB;AAAA,EAEQ,YAAsC;AAC5C,UAAM,SAAS;AAAA,MACb,GAAG,EAAE,UAAU,CAAC,EAAe;AAAA,IACjC;AAEA,eAAW,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,OAAO;AAAA,MAC7C,KAAK;AAAA,IACP,GAAG;AACD,UAAI,SAAS;AACX,cAAM,IAAI;AAAA,UACR,6BAA6B,GAAG;AAAA,UAChC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAU,QAAQ,MAAM;AAE9B,UAAI,QAAQ,WAAW,QAAQ;AAC7B,cAAM,IAAI;AAAA,UACR,mCAAmC,GAAG;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAEA,MAAC,OAAO,EAAE,SAAsD,GAAG,IACjE;AACF,cAAQ,OAAO;AACf,MAAC,OAAmC,GAAG,IAAI,QAAQ,OAAO;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,aAAgD;AAC5D,UAAM,SAAS;AAAA,MACb,GAAG,EAAE,UAAU,CAAC,EAAe;AAAA,IACjC;AAEA,eAAW,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,OAAO;AAAA,MAC7C,KAAK;AAAA,IACP,GAAG;AACD,YAAM,gBAAgB,EAAE,GAAG,OAAO;AAClC,YAAM,UAAU,UACZ,MACE,QAGA,aAAa,IAEb,QAGA,aAAa;AAEnB,MACE,OAAO,EAAE,SAIT,GAAG,IAAI;AAET,UAAI,QAAQ,MAAM;AAChB,YAAI,QAAQ,WAAW,SAAS;AAC9B,gBAAM,QAAQ,KAAK;AAAA,QACrB,OAAO;AACL,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAEA,MAAC,OAAmC,GAAG,IACrC,QAAQ,WAAW,UAAU,MAAM,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAAA,IACzE;AAEA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU;AACxB,SAAO,IAAI,EAAE;AACf;","names":[]}
@@ -0,0 +1,2 @@
1
+ export { createX } from './core/x.cjs';
2
+ import './core/types.cjs';
@@ -0,0 +1,2 @@
1
+ export { createX } from './core/x.js';
2
+ import './core/types.js';
package/dist/index.js ADDED
@@ -0,0 +1,107 @@
1
+ // src/core/adapters.ts
2
+ var AdapterError = class extends Error {
3
+ constructor(message, adapterName, cause) {
4
+ super(message);
5
+ this.adapterName = adapterName;
6
+ this.cause = cause;
7
+ this.name = "AdapterError";
8
+ }
9
+ };
10
+
11
+ // src/core/x.ts
12
+ var X = class _X {
13
+ constructor(adapterFactories = {}, isAsync = false) {
14
+ this.adapterFactories = adapterFactories;
15
+ this.isAsync = isAsync;
16
+ }
17
+ syncAdapter(name, factory) {
18
+ const newFactories = { ...this.adapterFactories };
19
+ newFactories[name] = [
20
+ factory,
21
+ false
22
+ ];
23
+ return new _X(
24
+ newFactories,
25
+ this.isAsync
26
+ );
27
+ }
28
+ asyncAdapter(name, factory) {
29
+ const wrappedFactory = async (deps) => {
30
+ const result = factory(deps);
31
+ return result instanceof Promise ? await result : result;
32
+ };
33
+ const newFactories = { ...this.adapterFactories };
34
+ newFactories[name] = [
35
+ wrappedFactory,
36
+ true
37
+ ];
38
+ return new _X(
39
+ newFactories,
40
+ true
41
+ );
42
+ }
43
+ use(other) {
44
+ const newFactories = {
45
+ ...this.adapterFactories,
46
+ ...other["adapterFactories"]
47
+ };
48
+ return new _X(newFactories, this.isAsync || other["isAsync"]);
49
+ }
50
+ build() {
51
+ return this.isAsync ? this.buildAsync() : this.buildSync();
52
+ }
53
+ buildSync() {
54
+ const result = {
55
+ _: { adapters: {} }
56
+ };
57
+ for (const [key, [factory, isAsync]] of Object.entries(
58
+ this.adapterFactories
59
+ )) {
60
+ if (isAsync) {
61
+ throw new AdapterError(
62
+ `Cannot use async adapter "${key}" in sync build`,
63
+ key
64
+ );
65
+ }
66
+ const adapter = factory(result);
67
+ if (adapter.__type !== "sync") {
68
+ throw new AdapterError(
69
+ `Factory returned async adapter "${key}" in sync build`,
70
+ key
71
+ );
72
+ }
73
+ result._.adapters[key] = adapter;
74
+ adapter.init?.();
75
+ result[key] = adapter.export();
76
+ }
77
+ return result;
78
+ }
79
+ async buildAsync() {
80
+ const result = {
81
+ _: { adapters: {} }
82
+ };
83
+ for (const [key, [factory, isAsync]] of Object.entries(
84
+ this.adapterFactories
85
+ )) {
86
+ const currentResult = { ...result };
87
+ const adapter = isAsync ? await factory(currentResult) : factory(currentResult);
88
+ result._.adapters[key] = adapter;
89
+ if (adapter.init) {
90
+ if (adapter.__type === "async") {
91
+ await adapter.init();
92
+ } else {
93
+ adapter.init();
94
+ }
95
+ }
96
+ result[key] = adapter.__type === "async" ? await adapter.export() : adapter.export();
97
+ }
98
+ return result;
99
+ }
100
+ };
101
+ function createX() {
102
+ return new X();
103
+ }
104
+ export {
105
+ createX
106
+ };
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/adapters.ts","../src/core/x.ts"],"sourcesContent":["import type { SyncAdapterType, AsyncAdapterType } from \"./types\";\n\nexport abstract class SyncAdapter<TExport> implements SyncAdapterType<TExport> {\n readonly __type = \"sync\" as const;\n init?(): void;\n abstract export(): TExport;\n}\n\nexport abstract class AsyncAdapter<TExport>\n implements AsyncAdapterType<TExport>\n{\n readonly __type = \"async\" as const;\n init?(): Promise<void>;\n abstract export(): Promise<TExport>;\n}\n\nexport class AdapterError extends Error {\n constructor(\n message: string,\n public readonly adapterName: string,\n public readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"AdapterError\";\n }\n}\n","import { AdapterError } from \"./adapters\";\nimport type {\n SyncAdapterCreator,\n SyncAdapterType,\n AsyncAdapterCreator,\n AsyncAdapterType,\n AdapterRegistry,\n AdapterResult,\n BuildOutput,\n} from \"./types\";\n\ntype AdapterFactory<T extends AdapterRegistry> =\n | [(deps: AdapterResult<T>) => SyncAdapterType<unknown>, false]\n | [(deps: AdapterResult<T>) => Promise<AsyncAdapterType<unknown>>, true];\n\nclass X<\n TAdapters extends AdapterRegistry = Record<string, never>,\n TIsAsync extends boolean = false,\n> {\n constructor(\n private readonly adapterFactories: Record<\n string,\n AdapterFactory<TAdapters>\n > = {} as Record<string, AdapterFactory<TAdapters>>,\n private readonly isAsync: TIsAsync = false as TIsAsync,\n ) {}\n\n syncAdapter<TKey extends string, TExport>(\n name: TKey,\n factory: SyncAdapterCreator<TExport, TAdapters>,\n ): X<TAdapters & Record<TKey, SyncAdapterType<TExport>>, TIsAsync> {\n type NewAdapters = TAdapters & Record<TKey, SyncAdapterType<TExport>>;\n const newFactories = { ...this.adapterFactories };\n // We know this is safe because factory is a SyncAdapterCreator\n (newFactories as Record<string, unknown>)[name] = [\n factory,\n false,\n ] as AdapterFactory<NewAdapters>;\n return new X(\n newFactories as Record<string, AdapterFactory<NewAdapters>>,\n this.isAsync,\n );\n }\n\n asyncAdapter<TKey extends string, TExport>(\n name: TKey,\n factory: AsyncAdapterCreator<TExport, TAdapters>,\n ): X<TAdapters & Record<TKey, AsyncAdapterType<TExport>>, true> {\n type NewAdapters = TAdapters & Record<TKey, AsyncAdapterType<TExport>>;\n const wrappedFactory = async (deps: AdapterResult<TAdapters>) => {\n const result = factory(deps);\n return result instanceof Promise ? await result : result;\n };\n\n const newFactories = { ...this.adapterFactories };\n // We know this is safe because wrappedFactory returns a Promise<AsyncAdapterType>\n (newFactories as Record<string, unknown>)[name] = [\n wrappedFactory,\n true,\n ] as AdapterFactory<NewAdapters>;\n return new X(\n newFactories as Record<string, AdapterFactory<NewAdapters>>,\n true,\n );\n }\n\n use<TOtherAdapters extends AdapterRegistry, TOtherAsync extends boolean>(\n other: X<TOtherAdapters, TOtherAsync>,\n ): X<TAdapters & TOtherAdapters, TIsAsync | TOtherAsync> {\n type CombinedAdapters = TAdapters & TOtherAdapters;\n const newFactories = {\n ...this.adapterFactories,\n ...other[\"adapterFactories\"],\n } as Record<string, AdapterFactory<CombinedAdapters>>;\n return new X(newFactories, this.isAsync || other[\"isAsync\"]);\n }\n\n build(): BuildOutput<TAdapters, TIsAsync> {\n return this.isAsync\n ? (this.buildAsync() as BuildOutput<TAdapters, TIsAsync>)\n : (this.buildSync() as BuildOutput<TAdapters, TIsAsync>);\n }\n\n private buildSync(): AdapterResult<TAdapters> {\n const result = {\n _: { adapters: {} as TAdapters },\n } as AdapterResult<TAdapters>;\n\n for (const [key, [factory, isAsync]] of Object.entries(\n this.adapterFactories,\n )) {\n if (isAsync) {\n throw new AdapterError(\n `Cannot use async adapter \"${key}\" in sync build`,\n key,\n );\n }\n\n const adapter = factory(result) as SyncAdapterType<unknown>;\n\n if (adapter.__type !== \"sync\") {\n throw new AdapterError(\n `Factory returned async adapter \"${key}\" in sync build`,\n key,\n );\n }\n\n (result._.adapters as Record<string, SyncAdapterType<unknown>>)[key] =\n adapter;\n adapter.init?.();\n (result as Record<string, unknown>)[key] = adapter.export();\n }\n\n return result;\n }\n\n private async buildAsync(): Promise<AdapterResult<TAdapters>> {\n const result = {\n _: { adapters: {} as TAdapters },\n } as AdapterResult<TAdapters>;\n\n for (const [key, [factory, isAsync]] of Object.entries(\n this.adapterFactories,\n )) {\n const currentResult = { ...result };\n const adapter = isAsync\n ? await (\n factory as (\n deps: AdapterResult<TAdapters>,\n ) => Promise<AsyncAdapterType<unknown>>\n )(currentResult)\n : (\n factory as (\n deps: AdapterResult<TAdapters>,\n ) => SyncAdapterType<unknown>\n )(currentResult);\n\n (\n result._.adapters as Record<\n string,\n SyncAdapterType<unknown> | AsyncAdapterType<unknown>\n >\n )[key] = adapter;\n\n if (adapter.init) {\n if (adapter.__type === \"async\") {\n await adapter.init();\n } else {\n adapter.init();\n }\n }\n\n (result as Record<string, unknown>)[key] =\n adapter.__type === \"async\" ? await adapter.export() : adapter.export();\n }\n\n return result;\n }\n}\n\nexport function createX() {\n return new X();\n}\n"],"mappings":";AAgBO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACtC,YACE,SACgB,aACA,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;;;ACVA,IAAM,IAAN,MAAM,GAGJ;AAAA,EACA,YACmB,mBAGb,CAAC,GACY,UAAoB,OACrC;AALiB;AAIA;AAAA,EAChB;AAAA,EAEH,YACE,MACA,SACiE;AAEjE,UAAM,eAAe,EAAE,GAAG,KAAK,iBAAiB;AAEhD,IAAC,aAAyC,IAAI,IAAI;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,MACA,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,aACE,MACA,SAC8D;AAE9D,UAAM,iBAAiB,OAAO,SAAmC;AAC/D,YAAM,SAAS,QAAQ,IAAI;AAC3B,aAAO,kBAAkB,UAAU,MAAM,SAAS;AAAA,IACpD;AAEA,UAAM,eAAe,EAAE,GAAG,KAAK,iBAAiB;AAEhD,IAAC,aAAyC,IAAI,IAAI;AAAA,MAChD;AAAA,MACA;AAAA,IACF;AACA,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,IACE,OACuD;AAEvD,UAAM,eAAe;AAAA,MACnB,GAAG,KAAK;AAAA,MACR,GAAG,MAAM,kBAAkB;AAAA,IAC7B;AACA,WAAO,IAAI,GAAE,cAAc,KAAK,WAAW,MAAM,SAAS,CAAC;AAAA,EAC7D;AAAA,EAEA,QAA0C;AACxC,WAAO,KAAK,UACP,KAAK,WAAW,IAChB,KAAK,UAAU;AAAA,EACtB;AAAA,EAEQ,YAAsC;AAC5C,UAAM,SAAS;AAAA,MACb,GAAG,EAAE,UAAU,CAAC,EAAe;AAAA,IACjC;AAEA,eAAW,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,OAAO;AAAA,MAC7C,KAAK;AAAA,IACP,GAAG;AACD,UAAI,SAAS;AACX,cAAM,IAAI;AAAA,UACR,6BAA6B,GAAG;AAAA,UAChC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,UAAU,QAAQ,MAAM;AAE9B,UAAI,QAAQ,WAAW,QAAQ;AAC7B,cAAM,IAAI;AAAA,UACR,mCAAmC,GAAG;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAEA,MAAC,OAAO,EAAE,SAAsD,GAAG,IACjE;AACF,cAAQ,OAAO;AACf,MAAC,OAAmC,GAAG,IAAI,QAAQ,OAAO;AAAA,IAC5D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,aAAgD;AAC5D,UAAM,SAAS;AAAA,MACb,GAAG,EAAE,UAAU,CAAC,EAAe;AAAA,IACjC;AAEA,eAAW,CAAC,KAAK,CAAC,SAAS,OAAO,CAAC,KAAK,OAAO;AAAA,MAC7C,KAAK;AAAA,IACP,GAAG;AACD,YAAM,gBAAgB,EAAE,GAAG,OAAO;AAClC,YAAM,UAAU,UACZ,MACE,QAGA,aAAa,IAEb,QAGA,aAAa;AAEnB,MACE,OAAO,EAAE,SAIT,GAAG,IAAI;AAET,UAAI,QAAQ,MAAM;AAChB,YAAI,QAAQ,WAAW,SAAS;AAC9B,gBAAM,QAAQ,KAAK;AAAA,QACrB,OAAO;AACL,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF;AAEA,MAAC,OAAmC,GAAG,IACrC,QAAQ,WAAW,UAAU,MAAM,QAAQ,OAAO,IAAI,QAAQ,OAAO;AAAA,IACzE;AAEA,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU;AACxB,SAAO,IAAI,EAAE;AACf;","names":[]}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@xframework/x",
3
+ "version": "0.4.0",
4
+ "type": "module",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./dist/index.d.ts",
8
+ "require": "./dist/index.cjs",
9
+ "import": "./dist/index.js"
10
+ },
11
+ "./adapter": {
12
+ "types": "./dist/adapter.d.ts",
13
+ "require": "./dist/adapter.cjs",
14
+ "import": "./dist/adapter.js"
15
+ }
16
+ },
17
+ "main": "./dist/index.cjs",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "devDependencies": {
24
+ "@types/node": "^20.11.24",
25
+ "tsd": "^0.31.2",
26
+ "tsup": "^8.2.4",
27
+ "typescript": "^5.5.4"
28
+ },
29
+ "scripts": {
30
+ "build": "tsup",
31
+ "dev": "tsup --watch"
32
+ }
33
+ }
@@ -0,0 +1,87 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createX } from "..";
3
+ import { AsyncAdapter } from "../adapter";
4
+
5
+ // async-adapter.test.ts
6
+ describe("Async Adapter Tests", () => {
7
+ class TestAsyncAdapter extends AsyncAdapter<string> {
8
+ constructor(private value: string) {
9
+ super();
10
+ }
11
+ async export() {
12
+ return this.value;
13
+ }
14
+ }
15
+
16
+ class InitializableAsyncAdapter extends AsyncAdapter<string> {
17
+ private initialized = false;
18
+
19
+ async init() {
20
+ await new Promise((resolve) => setTimeout(resolve, 10));
21
+ this.initialized = true;
22
+ }
23
+
24
+ async export() {
25
+ return this.initialized ? "initialized" : "not-initialized";
26
+ }
27
+ }
28
+
29
+ class ErrorAsyncAdapter extends AsyncAdapter<never> {
30
+ async init() {
31
+ throw new Error("Async init error");
32
+ }
33
+
34
+ async export(): Promise<never> {
35
+ throw new Error("Async export error");
36
+ }
37
+ }
38
+
39
+ it("should build async adapter chain", async () => {
40
+ const result = await createX()
41
+ .asyncAdapter("test1", () => new TestAsyncAdapter("hello"))
42
+ .asyncAdapter(
43
+ "test2",
44
+ async ({ test1 }) => new TestAsyncAdapter(test1 + " world"),
45
+ )
46
+ .build();
47
+
48
+ expect(result.test1).toBe("hello");
49
+ expect(result.test2).toBe("hello world");
50
+ });
51
+
52
+ it("should call init on async adapters", async () => {
53
+ const result = await createX()
54
+ .asyncAdapter("test", () => new InitializableAsyncAdapter())
55
+ .build();
56
+
57
+ expect(result.test).toBe("initialized");
58
+ });
59
+
60
+ it("should throw on init error in async adapter", async () => {
61
+ await expect(
62
+ createX()
63
+ .asyncAdapter("error", () => new ErrorAsyncAdapter())
64
+ .build(),
65
+ ).rejects.toThrow("Async init error");
66
+ });
67
+
68
+ it("should call init method on async adapter", async () => {
69
+ let initCalled = false;
70
+
71
+ class TestAsyncAdapter extends AsyncAdapter<string> {
72
+ async init() {
73
+ initCalled = true;
74
+ }
75
+
76
+ async export() {
77
+ return "test";
78
+ }
79
+ }
80
+
81
+ await createX()
82
+ .asyncAdapter("test", () => new TestAsyncAdapter())
83
+ .build();
84
+
85
+ expect(initCalled).toBe(true);
86
+ });
87
+ });
@@ -0,0 +1,45 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createX } from "..";
3
+ import { AsyncAdapter, SyncAdapter } from "../adapter";
4
+
5
+ // composition.test.ts
6
+ describe("Adapter Composition Tests", () => {
7
+ class NumberAdapter extends SyncAdapter<number> {
8
+ constructor(private value: number) {
9
+ super();
10
+ }
11
+ export() {
12
+ return this.value;
13
+ }
14
+ }
15
+
16
+ class StringAdapter extends AsyncAdapter<string> {
17
+ constructor(private deps: { number: number }) {
18
+ super();
19
+ }
20
+ async export() {
21
+ return `value: ${this.deps.number}`;
22
+ }
23
+ }
24
+
25
+ it("should compose sync adapters using use()", () => {
26
+ const first = createX().syncAdapter("num1", () => new NumberAdapter(1));
27
+ const second = createX().syncAdapter("num2", () => new NumberAdapter(2));
28
+
29
+ const result = createX().use(first).use(second).build();
30
+
31
+ expect(result.num1).toBe(1);
32
+ expect(result.num2).toBe(2);
33
+ });
34
+
35
+ it("should compose sync and async adapters", async () => {
36
+ const sync = createX().syncAdapter("number", () => new NumberAdapter(42));
37
+ const result = await createX()
38
+ .use(sync)
39
+ .asyncAdapter("string", ({ number }) => new StringAdapter({ number }))
40
+ .build();
41
+
42
+ expect(result.number).toBe(42);
43
+ expect(result.string).toBe("value: 42");
44
+ });
45
+ });
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { AdapterError } from "../core/adapters";
3
+ import { createX } from "..";
4
+
5
+ describe("Core Adapter Functionality", () => {
6
+ it("should create an empty X instance", () => {
7
+ const x = createX();
8
+ expect(x).toBeDefined();
9
+ expect(x.build()).toEqual({ _: { adapters: {} } });
10
+ });
11
+
12
+ it("should throw AdapterError with correct properties", () => {
13
+ const error = new AdapterError(
14
+ "test message",
15
+ "test-adapter",
16
+ new Error("cause"),
17
+ );
18
+ expect(error.message).toBe("test message");
19
+ expect(error.adapterName).toBe("test-adapter");
20
+ expect(error.cause).toBeInstanceOf(Error);
21
+ expect(error.name).toBe("AdapterError");
22
+ });
23
+ });
@@ -0,0 +1,71 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createX } from "..";
3
+ import { AsyncAdapter, SyncAdapter } from "../adapter";
4
+
5
+ // error-handling.test.ts
6
+ describe("Error Handling Tests", () => {
7
+ it("should handle synchronous factory errors", () => {
8
+ expect(() =>
9
+ createX()
10
+ .syncAdapter("error", () => {
11
+ throw new Error("Factory error");
12
+ })
13
+ .build(),
14
+ ).toThrow("Factory error");
15
+ });
16
+
17
+ it("should handle asynchronous factory errors", async () => {
18
+ await expect(
19
+ createX()
20
+ .asyncAdapter("error", async () => {
21
+ throw new Error("Async factory error");
22
+ })
23
+ .build(),
24
+ ).rejects.toThrow("Async factory error");
25
+ });
26
+
27
+ it("should handle export errors in sync adapters", () => {
28
+ class ExportErrorAdapter extends SyncAdapter<never> {
29
+ // @ts-expect-error test
30
+ export() {
31
+ throw new Error("Export error");
32
+ }
33
+ }
34
+
35
+ expect(() =>
36
+ createX()
37
+ .syncAdapter("error", () => new ExportErrorAdapter())
38
+ .build(),
39
+ ).toThrow("Export error");
40
+ });
41
+
42
+ it("should handle export errors in async adapters", async () => {
43
+ class AsyncExportErrorAdapter extends AsyncAdapter<never> {
44
+ // @ts-expect-error test
45
+ export() {
46
+ throw new Error("Async export error");
47
+ }
48
+ }
49
+
50
+ await expect(
51
+ createX()
52
+ .asyncAdapter("error", () => new AsyncExportErrorAdapter())
53
+ .build(),
54
+ ).rejects.toThrow("Async export error");
55
+ });
56
+
57
+ it("should handle async adapter returned in sync context", () => {
58
+ class MismatchedAdapter extends AsyncAdapter<string> {
59
+ export() {
60
+ return "test";
61
+ }
62
+ }
63
+
64
+ expect(() =>
65
+ createX()
66
+ // @ts-expect-error test
67
+ .syncAdapter("error", () => new MismatchedAdapter())
68
+ .build(),
69
+ ).toThrow('Factory returned async adapter "error" in sync build');
70
+ });
71
+ });
@@ -0,0 +1,83 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { createX } from "..";
3
+ import { SyncAdapter } from "../adapter";
4
+ // sync-adapter.test.ts
5
+ describe("Sync Adapter Tests", () => {
6
+ class TestSyncAdapter extends SyncAdapter<number> {
7
+ constructor(private value: number) {
8
+ super();
9
+ }
10
+ export() {
11
+ return this.value;
12
+ }
13
+ }
14
+
15
+ class InitializableSyncAdapter extends SyncAdapter<number> {
16
+ private initialized = false;
17
+
18
+ init() {
19
+ this.initialized = true;
20
+ }
21
+
22
+ export() {
23
+ return this.initialized ? 1 : 0;
24
+ }
25
+ }
26
+
27
+ class ErrorSyncAdapter extends SyncAdapter<never> {
28
+ init() {
29
+ throw new Error("Init error");
30
+ }
31
+
32
+ // @ts-expect-error test
33
+ export() {
34
+ throw new Error("Export error");
35
+ }
36
+ }
37
+
38
+ it("should build sync adapter chain", () => {
39
+ const result = createX()
40
+ .syncAdapter("test1", () => new TestSyncAdapter(1))
41
+ .syncAdapter("test2", ({ test1 }) => new TestSyncAdapter(test1 + 1))
42
+ .build();
43
+
44
+ expect(result.test1).toBe(1);
45
+ expect(result.test2).toBe(2);
46
+ });
47
+
48
+ it("should call init on sync adapters", () => {
49
+ const result = createX()
50
+ .syncAdapter("test", () => new InitializableSyncAdapter())
51
+ .build();
52
+
53
+ expect(result.test).toBe(1);
54
+ });
55
+
56
+ it("should throw on init error in sync adapter", () => {
57
+ expect(() =>
58
+ createX()
59
+ .syncAdapter("error", () => new ErrorSyncAdapter())
60
+ .build(),
61
+ ).toThrow("Init error");
62
+ });
63
+
64
+ it("should call init method on sync adapter", () => {
65
+ let initCalled = false;
66
+
67
+ class TestSyncAdapter extends SyncAdapter<string> {
68
+ init() {
69
+ initCalled = true;
70
+ }
71
+
72
+ export() {
73
+ return "test";
74
+ }
75
+ }
76
+
77
+ createX()
78
+ .syncAdapter("test", () => new TestSyncAdapter())
79
+ .build();
80
+
81
+ expect(initCalled).toBe(true);
82
+ });
83
+ });