@sundaeswap/sprinkles 0.8.1 → 0.9.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 (29) hide show
  1. package/dist/cjs/Sprinkle/__tests__/enhancements.test.js +19 -7
  2. package/dist/cjs/Sprinkle/__tests__/enhancements.test.js.map +1 -1
  3. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +114 -0
  4. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  5. package/dist/cjs/Sprinkle/__tests__/show-menu.test.js +109 -98
  6. package/dist/cjs/Sprinkle/__tests__/show-menu.test.js.map +1 -1
  7. package/dist/cjs/Sprinkle/index.js +480 -179
  8. package/dist/cjs/Sprinkle/index.js.map +1 -1
  9. package/dist/cjs/Sprinkle/types.js.map +1 -1
  10. package/dist/esm/Sprinkle/__tests__/enhancements.test.js +19 -7
  11. package/dist/esm/Sprinkle/__tests__/enhancements.test.js.map +1 -1
  12. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +114 -0
  13. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  14. package/dist/esm/Sprinkle/__tests__/show-menu.test.js +110 -99
  15. package/dist/esm/Sprinkle/__tests__/show-menu.test.js.map +1 -1
  16. package/dist/esm/Sprinkle/index.js +483 -182
  17. package/dist/esm/Sprinkle/index.js.map +1 -1
  18. package/dist/esm/Sprinkle/types.js.map +1 -1
  19. package/dist/types/Sprinkle/index.d.ts +29 -0
  20. package/dist/types/Sprinkle/index.d.ts.map +1 -1
  21. package/dist/types/Sprinkle/types.d.ts +6 -0
  22. package/dist/types/Sprinkle/types.d.ts.map +1 -1
  23. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  24. package/package.json +1 -1
  25. package/src/Sprinkle/__tests__/enhancements.test.ts +20 -7
  26. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +112 -1
  27. package/src/Sprinkle/__tests__/show-menu.test.ts +132 -116
  28. package/src/Sprinkle/index.ts +552 -188
  29. package/src/Sprinkle/types.ts +6 -0
@@ -3,11 +3,13 @@
3
3
  var _bunTest = require("bun:test");
4
4
  var _index = require("../index.js");
5
5
  var _testHelpers = require("./test-helpers.js");
6
+ const mockSearch = (0, _bunTest.mock)();
6
7
  const mockSelect = (0, _bunTest.mock)();
7
8
  const mockInput = (0, _bunTest.mock)();
8
9
  const mockSelectCancellable = (0, _bunTest.mock)();
9
10
  const mockInputCancellable = (0, _bunTest.mock)();
10
11
  _bunTest.mock.module("@inquirer/prompts", () => ({
12
+ search: mockSearch,
11
13
  select: mockSelect,
12
14
  input: mockInput
13
15
  }));
@@ -16,10 +18,21 @@ _bunTest.mock.module("../prompts.js", () => ({
16
18
  inputCancellable: mockInputCancellable,
17
19
  passwordCancellable: (0, _bunTest.mock)(),
18
20
  confirmCancellable: (0, _bunTest.mock)(),
19
- searchCancellable: (0, _bunTest.mock)(),
21
+ searchCancellable: mockSearch,
20
22
  select: mockSelectCancellable
21
23
  }));
22
- (0, _bunTest.describe)("showMenu", () => {
24
+ async function collectChoices(call) {
25
+ const source = call[0].source;
26
+ return source(undefined);
27
+ }
28
+ function pickByName(choices, name) {
29
+ const match = choices.find(c => c.name === name);
30
+ if (!match) {
31
+ throw new Error(`No choice named "${name}". Available: ${choices.map(c => c.name).join(", ")}`);
32
+ }
33
+ return match.value;
34
+ }
35
+ (0, _bunTest.describe)("showMenu (search-based)", () => {
23
36
  let sprinkle;
24
37
  (0, _bunTest.beforeEach)(() => {
25
38
  const schema = _index.Type.Object({
@@ -29,12 +42,16 @@ _bunTest.mock.module("../prompts.js", () => ({
29
42
  sprinkle.settings = {
30
43
  name: "test"
31
44
  };
45
+ mockSearch.mockClear();
32
46
  mockSelect.mockClear();
33
47
  mockSelectCancellable.mockClear();
34
48
  mockInput.mockClear();
35
49
  });
36
- (0, _bunTest.test)("exits when Exit is selected on main menu", async () => {
37
- mockSelectCancellable.mockResolvedValueOnce(-1);
50
+ (0, _bunTest.test)("exits when the Exit leaf is selected", async () => {
51
+ mockSearch.mockImplementationOnce(async opts => {
52
+ const choices = await opts.source(undefined);
53
+ return pickByName(choices, "Exit");
54
+ });
38
55
  const menu = {
39
56
  title: "Test Menu",
40
57
  items: [{
@@ -43,10 +60,17 @@ _bunTest.mock.module("../prompts.js", () => ({
43
60
  }]
44
61
  };
45
62
  await sprinkle.showMenu(menu);
63
+ (0, _bunTest.expect)(mockSearch).toHaveBeenCalledTimes(1);
46
64
  });
47
- (0, _bunTest.test)("executes action and re-shows menu", async () => {
65
+ (0, _bunTest.test)("executes a leaf action then loops back to the search prompt", async () => {
48
66
  const actionFn = (0, _bunTest.mock)(async () => {});
49
- mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);
67
+ mockSearch.mockImplementationOnce(async opts => {
68
+ const choices = await opts.source(undefined);
69
+ return pickByName(choices, "My Action");
70
+ }).mockImplementationOnce(async opts => {
71
+ const choices = await opts.source(undefined);
72
+ return pickByName(choices, "Exit");
73
+ });
50
74
  const menu = {
51
75
  title: "Test Menu",
52
76
  items: [{
@@ -56,48 +80,84 @@ _bunTest.mock.module("../prompts.js", () => ({
56
80
  };
57
81
  await sprinkle.showMenu(menu);
58
82
  (0, _bunTest.expect)(actionFn).toHaveBeenCalledTimes(1);
83
+ (0, _bunTest.expect)(mockSearch).toHaveBeenCalledTimes(2);
59
84
  });
60
- (0, _bunTest.test)("main menu includes Settings & Profiles submenu and Exit", async () => {
61
- mockSelectCancellable.mockResolvedValueOnce(-1);
85
+ (0, _bunTest.test)("flattens submenus into breadcrumb leaves and surfaces Settings & Profiles + Exit", async () => {
86
+ mockSearch.mockImplementationOnce(async opts => {
87
+ const choices = await opts.source(undefined);
88
+ return pickByName(choices, "Exit");
89
+ });
62
90
  const menu = {
63
- title: "Test",
91
+ title: "Main",
64
92
  items: [{
65
- title: "Action",
93
+ title: "Strategies",
94
+ items: [{
95
+ title: "Create limit order",
96
+ action: async () => {}
97
+ }, {
98
+ title: "List strategies",
99
+ action: async () => {}
100
+ }]
101
+ }, {
102
+ title: "Quit (custom)",
66
103
  action: async () => {}
67
104
  }]
68
105
  };
69
106
  await sprinkle.showMenu(menu);
70
- const choices = mockSelectCancellable.mock.calls[0][0].choices;
107
+ const choices = await collectChoices(mockSearch.mock.calls[0]);
71
108
  const names = choices.map(c => c.name);
72
- (0, _bunTest.expect)(names).toContain("Settings & Profiles");
109
+ (0, _bunTest.expect)(names).toContain("Strategies Create limit order");
110
+ (0, _bunTest.expect)(names).toContain("Strategies › List strategies");
111
+ (0, _bunTest.expect)(names).toContain("Quit (custom)");
112
+ (0, _bunTest.expect)(names).toContain("Settings & Profiles › Edit settings");
113
+ (0, _bunTest.expect)(names).toContain("Settings & Profiles › Import profile from file");
73
114
  (0, _bunTest.expect)(names).toContain("Exit");
74
- (0, _bunTest.expect)(names).not.toContain("Switch profile");
75
- (0, _bunTest.expect)(names).not.toContain("Manage profiles");
76
- (0, _bunTest.expect)(names).not.toContain("Edit settings");
77
115
  });
78
- (0, _bunTest.test)("submenu includes Back instead of Exit", async () => {
79
- mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1).mockResolvedValueOnce(-1);
116
+ (0, _bunTest.test)("filters leaves by typed term (case-insensitive, all tokens, leaf-title boost)", async () => {
117
+ let filtered = [];
118
+ mockSearch.mockImplementationOnce(async opts => {
119
+ filtered = await opts.source("strateg");
120
+ // pick Exit so the loop terminates
121
+ const exitChoice = (await opts.source(undefined)).find(c => c.name === "Exit");
122
+ return exitChoice.value;
123
+ });
80
124
  const menu = {
81
125
  title: "Main",
82
126
  items: [{
83
- title: "Sub",
127
+ title: "Strategies",
84
128
  items: [{
85
- title: "Sub Action",
129
+ title: "Create limit order",
130
+ action: async () => {}
131
+ }, {
132
+ title: "Cancel strategy",
86
133
  action: async () => {}
87
134
  }]
135
+ }, {
136
+ title: "Send payment",
137
+ action: async () => {}
88
138
  }]
89
139
  };
90
140
  await sprinkle.showMenu(menu);
91
- const subChoices = mockSelectCancellable.mock.calls[1][0].choices;
92
- const subNames = subChoices.map(c => c.name);
93
- (0, _bunTest.expect)(subNames).toContain("Back");
94
- (0, _bunTest.expect)(subNames).not.toContain("Exit");
141
+ const filteredNames = filtered.map(c => c.name);
142
+ // Everything under "Strategies" matches via the breadcrumb token
143
+ (0, _bunTest.expect)(filteredNames).toContain("Strategies › Create limit order");
144
+ (0, _bunTest.expect)(filteredNames).toContain("Strategies › Cancel strategy");
145
+ // Direct leaf-title hit outranks ancestor-only match
146
+ (0, _bunTest.expect)(filteredNames[0]).toBe("Strategies › Cancel strategy");
147
+ // Unrelated items are filtered out
148
+ (0, _bunTest.expect)(filteredNames).not.toContain("Send payment");
95
149
  });
96
- (0, _bunTest.test)("action returning sprinkle instance saves settings", async () => {
150
+ (0, _bunTest.test)("action returning a Sprinkle persists updated settings", async () => {
97
151
  sprinkle.settings = {
98
152
  name: "original"
99
153
  };
100
- mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);
154
+ mockSearch.mockImplementationOnce(async opts => {
155
+ const choices = await opts.source(undefined);
156
+ return pickByName(choices, "Update");
157
+ }).mockImplementationOnce(async opts => {
158
+ const choices = await opts.source(undefined);
159
+ return pickByName(choices, "Exit");
160
+ });
101
161
  const menu = {
102
162
  title: "Test",
103
163
  items: [{
@@ -115,84 +175,35 @@ _bunTest.mock.module("../prompts.js", () => ({
115
175
  name: "updated"
116
176
  });
117
177
  });
118
- (0, _bunTest.test)("Settings submenu includes View settings option", async () => {
119
- // Select "Settings & Profiles" (-5), then "Back" (-1), then "Exit" (-1)
120
- mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
121
- .mockResolvedValueOnce(-1) // Back
122
- .mockResolvedValueOnce(-1); // Exit
123
-
124
- const menu = {
125
- title: "Test",
126
- items: [{
127
- title: "Action",
128
- action: async () => {}
129
- }]
130
- };
131
- await sprinkle.showMenu(menu);
132
-
133
- // Second call is the settings submenu
134
- const settingsChoices = mockSelectCancellable.mock.calls[1][0].choices;
135
- const settingsNames = settingsChoices.map(c => c.name);
136
- (0, _bunTest.expect)(settingsNames).toContain("View settings");
137
- });
138
- (0, _bunTest.test)("View settings displays masked settings", async () => {
139
- const consoleSpy = (0, _bunTest.spyOn)(console, "log").mockImplementation(() => {});
140
-
141
- // Select "Settings & Profiles" (-5), then "View settings" (0),
142
- // then "Continue" for the press Enter prompt, then "Back" (-1), then "Exit" (-1)
143
- mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
144
- .mockResolvedValueOnce(0) // View settings (first item)
145
- .mockResolvedValueOnce("continue") // Press Enter to continue
146
- .mockResolvedValueOnce(-1) // Back
147
- .mockResolvedValueOnce(-1); // Exit
148
-
149
- const menu = {
150
- title: "Test",
151
- items: [{
152
- title: "Action",
153
- action: async () => {}
154
- }]
155
- };
156
- await sprinkle.showMenu(menu);
157
-
158
- // Should have called console.log with the settings (find the JSON output among breadcrumbs)
159
- (0, _bunTest.expect)(consoleSpy).toHaveBeenCalled();
160
- const jsonOutput = consoleSpy.mock.calls.find(call => call[0] && typeof call[0] === "string" && call[0].includes('"name"'));
161
- (0, _bunTest.expect)(jsonOutput).toBeDefined();
162
- consoleSpy.mockRestore();
163
- });
164
- (0, _bunTest.test)("Create profile restores state when FillInStruct is cancelled", async () => {
165
- // Capture original state
166
- const originalProfileId = sprinkle.currentProfile?.id;
167
- const originalSettings = {
168
- ...sprinkle.settings
169
- };
170
-
171
- // Settings menu indices: 0=View, 1=Edit, 2=Switch, 3=Create new profile
172
- mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
173
- .mockResolvedValueOnce(3); // Create new profile
174
-
175
- // promptProfileMeta: name then description
176
- mockInputCancellable.mockResolvedValueOnce("New Profile") // Profile name
177
- .mockResolvedValueOnce("") // Profile description
178
- .mockResolvedValueOnce(null); // Cancel during FillInStruct (name field)
179
-
180
- // After cancellation, back out of menus
181
- mockSelectCancellable.mockResolvedValueOnce(-1) // Back from settings
182
- .mockResolvedValueOnce(-1); // Exit
183
-
178
+ (0, _bunTest.test)("submenu beforeShow fires only when a leaf under it is selected", async () => {
179
+ const order = [];
180
+ const subBeforeShow = (0, _bunTest.mock)(async () => {
181
+ order.push("sub.beforeShow");
182
+ });
183
+ const actionFn = (0, _bunTest.mock)(async () => {
184
+ order.push("action");
185
+ });
186
+ mockSearch.mockImplementationOnce(async opts => {
187
+ const choices = await opts.source(undefined);
188
+ return pickByName(choices, "Strategies › Create");
189
+ }).mockImplementationOnce(async opts => {
190
+ const choices = await opts.source(undefined);
191
+ return pickByName(choices, "Exit");
192
+ });
184
193
  const menu = {
185
- title: "Test",
194
+ title: "Main",
186
195
  items: [{
187
- title: "Action",
188
- action: async () => {}
196
+ title: "Strategies",
197
+ beforeShow: subBeforeShow,
198
+ items: [{
199
+ title: "Create",
200
+ action: actionFn
201
+ }]
189
202
  }]
190
203
  };
191
204
  await sprinkle.showMenu(menu);
192
-
193
- // State should be restored to original
194
- (0, _bunTest.expect)(sprinkle.currentProfile?.id).toBe(originalProfileId);
195
- (0, _bunTest.expect)(sprinkle.settings).toEqual(originalSettings);
205
+ (0, _bunTest.expect)(subBeforeShow).toHaveBeenCalledTimes(1);
206
+ (0, _bunTest.expect)(order).toEqual(["sub.beforeShow", "action"]);
196
207
  });
197
208
  });
198
209
  //# sourceMappingURL=show-menu.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"show-menu.test.js","names":["_bunTest","require","_index","_testHelpers","mockSelect","mock","mockInput","mockSelectCancellable","mockInputCancellable","module","select","input","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","describe","sprinkle","beforeEach","schema","Type","Object","name","String","withProfile","Sprinkle","settings","mockClear","test","mockResolvedValueOnce","menu","title","items","action","showMenu","actionFn","expect","toHaveBeenCalledTimes","choices","calls","names","map","c","toContain","not","subChoices","subNames","s","toEqual","settingsChoices","settingsNames","consoleSpy","spyOn","console","mockImplementation","toHaveBeenCalled","jsonOutput","find","call","includes","toBeDefined","mockRestore","originalProfileId","currentProfile","id","originalSettings","toBe"],"sources":["../../../../src/Sprinkle/__tests__/show-menu.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, spyOn } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mock(),\n confirmCancellable: mock(),\n searchCancellable: mock(),\n select: mockSelectCancellable,\n}));\n\ndescribe(\"showMenu\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = withProfile(new Sprinkle(schema, \"/tmp/test\"));\n sprinkle.settings = { name: \"test\" } as any;\n mockSelect.mockClear();\n mockSelectCancellable.mockClear();\n mockInput.mockClear();\n });\n\n test(\"exits when Exit is selected on main menu\", async () => {\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [\n {\n title: \"Action 1\",\n action: async () => {},\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n });\n\n test(\"executes action and re-shows menu\", async () => {\n const actionFn = mock(async () => {});\n\n mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [\n {\n title: \"My Action\",\n action: actionFn,\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(actionFn).toHaveBeenCalledTimes(1);\n });\n\n test(\"main menu includes Settings & Profiles submenu and Exit\", async () => {\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n const choices = mockSelectCancellable.mock.calls[0][0].choices;\n const names = choices.map((c: any) => c.name);\n expect(names).toContain(\"Settings & Profiles\");\n expect(names).toContain(\"Exit\");\n expect(names).not.toContain(\"Switch profile\");\n expect(names).not.toContain(\"Manage profiles\");\n expect(names).not.toContain(\"Edit settings\");\n });\n\n test(\"submenu includes Back instead of Exit\", async () => {\n mockSelectCancellable\n .mockResolvedValueOnce(0)\n .mockResolvedValueOnce(-1)\n .mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Main\",\n items: [\n {\n title: \"Sub\",\n items: [{ title: \"Sub Action\", action: async () => {} }],\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n\n const subChoices = mockSelectCancellable.mock.calls[1][0].choices;\n const subNames = subChoices.map((c: any) => c.name);\n expect(subNames).toContain(\"Back\");\n expect(subNames).not.toContain(\"Exit\");\n });\n\n test(\"action returning sprinkle instance saves settings\", async () => {\n sprinkle.settings = { name: \"original\" } as any;\n\n mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [\n {\n title: \"Update\",\n action: async (s: Sprinkle<any>) => {\n s.settings = { name: \"updated\" } as any;\n return s;\n },\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(sprinkle.settings).toEqual({ name: \"updated\" });\n });\n\n test(\"Settings submenu includes View settings option\", async () => {\n // Select \"Settings & Profiles\" (-5), then \"Back\" (-1), then \"Exit\" (-1)\n mockSelectCancellable\n .mockResolvedValueOnce(-5) // Settings & Profiles\n .mockResolvedValueOnce(-1) // Back\n .mockResolvedValueOnce(-1); // Exit\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n // Second call is the settings submenu\n const settingsChoices = mockSelectCancellable.mock.calls[1][0].choices;\n const settingsNames = settingsChoices.map((c: any) => c.name);\n expect(settingsNames).toContain(\"View settings\");\n });\n\n test(\"View settings displays masked settings\", async () => {\n const consoleSpy = spyOn(console, \"log\").mockImplementation(() => {});\n\n // Select \"Settings & Profiles\" (-5), then \"View settings\" (0),\n // then \"Continue\" for the press Enter prompt, then \"Back\" (-1), then \"Exit\" (-1)\n mockSelectCancellable\n .mockResolvedValueOnce(-5) // Settings & Profiles\n .mockResolvedValueOnce(0) // View settings (first item)\n .mockResolvedValueOnce(\"continue\") // Press Enter to continue\n .mockResolvedValueOnce(-1) // Back\n .mockResolvedValueOnce(-1); // Exit\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n // Should have called console.log with the settings (find the JSON output among breadcrumbs)\n expect(consoleSpy).toHaveBeenCalled();\n const jsonOutput = consoleSpy.mock.calls.find((call: any[]) =>\n call[0] && typeof call[0] === \"string\" && call[0].includes('\"name\"')\n );\n expect(jsonOutput).toBeDefined();\n\n consoleSpy.mockRestore();\n });\n\n test(\"Create profile restores state when FillInStruct is cancelled\", async () => {\n // Capture original state\n const originalProfileId = sprinkle.currentProfile?.id;\n const originalSettings = { ...sprinkle.settings };\n\n // Settings menu indices: 0=View, 1=Edit, 2=Switch, 3=Create new profile\n mockSelectCancellable\n .mockResolvedValueOnce(-5) // Settings & Profiles\n .mockResolvedValueOnce(3); // Create new profile\n\n // promptProfileMeta: name then description\n mockInputCancellable\n .mockResolvedValueOnce(\"New Profile\") // Profile name\n .mockResolvedValueOnce(\"\") // Profile description\n .mockResolvedValueOnce(null); // Cancel during FillInStruct (name field)\n\n // After cancellation, back out of menus\n mockSelectCancellable\n .mockResolvedValueOnce(-1) // Back from settings\n .mockResolvedValueOnce(-1); // Exit\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n // State should be restored to original\n expect(sprinkle.currentProfile?.id).toBe(originalProfileId);\n expect(sprinkle.settings).toEqual(originalSettings);\n });\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"show-menu.test.js","names":["_bunTest","require","_index","_testHelpers","mockSearch","mock","mockSelect","mockInput","mockSelectCancellable","mockInputCancellable","module","search","select","input","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","collectChoices","call","source","undefined","pickByName","choices","name","match","find","c","Error","map","join","value","describe","sprinkle","beforeEach","schema","Type","Object","String","withProfile","Sprinkle","settings","mockClear","test","mockImplementationOnce","opts","menu","title","items","action","showMenu","expect","toHaveBeenCalledTimes","actionFn","calls","names","toContain","filtered","exitChoice","filteredNames","toBe","not","s","toEqual","order","subBeforeShow","push","beforeShow"],"sources":["../../../../src/Sprinkle/__tests__/show-menu.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, spyOn } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSearch = mock();\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n search: mockSearch,\n select: mockSelect,\n input: mockInput,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mock(),\n confirmCancellable: mock(),\n searchCancellable: mockSearch,\n select: mockSelectCancellable,\n}));\n\ntype SearchSource = (\n term: string | undefined,\n) => Promise<{ name: string; value: any }[]>;\n\nasync function collectChoices(call: any): Promise<{ name: string; value: any }[]> {\n const source: SearchSource = call[0].source;\n return source(undefined);\n}\n\nfunction pickByName(\n choices: { name: string; value: any }[],\n name: string,\n): any {\n const match = choices.find((c) => c.name === name);\n if (!match) {\n throw new Error(\n `No choice named \"${name}\". Available: ${choices.map((c) => c.name).join(\", \")}`,\n );\n }\n return match.value;\n}\n\ndescribe(\"showMenu (search-based)\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = withProfile(new Sprinkle(schema, \"/tmp/test\"));\n sprinkle.settings = { name: \"test\" } as any;\n mockSearch.mockClear();\n mockSelect.mockClear();\n mockSelectCancellable.mockClear();\n mockInput.mockClear();\n });\n\n test(\"exits when the Exit leaf is selected\", async () => {\n mockSearch.mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Exit\");\n });\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [{ title: \"Action 1\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n expect(mockSearch).toHaveBeenCalledTimes(1);\n });\n\n test(\"executes a leaf action then loops back to the search prompt\", async () => {\n const actionFn = mock(async () => {});\n\n mockSearch\n .mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"My Action\");\n })\n .mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Exit\");\n });\n\n const menu: IMenu<any> = {\n title: \"Test Menu\",\n items: [{ title: \"My Action\", action: actionFn }],\n };\n\n await sprinkle.showMenu(menu);\n expect(actionFn).toHaveBeenCalledTimes(1);\n expect(mockSearch).toHaveBeenCalledTimes(2);\n });\n\n test(\"flattens submenus into breadcrumb leaves and surfaces Settings & Profiles + Exit\", async () => {\n mockSearch.mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Exit\");\n });\n\n const menu: IMenu<any> = {\n title: \"Main\",\n items: [\n {\n title: \"Strategies\",\n items: [\n { title: \"Create limit order\", action: async () => {} },\n { title: \"List strategies\", action: async () => {} },\n ],\n },\n { title: \"Quit (custom)\", action: async () => {} },\n ],\n };\n\n await sprinkle.showMenu(menu);\n\n const choices = await collectChoices(mockSearch.mock.calls[0]);\n const names = choices.map((c) => c.name);\n expect(names).toContain(\"Strategies › Create limit order\");\n expect(names).toContain(\"Strategies › List strategies\");\n expect(names).toContain(\"Quit (custom)\");\n expect(names).toContain(\"Settings & Profiles › Edit settings\");\n expect(names).toContain(\"Settings & Profiles › Import profile from file\");\n expect(names).toContain(\"Exit\");\n });\n\n test(\"filters leaves by typed term (case-insensitive, all tokens, leaf-title boost)\", async () => {\n let filtered: { name: string; value: any }[] = [];\n\n mockSearch.mockImplementationOnce(async (opts: any) => {\n filtered = await opts.source(\"strateg\");\n // pick Exit so the loop terminates\n const exitChoice = (await opts.source(undefined)).find(\n (c: any) => c.name === \"Exit\",\n );\n return exitChoice.value;\n });\n\n const menu: IMenu<any> = {\n title: \"Main\",\n items: [\n {\n title: \"Strategies\",\n items: [\n { title: \"Create limit order\", action: async () => {} },\n { title: \"Cancel strategy\", action: async () => {} },\n ],\n },\n { title: \"Send payment\", action: async () => {} },\n ],\n };\n\n await sprinkle.showMenu(menu);\n\n const filteredNames = filtered.map((c) => c.name);\n // Everything under \"Strategies\" matches via the breadcrumb token\n expect(filteredNames).toContain(\"Strategies › Create limit order\");\n expect(filteredNames).toContain(\"Strategies › Cancel strategy\");\n // Direct leaf-title hit outranks ancestor-only match\n expect(filteredNames[0]).toBe(\"Strategies › Cancel strategy\");\n // Unrelated items are filtered out\n expect(filteredNames).not.toContain(\"Send payment\");\n });\n\n test(\"action returning a Sprinkle persists updated settings\", async () => {\n sprinkle.settings = { name: \"original\" } as any;\n\n mockSearch\n .mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Update\");\n })\n .mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Exit\");\n });\n\n const menu: IMenu<any> = {\n title: \"Test\",\n items: [\n {\n title: \"Update\",\n action: async (s: Sprinkle<any>) => {\n s.settings = { name: \"updated\" } as any;\n return s;\n },\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(sprinkle.settings).toEqual({ name: \"updated\" });\n });\n\n test(\"submenu beforeShow fires only when a leaf under it is selected\", async () => {\n const order: string[] = [];\n const subBeforeShow = mock(async () => {\n order.push(\"sub.beforeShow\");\n });\n const actionFn = mock(async () => {\n order.push(\"action\");\n });\n\n mockSearch\n .mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Strategies › Create\");\n })\n .mockImplementationOnce(async (opts: any) => {\n const choices = await opts.source(undefined);\n return pickByName(choices, \"Exit\");\n });\n\n const menu: IMenu<any> = {\n title: \"Main\",\n items: [\n {\n title: \"Strategies\",\n beforeShow: subBeforeShow,\n items: [{ title: \"Create\", action: actionFn }],\n },\n ],\n };\n\n await sprinkle.showMenu(menu);\n expect(subBeforeShow).toHaveBeenCalledTimes(1);\n expect(order).toEqual([\"sub.beforeShow\", \"action\"]);\n });\n});\n"],"mappings":"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","ignoreList":[]}