@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
@@ -1,11 +1,13 @@
1
- import { describe, expect, test, mock, beforeEach, spyOn } from "bun:test";
1
+ import { describe, expect, test, mock, beforeEach } from "bun:test";
2
2
  import { Sprinkle, Type } from "../index.js";
3
3
  import { withProfile } from "./test-helpers.js";
4
+ const mockSearch = mock();
4
5
  const mockSelect = mock();
5
6
  const mockInput = mock();
6
7
  const mockSelectCancellable = mock();
7
8
  const mockInputCancellable = mock();
8
9
  mock.module("@inquirer/prompts", () => ({
10
+ search: mockSearch,
9
11
  select: mockSelect,
10
12
  input: mockInput
11
13
  }));
@@ -14,10 +16,21 @@ mock.module("../prompts.js", () => ({
14
16
  inputCancellable: mockInputCancellable,
15
17
  passwordCancellable: mock(),
16
18
  confirmCancellable: mock(),
17
- searchCancellable: mock(),
19
+ searchCancellable: mockSearch,
18
20
  select: mockSelectCancellable
19
21
  }));
20
- describe("showMenu", () => {
22
+ async function collectChoices(call) {
23
+ const source = call[0].source;
24
+ return source(undefined);
25
+ }
26
+ function pickByName(choices, name) {
27
+ const match = choices.find(c => c.name === name);
28
+ if (!match) {
29
+ throw new Error(`No choice named "${name}". Available: ${choices.map(c => c.name).join(", ")}`);
30
+ }
31
+ return match.value;
32
+ }
33
+ describe("showMenu (search-based)", () => {
21
34
  let sprinkle;
22
35
  beforeEach(() => {
23
36
  const schema = Type.Object({
@@ -27,12 +40,16 @@ describe("showMenu", () => {
27
40
  sprinkle.settings = {
28
41
  name: "test"
29
42
  };
43
+ mockSearch.mockClear();
30
44
  mockSelect.mockClear();
31
45
  mockSelectCancellable.mockClear();
32
46
  mockInput.mockClear();
33
47
  });
34
- test("exits when Exit is selected on main menu", async () => {
35
- mockSelectCancellable.mockResolvedValueOnce(-1);
48
+ test("exits when the Exit leaf is selected", async () => {
49
+ mockSearch.mockImplementationOnce(async opts => {
50
+ const choices = await opts.source(undefined);
51
+ return pickByName(choices, "Exit");
52
+ });
36
53
  const menu = {
37
54
  title: "Test Menu",
38
55
  items: [{
@@ -41,10 +58,17 @@ describe("showMenu", () => {
41
58
  }]
42
59
  };
43
60
  await sprinkle.showMenu(menu);
61
+ expect(mockSearch).toHaveBeenCalledTimes(1);
44
62
  });
45
- test("executes action and re-shows menu", async () => {
63
+ test("executes a leaf action then loops back to the search prompt", async () => {
46
64
  const actionFn = mock(async () => {});
47
- mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);
65
+ mockSearch.mockImplementationOnce(async opts => {
66
+ const choices = await opts.source(undefined);
67
+ return pickByName(choices, "My Action");
68
+ }).mockImplementationOnce(async opts => {
69
+ const choices = await opts.source(undefined);
70
+ return pickByName(choices, "Exit");
71
+ });
48
72
  const menu = {
49
73
  title: "Test Menu",
50
74
  items: [{
@@ -54,48 +78,84 @@ describe("showMenu", () => {
54
78
  };
55
79
  await sprinkle.showMenu(menu);
56
80
  expect(actionFn).toHaveBeenCalledTimes(1);
81
+ expect(mockSearch).toHaveBeenCalledTimes(2);
57
82
  });
58
- test("main menu includes Settings & Profiles submenu and Exit", async () => {
59
- mockSelectCancellable.mockResolvedValueOnce(-1);
83
+ test("flattens submenus into breadcrumb leaves and surfaces Settings & Profiles + Exit", async () => {
84
+ mockSearch.mockImplementationOnce(async opts => {
85
+ const choices = await opts.source(undefined);
86
+ return pickByName(choices, "Exit");
87
+ });
60
88
  const menu = {
61
- title: "Test",
89
+ title: "Main",
62
90
  items: [{
63
- title: "Action",
91
+ title: "Strategies",
92
+ items: [{
93
+ title: "Create limit order",
94
+ action: async () => {}
95
+ }, {
96
+ title: "List strategies",
97
+ action: async () => {}
98
+ }]
99
+ }, {
100
+ title: "Quit (custom)",
64
101
  action: async () => {}
65
102
  }]
66
103
  };
67
104
  await sprinkle.showMenu(menu);
68
- const choices = mockSelectCancellable.mock.calls[0][0].choices;
105
+ const choices = await collectChoices(mockSearch.mock.calls[0]);
69
106
  const names = choices.map(c => c.name);
70
- expect(names).toContain("Settings & Profiles");
107
+ expect(names).toContain("Strategies Create limit order");
108
+ expect(names).toContain("Strategies › List strategies");
109
+ expect(names).toContain("Quit (custom)");
110
+ expect(names).toContain("Settings & Profiles › Edit settings");
111
+ expect(names).toContain("Settings & Profiles › Import profile from file");
71
112
  expect(names).toContain("Exit");
72
- expect(names).not.toContain("Switch profile");
73
- expect(names).not.toContain("Manage profiles");
74
- expect(names).not.toContain("Edit settings");
75
113
  });
76
- test("submenu includes Back instead of Exit", async () => {
77
- mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1).mockResolvedValueOnce(-1);
114
+ test("filters leaves by typed term (case-insensitive, all tokens, leaf-title boost)", async () => {
115
+ let filtered = [];
116
+ mockSearch.mockImplementationOnce(async opts => {
117
+ filtered = await opts.source("strateg");
118
+ // pick Exit so the loop terminates
119
+ const exitChoice = (await opts.source(undefined)).find(c => c.name === "Exit");
120
+ return exitChoice.value;
121
+ });
78
122
  const menu = {
79
123
  title: "Main",
80
124
  items: [{
81
- title: "Sub",
125
+ title: "Strategies",
82
126
  items: [{
83
- title: "Sub Action",
127
+ title: "Create limit order",
128
+ action: async () => {}
129
+ }, {
130
+ title: "Cancel strategy",
84
131
  action: async () => {}
85
132
  }]
133
+ }, {
134
+ title: "Send payment",
135
+ action: async () => {}
86
136
  }]
87
137
  };
88
138
  await sprinkle.showMenu(menu);
89
- const subChoices = mockSelectCancellable.mock.calls[1][0].choices;
90
- const subNames = subChoices.map(c => c.name);
91
- expect(subNames).toContain("Back");
92
- expect(subNames).not.toContain("Exit");
139
+ const filteredNames = filtered.map(c => c.name);
140
+ // Everything under "Strategies" matches via the breadcrumb token
141
+ expect(filteredNames).toContain("Strategies › Create limit order");
142
+ expect(filteredNames).toContain("Strategies › Cancel strategy");
143
+ // Direct leaf-title hit outranks ancestor-only match
144
+ expect(filteredNames[0]).toBe("Strategies › Cancel strategy");
145
+ // Unrelated items are filtered out
146
+ expect(filteredNames).not.toContain("Send payment");
93
147
  });
94
- test("action returning sprinkle instance saves settings", async () => {
148
+ test("action returning a Sprinkle persists updated settings", async () => {
95
149
  sprinkle.settings = {
96
150
  name: "original"
97
151
  };
98
- mockSelectCancellable.mockResolvedValueOnce(0).mockResolvedValueOnce(-1);
152
+ mockSearch.mockImplementationOnce(async opts => {
153
+ const choices = await opts.source(undefined);
154
+ return pickByName(choices, "Update");
155
+ }).mockImplementationOnce(async opts => {
156
+ const choices = await opts.source(undefined);
157
+ return pickByName(choices, "Exit");
158
+ });
99
159
  const menu = {
100
160
  title: "Test",
101
161
  items: [{
@@ -113,84 +173,35 @@ describe("showMenu", () => {
113
173
  name: "updated"
114
174
  });
115
175
  });
116
- test("Settings submenu includes View settings option", async () => {
117
- // Select "Settings & Profiles" (-5), then "Back" (-1), then "Exit" (-1)
118
- mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
119
- .mockResolvedValueOnce(-1) // Back
120
- .mockResolvedValueOnce(-1); // Exit
121
-
122
- const menu = {
123
- title: "Test",
124
- items: [{
125
- title: "Action",
126
- action: async () => {}
127
- }]
128
- };
129
- await sprinkle.showMenu(menu);
130
-
131
- // Second call is the settings submenu
132
- const settingsChoices = mockSelectCancellable.mock.calls[1][0].choices;
133
- const settingsNames = settingsChoices.map(c => c.name);
134
- expect(settingsNames).toContain("View settings");
135
- });
136
- test("View settings displays masked settings", async () => {
137
- const consoleSpy = spyOn(console, "log").mockImplementation(() => {});
138
-
139
- // Select "Settings & Profiles" (-5), then "View settings" (0),
140
- // then "Continue" for the press Enter prompt, then "Back" (-1), then "Exit" (-1)
141
- mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
142
- .mockResolvedValueOnce(0) // View settings (first item)
143
- .mockResolvedValueOnce("continue") // Press Enter to continue
144
- .mockResolvedValueOnce(-1) // Back
145
- .mockResolvedValueOnce(-1); // Exit
146
-
147
- const menu = {
148
- title: "Test",
149
- items: [{
150
- title: "Action",
151
- action: async () => {}
152
- }]
153
- };
154
- await sprinkle.showMenu(menu);
155
-
156
- // Should have called console.log with the settings (find the JSON output among breadcrumbs)
157
- expect(consoleSpy).toHaveBeenCalled();
158
- const jsonOutput = consoleSpy.mock.calls.find(call => call[0] && typeof call[0] === "string" && call[0].includes('"name"'));
159
- expect(jsonOutput).toBeDefined();
160
- consoleSpy.mockRestore();
161
- });
162
- test("Create profile restores state when FillInStruct is cancelled", async () => {
163
- // Capture original state
164
- const originalProfileId = sprinkle.currentProfile?.id;
165
- const originalSettings = {
166
- ...sprinkle.settings
167
- };
168
-
169
- // Settings menu indices: 0=View, 1=Edit, 2=Switch, 3=Create new profile
170
- mockSelectCancellable.mockResolvedValueOnce(-5) // Settings & Profiles
171
- .mockResolvedValueOnce(3); // Create new profile
172
-
173
- // promptProfileMeta: name then description
174
- mockInputCancellable.mockResolvedValueOnce("New Profile") // Profile name
175
- .mockResolvedValueOnce("") // Profile description
176
- .mockResolvedValueOnce(null); // Cancel during FillInStruct (name field)
177
-
178
- // After cancellation, back out of menus
179
- mockSelectCancellable.mockResolvedValueOnce(-1) // Back from settings
180
- .mockResolvedValueOnce(-1); // Exit
181
-
176
+ test("submenu beforeShow fires only when a leaf under it is selected", async () => {
177
+ const order = [];
178
+ const subBeforeShow = mock(async () => {
179
+ order.push("sub.beforeShow");
180
+ });
181
+ const actionFn = mock(async () => {
182
+ order.push("action");
183
+ });
184
+ mockSearch.mockImplementationOnce(async opts => {
185
+ const choices = await opts.source(undefined);
186
+ return pickByName(choices, "Strategies › Create");
187
+ }).mockImplementationOnce(async opts => {
188
+ const choices = await opts.source(undefined);
189
+ return pickByName(choices, "Exit");
190
+ });
182
191
  const menu = {
183
- title: "Test",
192
+ title: "Main",
184
193
  items: [{
185
- title: "Action",
186
- action: async () => {}
194
+ title: "Strategies",
195
+ beforeShow: subBeforeShow,
196
+ items: [{
197
+ title: "Create",
198
+ action: actionFn
199
+ }]
187
200
  }]
188
201
  };
189
202
  await sprinkle.showMenu(menu);
190
-
191
- // State should be restored to original
192
- expect(sprinkle.currentProfile?.id).toBe(originalProfileId);
193
- expect(sprinkle.settings).toEqual(originalSettings);
203
+ expect(subBeforeShow).toHaveBeenCalledTimes(1);
204
+ expect(order).toEqual(["sub.beforeShow", "action"]);
194
205
  });
195
206
  });
196
207
  //# sourceMappingURL=show-menu.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"show-menu.test.js","names":["describe","expect","test","mock","beforeEach","spyOn","Sprinkle","Type","withProfile","mockSelect","mockInput","mockSelectCancellable","mockInputCancellable","module","select","input","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","sprinkle","schema","Object","name","String","settings","mockClear","mockResolvedValueOnce","menu","title","items","action","showMenu","actionFn","toHaveBeenCalledTimes","choices","calls","names","map","c","toContain","not","subChoices","subNames","s","toEqual","settingsChoices","settingsNames","consoleSpy","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":["describe","expect","test","mock","beforeEach","Sprinkle","Type","withProfile","mockSearch","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","sprinkle","schema","Object","String","settings","mockClear","mockImplementationOnce","opts","menu","title","items","action","showMenu","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":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,IAAI,EAAEC,IAAI,EAAEC,UAAU,QAAe,UAAU;AAC1E,SAASC,QAAQ,EAAEC,IAAI,QAAoB,aAAa;AACxD,SAASC,WAAW,QAAQ,mBAAmB;AAE/C,MAAMC,UAAU,GAAGL,IAAI,CAAC,CAAC;AACzB,MAAMM,UAAU,GAAGN,IAAI,CAAC,CAAC;AACzB,MAAMO,SAAS,GAAGP,IAAI,CAAC,CAAC;AACxB,MAAMQ,qBAAqB,GAAGR,IAAI,CAAC,CAAC;AACpC,MAAMS,oBAAoB,GAAGT,IAAI,CAAC,CAAC;AAEnCA,IAAI,CAACU,MAAM,CAAC,mBAAmB,EAAE,OAAO;EACtCC,MAAM,EAAEN,UAAU;EAClBO,MAAM,EAAEN,UAAU;EAClBO,KAAK,EAAEN;AACT,CAAC,CAAC,CAAC;AAEHP,IAAI,CAACU,MAAM,CAAC,eAAe,EAAE,OAAO;EAClCI,iBAAiB,EAAEN,qBAAqB;EACxCO,gBAAgB,EAAEN,oBAAoB;EACtCO,mBAAmB,EAAEhB,IAAI,CAAC,CAAC;EAC3BiB,kBAAkB,EAAEjB,IAAI,CAAC,CAAC;EAC1BkB,iBAAiB,EAAEb,UAAU;EAC7BO,MAAM,EAAEJ;AACV,CAAC,CAAC,CAAC;AAMH,eAAeW,cAAcA,CAACC,IAAS,EAA2C;EAChF,MAAMC,MAAoB,GAAGD,IAAI,CAAC,CAAC,CAAC,CAACC,MAAM;EAC3C,OAAOA,MAAM,CAACC,SAAS,CAAC;AAC1B;AAEA,SAASC,UAAUA,CACjBC,OAAuC,EACvCC,IAAY,EACP;EACL,MAAMC,KAAK,GAAGF,OAAO,CAACG,IAAI,CAAEC,CAAC,IAAKA,CAAC,CAACH,IAAI,KAAKA,IAAI,CAAC;EAClD,IAAI,CAACC,KAAK,EAAE;IACV,MAAM,IAAIG,KAAK,CACb,oBAAoBJ,IAAI,iBAAiBD,OAAO,CAACM,GAAG,CAAEF,CAAC,IAAKA,CAAC,CAACH,IAAI,CAAC,CAACM,IAAI,CAAC,IAAI,CAAC,EAChF,CAAC;EACH;EACA,OAAOL,KAAK,CAACM,KAAK;AACpB;AAEAnC,QAAQ,CAAC,yBAAyB,EAAE,MAAM;EACxC,IAAIoC,QAAuB;EAE3BhC,UAAU,CAAC,MAAM;IACf,MAAMiC,MAAM,GAAG/B,IAAI,CAACgC,MAAM,CAAC;MAAEV,IAAI,EAAEtB,IAAI,CAACiC,MAAM,CAAC;IAAE,CAAC,CAAC;IACnDH,QAAQ,GAAG7B,WAAW,CAAC,IAAIF,QAAQ,CAACgC,MAAM,EAAE,WAAW,CAAC,CAAC;IACzDD,QAAQ,CAACI,QAAQ,GAAG;MAAEZ,IAAI,EAAE;IAAO,CAAQ;IAC3CpB,UAAU,CAACiC,SAAS,CAAC,CAAC;IACtBhC,UAAU,CAACgC,SAAS,CAAC,CAAC;IACtB9B,qBAAqB,CAAC8B,SAAS,CAAC,CAAC;IACjC/B,SAAS,CAAC+B,SAAS,CAAC,CAAC;EACvB,CAAC,CAAC;EAEFvC,IAAI,CAAC,sCAAsC,EAAE,YAAY;IACvDM,UAAU,CAACkC,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MACrD,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,MAAM,CAAC;IACpC,CAAC,CAAC;IAEF,MAAMiB,IAAgB,GAAG;MACvBC,KAAK,EAAE,WAAW;MAClBC,KAAK,EAAE,CAAC;QAAED,KAAK,EAAE,UAAU;QAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;MAAE,CAAC;IACvD,CAAC;IAED,MAAMX,QAAQ,CAACY,QAAQ,CAACJ,IAAI,CAAC;IAC7B3C,MAAM,CAACO,UAAU,CAAC,CAACyC,qBAAqB,CAAC,CAAC,CAAC;EAC7C,CAAC,CAAC;EAEF/C,IAAI,CAAC,6DAA6D,EAAE,YAAY;IAC9E,MAAMgD,QAAQ,GAAG/C,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAErCK,UAAU,CACPkC,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MAC3C,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,WAAW,CAAC;IACzC,CAAC,CAAC,CACDe,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MAC3C,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,MAAM,CAAC;IACpC,CAAC,CAAC;IAEJ,MAAMiB,IAAgB,GAAG;MACvBC,KAAK,EAAE,WAAW;MAClBC,KAAK,EAAE,CAAC;QAAED,KAAK,EAAE,WAAW;QAAEE,MAAM,EAAEG;MAAS,CAAC;IAClD,CAAC;IAED,MAAMd,QAAQ,CAACY,QAAQ,CAACJ,IAAI,CAAC;IAC7B3C,MAAM,CAACiD,QAAQ,CAAC,CAACD,qBAAqB,CAAC,CAAC,CAAC;IACzChD,MAAM,CAACO,UAAU,CAAC,CAACyC,qBAAqB,CAAC,CAAC,CAAC;EAC7C,CAAC,CAAC;EAEF/C,IAAI,CAAC,kFAAkF,EAAE,YAAY;IACnGM,UAAU,CAACkC,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MACrD,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,MAAM,CAAC;IACpC,CAAC,CAAC;IAEF,MAAMiB,IAAgB,GAAG;MACvBC,KAAK,EAAE,MAAM;MACbC,KAAK,EAAE,CACL;QACED,KAAK,EAAE,YAAY;QACnBC,KAAK,EAAE,CACL;UAAED,KAAK,EAAE,oBAAoB;UAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;QAAE,CAAC,EACvD;UAAEF,KAAK,EAAE,iBAAiB;UAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;QAAE,CAAC;MAExD,CAAC,EACD;QAAEF,KAAK,EAAE,eAAe;QAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;MAAE,CAAC;IAEtD,CAAC;IAED,MAAMX,QAAQ,CAACY,QAAQ,CAACJ,IAAI,CAAC;IAE7B,MAAMjB,OAAO,GAAG,MAAML,cAAc,CAACd,UAAU,CAACL,IAAI,CAACgD,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9D,MAAMC,KAAK,GAAGzB,OAAO,CAACM,GAAG,CAAEF,CAAC,IAAKA,CAAC,CAACH,IAAI,CAAC;IACxC3B,MAAM,CAACmD,KAAK,CAAC,CAACC,SAAS,CAAC,iCAAiC,CAAC;IAC1DpD,MAAM,CAACmD,KAAK,CAAC,CAACC,SAAS,CAAC,8BAA8B,CAAC;IACvDpD,MAAM,CAACmD,KAAK,CAAC,CAACC,SAAS,CAAC,eAAe,CAAC;IACxCpD,MAAM,CAACmD,KAAK,CAAC,CAACC,SAAS,CAAC,qCAAqC,CAAC;IAC9DpD,MAAM,CAACmD,KAAK,CAAC,CAACC,SAAS,CAAC,gDAAgD,CAAC;IACzEpD,MAAM,CAACmD,KAAK,CAAC,CAACC,SAAS,CAAC,MAAM,CAAC;EACjC,CAAC,CAAC;EAEFnD,IAAI,CAAC,+EAA+E,EAAE,YAAY;IAChG,IAAIoD,QAAwC,GAAG,EAAE;IAEjD9C,UAAU,CAACkC,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MACrDW,QAAQ,GAAG,MAAMX,IAAI,CAACnB,MAAM,CAAC,SAAS,CAAC;MACvC;MACA,MAAM+B,UAAU,GAAG,CAAC,MAAMZ,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC,EAAEK,IAAI,CACnDC,CAAM,IAAKA,CAAC,CAACH,IAAI,KAAK,MACzB,CAAC;MACD,OAAO2B,UAAU,CAACpB,KAAK;IACzB,CAAC,CAAC;IAEF,MAAMS,IAAgB,GAAG;MACvBC,KAAK,EAAE,MAAM;MACbC,KAAK,EAAE,CACL;QACED,KAAK,EAAE,YAAY;QACnBC,KAAK,EAAE,CACL;UAAED,KAAK,EAAE,oBAAoB;UAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;QAAE,CAAC,EACvD;UAAEF,KAAK,EAAE,iBAAiB;UAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;QAAE,CAAC;MAExD,CAAC,EACD;QAAEF,KAAK,EAAE,cAAc;QAAEE,MAAM,EAAE,MAAAA,CAAA,KAAY,CAAC;MAAE,CAAC;IAErD,CAAC;IAED,MAAMX,QAAQ,CAACY,QAAQ,CAACJ,IAAI,CAAC;IAE7B,MAAMY,aAAa,GAAGF,QAAQ,CAACrB,GAAG,CAAEF,CAAC,IAAKA,CAAC,CAACH,IAAI,CAAC;IACjD;IACA3B,MAAM,CAACuD,aAAa,CAAC,CAACH,SAAS,CAAC,iCAAiC,CAAC;IAClEpD,MAAM,CAACuD,aAAa,CAAC,CAACH,SAAS,CAAC,8BAA8B,CAAC;IAC/D;IACApD,MAAM,CAACuD,aAAa,CAAC,CAAC,CAAC,CAAC,CAACC,IAAI,CAAC,8BAA8B,CAAC;IAC7D;IACAxD,MAAM,CAACuD,aAAa,CAAC,CAACE,GAAG,CAACL,SAAS,CAAC,cAAc,CAAC;EACrD,CAAC,CAAC;EAEFnD,IAAI,CAAC,uDAAuD,EAAE,YAAY;IACxEkC,QAAQ,CAACI,QAAQ,GAAG;MAAEZ,IAAI,EAAE;IAAW,CAAQ;IAE/CpB,UAAU,CACPkC,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MAC3C,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,QAAQ,CAAC;IACtC,CAAC,CAAC,CACDe,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MAC3C,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,MAAM,CAAC;IACpC,CAAC,CAAC;IAEJ,MAAMiB,IAAgB,GAAG;MACvBC,KAAK,EAAE,MAAM;MACbC,KAAK,EAAE,CACL;QACED,KAAK,EAAE,QAAQ;QACfE,MAAM,EAAE,MAAOY,CAAgB,IAAK;UAClCA,CAAC,CAACnB,QAAQ,GAAG;YAAEZ,IAAI,EAAE;UAAU,CAAQ;UACvC,OAAO+B,CAAC;QACV;MACF,CAAC;IAEL,CAAC;IAED,MAAMvB,QAAQ,CAACY,QAAQ,CAACJ,IAAI,CAAC;IAC7B3C,MAAM,CAACmC,QAAQ,CAACI,QAAQ,CAAC,CAACoB,OAAO,CAAC;MAAEhC,IAAI,EAAE;IAAU,CAAC,CAAC;EACxD,CAAC,CAAC;EAEF1B,IAAI,CAAC,gEAAgE,EAAE,YAAY;IACjF,MAAM2D,KAAe,GAAG,EAAE;IAC1B,MAAMC,aAAa,GAAG3D,IAAI,CAAC,YAAY;MACrC0D,KAAK,CAACE,IAAI,CAAC,gBAAgB,CAAC;IAC9B,CAAC,CAAC;IACF,MAAMb,QAAQ,GAAG/C,IAAI,CAAC,YAAY;MAChC0D,KAAK,CAACE,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC,CAAC;IAEFvD,UAAU,CACPkC,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MAC3C,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,qBAAqB,CAAC;IACnD,CAAC,CAAC,CACDe,sBAAsB,CAAC,MAAOC,IAAS,IAAK;MAC3C,MAAMhB,OAAO,GAAG,MAAMgB,IAAI,CAACnB,MAAM,CAACC,SAAS,CAAC;MAC5C,OAAOC,UAAU,CAACC,OAAO,EAAE,MAAM,CAAC;IACpC,CAAC,CAAC;IAEJ,MAAMiB,IAAgB,GAAG;MACvBC,KAAK,EAAE,MAAM;MACbC,KAAK,EAAE,CACL;QACED,KAAK,EAAE,YAAY;QACnBmB,UAAU,EAAEF,aAAa;QACzBhB,KAAK,EAAE,CAAC;UAAED,KAAK,EAAE,QAAQ;UAAEE,MAAM,EAAEG;QAAS,CAAC;MAC/C,CAAC;IAEL,CAAC;IAED,MAAMd,QAAQ,CAACY,QAAQ,CAACJ,IAAI,CAAC;IAC7B3C,MAAM,CAAC6D,aAAa,CAAC,CAACb,qBAAqB,CAAC,CAAC,CAAC;IAC9ChD,MAAM,CAAC4D,KAAK,CAAC,CAACD,OAAO,CAAC,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;EACrD,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}