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

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.
@@ -1,5 +1,5 @@
1
1
  <script>import { Alert } from "flowbite-svelte";
2
- import TokenIOSection from "./TokenIOSection.svelte";
2
+ import TokenIOInput from "./TokenIOInput.svelte";
3
3
  import DepositsSection from "./DepositsSection.svelte";
4
4
  import ComposedRainlangModal from "./ComposedRainlangModal.svelte";
5
5
  import FieldDefinitionsSection from "./FieldDefinitionsSection.svelte";
@@ -47,8 +47,16 @@ onMount(async () => {
47
47
  });
48
48
  function getAllFieldDefinitions() {
49
49
  try {
50
- allFieldDefinitionsWithoutDefaults = gui.getAllFieldDefinitions(false);
51
- allFieldDefinitionsWithDefaults = gui.getAllFieldDefinitions(true);
50
+ const allFieldDefinitionsResult = gui.getAllFieldDefinitions(false);
51
+ if (allFieldDefinitionsResult.error) {
52
+ throw new Error(allFieldDefinitionsResult.error.msg);
53
+ }
54
+ allFieldDefinitionsWithoutDefaults = allFieldDefinitionsResult.value;
55
+ const allFieldDefinitionsWithDefaultsResult = gui.getAllFieldDefinitions(true);
56
+ if (allFieldDefinitionsWithDefaultsResult.error) {
57
+ throw new Error(allFieldDefinitionsWithDefaultsResult.error.msg);
58
+ }
59
+ allFieldDefinitionsWithDefaults = allFieldDefinitionsWithDefaultsResult.value;
52
60
  } catch (e) {
53
61
  DeploymentStepsError.catch(e, DeploymentStepsErrorCode.NO_FIELD_DEFINITIONS);
54
62
  }
@@ -240,8 +248,14 @@ const areAllTokensSelected = async () => {
240
248
  <DepositsSection bind:allDepositFields {gui} />
241
249
  {/if}
242
250
 
243
- {#if allTokenInputs.length > 0 && allTokenOutputs.length > 0 && showAdvancedOptions}
244
- <TokenIOSection bind:allTokenInputs bind:allTokenOutputs {gui} />
251
+ {#if showAdvancedOptions}
252
+ {#each allTokenInputs as input, i}
253
+ <TokenIOInput {i} label="Input" vault={input} {gui} />
254
+ {/each}
255
+
256
+ {#each allTokenOutputs as output, i}
257
+ <TokenIOInput {i} label="Output" vault={output} {gui} />
258
+ {/each}
245
259
  {/if}
246
260
 
247
261
  {#if $deploymentStepsError}
@@ -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
  }
@@ -11,7 +11,11 @@ let currentValue;
11
11
  let inputValue = currentValue?.value ? currentValue?.value : fieldDefinition.default || null;
12
12
  onMount(() => {
13
13
  try {
14
- currentValue = gui.getFieldValue(fieldDefinition.binding);
14
+ const result = gui.getFieldValue(fieldDefinition.binding);
15
+ if (result.error) {
16
+ throw new Error(result.error.msg);
17
+ }
18
+ currentValue = result.value;
15
19
  inputValue = currentValue?.value ? currentValue?.value : fieldDefinition.default || null;
16
20
  } catch {
17
21
  currentValue = void 0;
@@ -23,7 +27,11 @@ async function handlePresetClick(preset) {
23
27
  isPreset: true,
24
28
  value: preset.id
25
29
  });
26
- currentValue = gui.getFieldValue(fieldDefinition.binding);
30
+ const result = gui.getFieldValue(fieldDefinition.binding);
31
+ if (result.error) {
32
+ throw new Error(result.error.msg);
33
+ }
34
+ currentValue = result.value;
27
35
  }
28
36
  async function handleCustomInputChange(value) {
29
37
  inputValue = value;
@@ -31,7 +39,11 @@ async function handleCustomInputChange(value) {
31
39
  isPreset: false,
32
40
  value
33
41
  });
34
- currentValue = gui.getFieldValue(fieldDefinition.binding);
42
+ const result = gui.getFieldValue(fieldDefinition.binding);
43
+ if (result.error) {
44
+ throw new Error(result.error.msg);
45
+ }
46
+ currentValue = result.value;
35
47
  }
36
48
  </script>
37
49
 
@@ -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.18",
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.18",
57
57
  "@reown/appkit": "^1.6.4",
58
58
  "@reown/appkit-adapter-wagmi": "^1.6.4",
59
59
  "@sentry/sveltekit": "^7.107.0",
@@ -1,17 +0,0 @@
1
- <script>import TokenIOInput from "./TokenIOInput.svelte";
2
- export let allTokenInputs = [];
3
- export let allTokenOutputs = [];
4
- export let gui;
5
- </script>
6
-
7
- {#if allTokenInputs.length > 0}
8
- {#each allTokenInputs as input, i}
9
- <TokenIOInput {i} label="Input" vault={input} {gui} />
10
- {/each}
11
- {/if}
12
-
13
- {#if allTokenOutputs.length > 0}
14
- {#each allTokenOutputs as output, i}
15
- <TokenIOInput {i} label="Output" vault={output} {gui} />
16
- {/each}
17
- {/if}
@@ -1,21 +0,0 @@
1
- import { SvelteComponent } from "svelte";
2
- import type { DotrainOrderGui, OrderIOCfg } from '@rainlanguage/orderbook/js_api';
3
- declare const __propDef: {
4
- props: {
5
- allTokenInputs?: OrderIOCfg[];
6
- allTokenOutputs?: OrderIOCfg[];
7
- gui: DotrainOrderGui;
8
- };
9
- events: {
10
- [evt: string]: CustomEvent<any>;
11
- };
12
- slots: {};
13
- exports?: {} | undefined;
14
- bindings?: string | undefined;
15
- };
16
- export type TokenIoSectionProps = typeof __propDef.props;
17
- export type TokenIoSectionEvents = typeof __propDef.events;
18
- export type TokenIoSectionSlots = typeof __propDef.slots;
19
- export default class TokenIoSection extends SvelteComponent<TokenIoSectionProps, TokenIoSectionEvents, TokenIoSectionSlots> {
20
- }
21
- export {};