@rainlanguage/ui-components 0.0.1-alpha.16 → 0.0.1-alpha.17

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.
@@ -15,12 +15,20 @@ let tokenInfo = null;
15
15
  onMount(() => {
16
16
  setCurrentDeposit();
17
17
  });
18
- const setCurrentDeposit = async () => {
18
+ const getCurrentDeposit = () => {
19
+ const deposits = gui.getDeposits();
20
+ if (deposits.error) {
21
+ throw new Error(deposits.error.msg);
22
+ }
23
+ return deposits.value.find((d) => d.token === deposit.token?.key);
24
+ };
25
+ const setCurrentDeposit = () => {
19
26
  try {
20
- currentDeposit = gui.getDeposits().find((d) => d.token === deposit.token?.key);
27
+ currentDeposit = getCurrentDeposit();
21
28
  inputValue = currentDeposit?.amount || "";
22
- } catch {
29
+ } catch (e) {
23
30
  currentDeposit = void 0;
31
+ error = e.message ? e.message : "Error setting current deposit.";
24
32
  }
25
33
  };
26
34
  const getTokenSymbol = async () => {
@@ -41,7 +49,11 @@ function handlePresetClick(preset) {
41
49
  inputValue = preset;
42
50
  gui?.saveDeposit(deposit.token?.key, preset);
43
51
  gui = gui;
44
- currentDeposit = gui?.getDeposits().find((d) => d.token === deposit.token?.key);
52
+ try {
53
+ currentDeposit = getCurrentDeposit();
54
+ } catch (e) {
55
+ error = e.message ? e.message : "Error handling preset click.";
56
+ }
45
57
  }
46
58
  }
47
59
  function handleInput(e) {
@@ -50,7 +62,11 @@ function handleInput(e) {
50
62
  inputValue = e.currentTarget.value;
51
63
  gui?.saveDeposit(deposit.token.key, e.currentTarget.value);
52
64
  gui = gui;
53
- currentDeposit = gui?.getDeposits().find((d) => d.token === deposit.token?.key);
65
+ try {
66
+ currentDeposit = getCurrentDeposit();
67
+ } catch (e2) {
68
+ error = e2.message ? e2.message : "Error handling input.";
69
+ }
54
70
  }
55
71
  }
56
72
  }
@@ -1,2 +1,2 @@
1
- export { fetchParseRegistry, fetchRegistryDotrains } from './registry';
1
+ export { fetchParseRegistry, fetchRegistryDotrains, validateStrategies } from './registry';
2
2
  export type { RegistryDotrain, RegistryFile } from './registry';
@@ -1 +1 @@
1
- export { fetchParseRegistry, fetchRegistryDotrains } from './registry';
1
+ export { fetchParseRegistry, fetchRegistryDotrains, validateStrategies } from './registry';
@@ -1,3 +1,4 @@
1
+ import type { InvalidStrategyDetail, ValidStrategyDetail } from '../types/strategy';
1
2
  export type RegistryFile = {
2
3
  name: string;
3
4
  url: string;
@@ -6,6 +7,10 @@ export type RegistryDotrain = {
6
7
  name: string;
7
8
  dotrain: string;
8
9
  };
10
+ export interface StrategyValidationResult {
11
+ validStrategies: ValidStrategyDetail[];
12
+ invalidStrategies: InvalidStrategyDetail[];
13
+ }
9
14
  /**
10
15
  * Fetches and parses a file registry from a given URL.
11
16
  * The registry is expected to be a text file where each line contains a file name and URL separated by a space.
@@ -23,3 +28,4 @@ export declare const fetchParseRegistry: (url: string) => Promise<{
23
28
  url: string;
24
29
  }[]>;
25
30
  export declare const fetchRegistryDotrains: (url: string) => Promise<RegistryDotrain[]>;
31
+ export declare function validateStrategies(registryDotrains: RegistryDotrain[]): Promise<StrategyValidationResult>;
@@ -1,3 +1,4 @@
1
+ import { DotrainOrderGui } from '@rainlanguage/orderbook/js_api';
1
2
  /**
2
3
  * Fetches and parses a file registry from a given URL.
3
4
  * The registry is expected to be a text file where each line contains a file name and URL separated by a space.
@@ -52,6 +53,40 @@ export const fetchRegistryDotrains = async (url) => {
52
53
  }));
53
54
  return dotrains;
54
55
  };
56
+ export async function validateStrategies(registryDotrains) {
57
+ const strategiesPromises = registryDotrains.map(async (registryDotrain) => {
58
+ try {
59
+ const result = await DotrainOrderGui.getStrategyDetails(registryDotrain.dotrain);
60
+ if (result.error) {
61
+ throw new Error(result.error.msg);
62
+ }
63
+ return {
64
+ valid: true,
65
+ data: {
66
+ ...registryDotrain,
67
+ details: result.value
68
+ }
69
+ };
70
+ }
71
+ catch (error) {
72
+ return {
73
+ valid: false,
74
+ data: {
75
+ name: registryDotrain.name,
76
+ error: error instanceof Error ? error.message : String(error)
77
+ }
78
+ };
79
+ }
80
+ });
81
+ const strategiesResults = await Promise.all(strategiesPromises);
82
+ const validStrategies = strategiesResults
83
+ .filter((result) => result.valid)
84
+ .map((result) => result.data);
85
+ const invalidStrategies = strategiesResults
86
+ .filter((result) => !result.valid)
87
+ .map((result) => result.data);
88
+ return { validStrategies, invalidStrategies };
89
+ }
55
90
  if (import.meta.vitest) {
56
91
  const { describe, it, expect, vi } = import.meta.vitest;
57
92
  describe('getFileRegistry', () => {
@@ -130,4 +165,125 @@ file2.rain https://example.com/file2.rain`;
130
165
  await expect(fetchRegistryDotrains('https://example.com/registry')).rejects.toThrow('Error fetching dotrain for file1.rain: Network error');
131
166
  });
132
167
  });
168
+ describe('validateStrategies', async () => {
169
+ // Mock the DotrainOrderGui dependency
170
+ vi.mock('@rainlanguage/orderbook/js_api', () => ({
171
+ DotrainOrderGui: {
172
+ getStrategyDetails: vi.fn()
173
+ }
174
+ }));
175
+ // Import DotrainOrderGui after mocking
176
+ const { DotrainOrderGui } = await import('@rainlanguage/orderbook/js_api');
177
+ beforeEach(() => {
178
+ vi.resetAllMocks();
179
+ });
180
+ it('should validate strategies and categorize them properly', async () => {
181
+ // Input data
182
+ const registryDotrains = [
183
+ { name: 'valid.rain', dotrain: 'valid dotrain content' },
184
+ { name: 'invalid.rain', dotrain: 'invalid dotrain content' },
185
+ { name: 'another-valid.rain', dotrain: 'another valid content' }
186
+ ];
187
+ // Set up mock responses for the DotrainOrderGui
188
+ DotrainOrderGui.getStrategyDetails
189
+ .mockResolvedValueOnce({
190
+ value: { name: 'Valid Strategy', description: 'A valid strategy' },
191
+ error: null
192
+ })
193
+ .mockResolvedValueOnce({
194
+ error: { msg: 'Invalid syntax' },
195
+ value: null
196
+ })
197
+ .mockResolvedValueOnce({
198
+ value: { name: 'Another Valid', description: 'Another valid strategy' },
199
+ error: null
200
+ });
201
+ // Call the function with our test data
202
+ const result = await validateStrategies(registryDotrains);
203
+ // Verify DotrainOrderGui was called correctly
204
+ expect(DotrainOrderGui.getStrategyDetails).toHaveBeenCalledTimes(3);
205
+ expect(DotrainOrderGui.getStrategyDetails).toHaveBeenCalledWith('valid dotrain content');
206
+ expect(DotrainOrderGui.getStrategyDetails).toHaveBeenCalledWith('invalid dotrain content');
207
+ expect(DotrainOrderGui.getStrategyDetails).toHaveBeenCalledWith('another valid content');
208
+ // Verify the valid strategies are processed correctly
209
+ expect(result.validStrategies).toHaveLength(2);
210
+ expect(result.validStrategies[0].name).toBe('valid.rain');
211
+ expect(result.validStrategies[0].dotrain).toBe('valid dotrain content');
212
+ expect(result.validStrategies[0].details).toEqual({
213
+ name: 'Valid Strategy',
214
+ description: 'A valid strategy'
215
+ });
216
+ // Verify the invalid strategies are processed correctly
217
+ expect(result.invalidStrategies).toHaveLength(1);
218
+ expect(result.invalidStrategies[0].name).toBe('invalid.rain');
219
+ expect(result.invalidStrategies[0].error).toBe('Invalid syntax');
220
+ });
221
+ it('should handle exceptions thrown during strategy validation', async () => {
222
+ // Input data
223
+ const registryDotrains = [{ name: 'error.rain', dotrain: 'will throw error' }];
224
+ // Mock the DotrainOrderGui to throw an exception
225
+ DotrainOrderGui.getStrategyDetails.mockRejectedValueOnce(new Error('Unexpected parsing error'));
226
+ // Call the function
227
+ const result = await validateStrategies(registryDotrains);
228
+ // Verify results
229
+ expect(result.validStrategies).toHaveLength(0);
230
+ expect(result.invalidStrategies).toHaveLength(1);
231
+ expect(result.invalidStrategies[0].name).toBe('error.rain');
232
+ expect(result.invalidStrategies[0].error).toBe('Unexpected parsing error');
233
+ });
234
+ it('should handle non-Error objects being thrown', async () => {
235
+ // Input data
236
+ const registryDotrains = [{ name: 'string-error.rain', dotrain: 'will throw string' }];
237
+ // Mock the DotrainOrderGui to throw a string instead of an Error
238
+ DotrainOrderGui.getStrategyDetails.mockRejectedValueOnce('String error message');
239
+ // Call the function
240
+ const result = await validateStrategies(registryDotrains);
241
+ // Verify results
242
+ expect(result.validStrategies).toHaveLength(0);
243
+ expect(result.invalidStrategies).toHaveLength(1);
244
+ expect(result.invalidStrategies[0].name).toBe('string-error.rain');
245
+ expect(result.invalidStrategies[0].error).toBe('String error message');
246
+ });
247
+ it('should process an empty array of strategies', async () => {
248
+ const result = await validateStrategies([]);
249
+ expect(result.validStrategies).toEqual([]);
250
+ expect(result.invalidStrategies).toEqual([]);
251
+ expect(DotrainOrderGui.getStrategyDetails).not.toHaveBeenCalled();
252
+ });
253
+ it('should handle mixed validation results correctly', async () => {
254
+ // Create a mix of scenarios
255
+ const registryDotrains = [
256
+ { name: 'valid1.rain', dotrain: 'valid content 1' },
257
+ { name: 'error.rain', dotrain: 'will throw error' },
258
+ { name: 'valid2.rain', dotrain: 'valid content 2' },
259
+ { name: 'invalid.rain', dotrain: 'invalid content' }
260
+ ];
261
+ // Set up mock responses
262
+ DotrainOrderGui.getStrategyDetails
263
+ .mockResolvedValueOnce({
264
+ value: { strategyName: 'Strategy 1', description: 'Description 1' },
265
+ error: null
266
+ })
267
+ .mockRejectedValueOnce(new Error('Processing error'))
268
+ .mockResolvedValueOnce({
269
+ value: { strategyName: 'Strategy 2', description: 'Description 2' },
270
+ error: null
271
+ })
272
+ .mockResolvedValueOnce({
273
+ error: { msg: 'Validation failed' },
274
+ value: null
275
+ });
276
+ // Call the function
277
+ const result = await validateStrategies(registryDotrains);
278
+ // Verify results
279
+ expect(result.validStrategies).toHaveLength(2);
280
+ expect(result.validStrategies[0].name).toBe('valid1.rain');
281
+ expect(result.validStrategies[1].name).toBe('valid2.rain');
282
+ expect(result.invalidStrategies).toHaveLength(2);
283
+ expect(result.invalidStrategies[0].name).toBe('error.rain');
284
+ expect(result.invalidStrategies[0].error).toBe('Processing error');
285
+ expect(result.invalidStrategies[1].name).toBe('invalid.rain');
286
+ expect(result.invalidStrategies[1].error).toBe('Validation failed');
287
+ });
288
+ });
133
289
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rainlanguage/ui-components",
3
- "version": "0.0.1-alpha.16",
3
+ "version": "0.0.1-alpha.17",
4
4
  "description": "A component library for building Svelte applications to be used with Raindex.",
5
5
  "license": "LicenseRef-DCL-1.0",
6
6
  "author": "Rain Open Source Software Ltd",
@@ -53,7 +53,7 @@
53
53
  "@fontsource/dm-sans": "^5.0.18",
54
54
  "@imask/svelte": "^7.3.0",
55
55
  "@observablehq/plot": "^0.6.13",
56
- "@rainlanguage/orderbook": "0.0.1-alpha.16",
56
+ "@rainlanguage/orderbook": "0.0.1-alpha.17",
57
57
  "@reown/appkit": "^1.6.4",
58
58
  "@reown/appkit-adapter-wagmi": "^1.6.4",
59
59
  "@sentry/sveltekit": "^7.107.0",