@sundaeswap/sprinkles 0.5.0 → 0.6.1

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 (112) hide show
  1. package/dist/cjs/Sprinkle/__tests__/encryption.test.js +3 -1
  2. package/dist/cjs/Sprinkle/__tests__/encryption.test.js.map +1 -1
  3. package/dist/cjs/Sprinkle/__tests__/enhancements.test.js +3 -37
  4. package/dist/cjs/Sprinkle/__tests__/enhancements.test.js.map +1 -1
  5. package/dist/cjs/Sprinkle/__tests__/field-utils.test.js +170 -0
  6. package/dist/cjs/Sprinkle/__tests__/field-utils.test.js.map +1 -0
  7. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +377 -84
  8. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  9. package/dist/cjs/Sprinkle/__tests__/formatting.test.js +97 -0
  10. package/dist/cjs/Sprinkle/__tests__/formatting.test.js.map +1 -0
  11. package/dist/cjs/Sprinkle/__tests__/show-menu.test.js +9 -5
  12. package/dist/cjs/Sprinkle/__tests__/show-menu.test.js.map +1 -1
  13. package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js +9 -0
  14. package/dist/cjs/Sprinkle/__tests__/tx-dialog.test.js.map +1 -1
  15. package/dist/cjs/Sprinkle/index.js +174 -94
  16. package/dist/cjs/Sprinkle/index.js.map +1 -1
  17. package/dist/cjs/Sprinkle/menus/array-menu.js +195 -0
  18. package/dist/cjs/Sprinkle/menus/array-menu.js.map +1 -0
  19. package/dist/cjs/Sprinkle/menus/field-menu.js +161 -0
  20. package/dist/cjs/Sprinkle/menus/field-menu.js.map +1 -0
  21. package/dist/cjs/Sprinkle/menus/index.js +33 -0
  22. package/dist/cjs/Sprinkle/menus/index.js.map +1 -0
  23. package/dist/cjs/Sprinkle/menus/object-menu.js +324 -0
  24. package/dist/cjs/Sprinkle/menus/object-menu.js.map +1 -0
  25. package/dist/cjs/Sprinkle/prompts.js +68 -2
  26. package/dist/cjs/Sprinkle/prompts.js.map +1 -1
  27. package/dist/cjs/Sprinkle/type-guards.js +48 -1
  28. package/dist/cjs/Sprinkle/type-guards.js.map +1 -1
  29. package/dist/cjs/Sprinkle/types.js +24 -0
  30. package/dist/cjs/Sprinkle/types.js.map +1 -1
  31. package/dist/cjs/Sprinkle/utils/field-utils.js +154 -0
  32. package/dist/cjs/Sprinkle/utils/field-utils.js.map +1 -0
  33. package/dist/cjs/Sprinkle/utils/formatting.js +126 -0
  34. package/dist/cjs/Sprinkle/utils/formatting.js.map +1 -0
  35. package/dist/cjs/Sprinkle/utils/index.js +56 -0
  36. package/dist/cjs/Sprinkle/utils/index.js.map +1 -0
  37. package/dist/esm/Sprinkle/__tests__/encryption.test.js +3 -1
  38. package/dist/esm/Sprinkle/__tests__/encryption.test.js.map +1 -1
  39. package/dist/esm/Sprinkle/__tests__/enhancements.test.js +3 -37
  40. package/dist/esm/Sprinkle/__tests__/enhancements.test.js.map +1 -1
  41. package/dist/esm/Sprinkle/__tests__/field-utils.test.js +168 -0
  42. package/dist/esm/Sprinkle/__tests__/field-utils.test.js.map +1 -0
  43. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +378 -85
  44. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  45. package/dist/esm/Sprinkle/__tests__/formatting.test.js +95 -0
  46. package/dist/esm/Sprinkle/__tests__/formatting.test.js.map +1 -0
  47. package/dist/esm/Sprinkle/__tests__/show-menu.test.js +9 -5
  48. package/dist/esm/Sprinkle/__tests__/show-menu.test.js.map +1 -1
  49. package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js +9 -0
  50. package/dist/esm/Sprinkle/__tests__/tx-dialog.test.js.map +1 -1
  51. package/dist/esm/Sprinkle/index.js +141 -96
  52. package/dist/esm/Sprinkle/index.js.map +1 -1
  53. package/dist/esm/Sprinkle/menus/array-menu.js +190 -0
  54. package/dist/esm/Sprinkle/menus/array-menu.js.map +1 -0
  55. package/dist/esm/Sprinkle/menus/field-menu.js +155 -0
  56. package/dist/esm/Sprinkle/menus/field-menu.js.map +1 -0
  57. package/dist/esm/Sprinkle/menus/index.js +8 -0
  58. package/dist/esm/Sprinkle/menus/index.js.map +1 -0
  59. package/dist/esm/Sprinkle/menus/object-menu.js +318 -0
  60. package/dist/esm/Sprinkle/menus/object-menu.js.map +1 -0
  61. package/dist/esm/Sprinkle/prompts.js +59 -1
  62. package/dist/esm/Sprinkle/prompts.js.map +1 -1
  63. package/dist/esm/Sprinkle/type-guards.js +42 -0
  64. package/dist/esm/Sprinkle/type-guards.js.map +1 -1
  65. package/dist/esm/Sprinkle/types.js +24 -0
  66. package/dist/esm/Sprinkle/types.js.map +1 -1
  67. package/dist/esm/Sprinkle/utils/field-utils.js +145 -0
  68. package/dist/esm/Sprinkle/utils/field-utils.js.map +1 -0
  69. package/dist/esm/Sprinkle/utils/formatting.js +118 -0
  70. package/dist/esm/Sprinkle/utils/formatting.js.map +1 -0
  71. package/dist/esm/Sprinkle/utils/index.js +7 -0
  72. package/dist/esm/Sprinkle/utils/index.js.map +1 -0
  73. package/dist/types/Sprinkle/index.d.ts +9 -3
  74. package/dist/types/Sprinkle/index.d.ts.map +1 -1
  75. package/dist/types/Sprinkle/menus/array-menu.d.ts +31 -0
  76. package/dist/types/Sprinkle/menus/array-menu.d.ts.map +1 -0
  77. package/dist/types/Sprinkle/menus/field-menu.d.ts +34 -0
  78. package/dist/types/Sprinkle/menus/field-menu.d.ts.map +1 -0
  79. package/dist/types/Sprinkle/menus/index.d.ts +10 -0
  80. package/dist/types/Sprinkle/menus/index.d.ts.map +1 -0
  81. package/dist/types/Sprinkle/menus/object-menu.d.ts +34 -0
  82. package/dist/types/Sprinkle/menus/object-menu.d.ts.map +1 -0
  83. package/dist/types/Sprinkle/prompts.d.ts +25 -0
  84. package/dist/types/Sprinkle/prompts.d.ts.map +1 -1
  85. package/dist/types/Sprinkle/type-guards.d.ts +24 -1
  86. package/dist/types/Sprinkle/type-guards.d.ts.map +1 -1
  87. package/dist/types/Sprinkle/types.d.ts +53 -0
  88. package/dist/types/Sprinkle/types.d.ts.map +1 -1
  89. package/dist/types/Sprinkle/utils/field-utils.d.ts +47 -0
  90. package/dist/types/Sprinkle/utils/field-utils.d.ts.map +1 -0
  91. package/dist/types/Sprinkle/utils/formatting.d.ts +30 -0
  92. package/dist/types/Sprinkle/utils/formatting.d.ts.map +1 -0
  93. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  94. package/package.json +1 -1
  95. package/src/Sprinkle/__tests__/encryption.test.ts +2 -0
  96. package/src/Sprinkle/__tests__/enhancements.test.ts +3 -42
  97. package/src/Sprinkle/__tests__/field-utils.test.ts +191 -0
  98. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +393 -100
  99. package/src/Sprinkle/__tests__/formatting.test.ts +115 -0
  100. package/src/Sprinkle/__tests__/show-menu.test.ts +14 -8
  101. package/src/Sprinkle/__tests__/tx-dialog.test.ts +9 -0
  102. package/src/Sprinkle/index.ts +175 -122
  103. package/src/Sprinkle/menus/array-menu.ts +191 -0
  104. package/src/Sprinkle/menus/field-menu.ts +145 -0
  105. package/src/Sprinkle/menus/index.ts +12 -0
  106. package/src/Sprinkle/menus/object-menu.ts +336 -0
  107. package/src/Sprinkle/prompts.ts +71 -1
  108. package/src/Sprinkle/type-guards.ts +42 -0
  109. package/src/Sprinkle/types.ts +43 -0
  110. package/src/Sprinkle/utils/field-utils.ts +158 -0
  111. package/src/Sprinkle/utils/formatting.ts +127 -0
  112. package/src/Sprinkle/utils/index.ts +17 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"array-menu.js","names":["_core","require","_prompts","_types","_formatting","_fieldMenu","promptArray","options","type","path","defs","defaults","fillField","itemType","items","choices","i","length","preview","formatValuePreview","push","name","value","Separator","breadcrumb","formatBreadcrumb","message","selection","selectWithClear","action","newItem","undefined","e","UserCancelledError","removeChoices","map","item","indexToRemove","splice","startsWith","index","parseInt","slice","currentValue","itemState","status","menuResult","promptFieldMenu","fieldName","fieldType","state","newValue","displayFullValue"],"sources":["../../../../src/Sprinkle/menus/array-menu.ts"],"sourcesContent":["/**\n * Array menu module for menu-based struct editing.\n * Shows array items and allows adding/removing/editing.\n */\n\nimport { Separator } from \"@inquirer/core\";\nimport type { TArray, TSchema } from \"@sinclair/typebox\";\nimport { selectWithClear } from \"../prompts.js\";\nimport type { ArrayMenuResult, FieldState } from \"../types.js\";\nimport { UserCancelledError } from \"../types.js\";\nimport { formatValuePreview, formatBreadcrumb } from \"../utils/formatting.js\";\nimport { promptFieldMenu, displayFullValue } from \"./field-menu.js\";\nimport type { FillFunction } from \"./object-menu.js\";\n\n/**\n * Options for the array menu prompt.\n */\nexport interface ArrayMenuOptions {\n /** The array schema */\n type: TArray;\n /** Current path for display */\n path: string[];\n /** Type definitions for resolving refs */\n defs: Record<string, TSchema>;\n /** Existing array values */\n defaults?: unknown[];\n /** Function to fill individual items */\n fillField: FillFunction;\n}\n\n/**\n * Show a menu-based editor for an array.\n * Allows adding, removing, and editing items.\n *\n * @param options - Array menu options\n * @returns The edited array or back result\n */\nexport async function promptArray<T>(\n options: ArrayMenuOptions,\n): Promise<ArrayMenuResult<T>> {\n const { type, path, defs, defaults = [], fillField } = options;\n\n const itemType = type.items as TSchema;\n\n // Initialize items from defaults\n const items: T[] = [...(defaults as T[])];\n\n // Main menu loop\n while (true) {\n // Build menu choices\n const choices: Array<{ name: string; value: string } | Separator> = [];\n\n // Add existing items\n for (let i = 0; i < items.length; i++) {\n const preview = formatValuePreview(items[i], 40);\n choices.push({ name: `[${i}]: ${preview}`, value: `item:${i}` });\n }\n\n // Add separator and actions\n choices.push(new Separator(\"\\u2500\\u2500\\u2500 Actions \\u2500\\u2500\\u2500\"));\n choices.push({ name: \"Add item\", value: \"add\" });\n\n if (items.length > 0) {\n choices.push({ name: \"Remove item...\", value: \"remove\" });\n }\n\n choices.push({ name: `Done (${items.length} item${items.length === 1 ? \"\" : \"s\"})`, value: \"done\" });\n choices.push({ name: \"Back\", value: \"back\" });\n\n // Show menu\n const breadcrumb = formatBreadcrumb(path);\n const message = breadcrumb\n ? `Edit ${breadcrumb} [${items.length} items]:`\n : `Edit array [${items.length} items]:`;\n\n const selection = await selectWithClear({\n message,\n choices,\n });\n\n // Handle escape - same as done\n if (selection === null) {\n return { action: \"done\", value: items };\n }\n\n // Handle done\n if (selection === \"done\") {\n return { action: \"done\", value: items };\n }\n\n // Handle back\n if (selection === \"back\") {\n return { action: \"back\" };\n }\n\n // Handle add\n if (selection === \"add\") {\n try {\n const newItem = await fillField(\n itemType,\n [...path, `[${items.length}]`],\n defs,\n undefined,\n );\n items.push(newItem as T);\n } catch (e) {\n if (e instanceof UserCancelledError) {\n // Return to menu without adding\n continue;\n }\n throw e;\n }\n continue;\n }\n\n // Handle remove\n if (selection === \"remove\") {\n const removeChoices = items.map((item, i) => ({\n name: `[${i}]: ${formatValuePreview(item, 40)}`,\n value: i,\n }));\n removeChoices.push({ name: \"Cancel\", value: -1 } as { name: string; value: number });\n\n const indexToRemove = await selectWithClear({\n message: \"Select item to remove:\",\n choices: removeChoices,\n });\n\n if (indexToRemove !== null && indexToRemove !== -1) {\n items.splice(indexToRemove as number, 1);\n }\n continue;\n }\n\n // Handle item selection\n if (typeof selection === \"string\" && selection.startsWith(\"item:\")) {\n const index = parseInt(selection.slice(5), 10);\n const currentValue = items[index];\n\n // Create a FieldState for the item\n const itemState: FieldState<T> = { status: \"set\", value: currentValue as T };\n\n const menuResult = await promptFieldMenu({\n fieldName: `[${index}]`,\n fieldType: itemType,\n state: itemState,\n });\n\n switch (menuResult.action) {\n case \"edit\": {\n try {\n const newValue = await fillField(\n itemType,\n [...path, `[${index}]`],\n defs,\n currentValue,\n );\n items[index] = newValue as T;\n } catch (e) {\n if (e instanceof UserCancelledError) {\n continue;\n }\n throw e;\n }\n break;\n }\n\n case \"view\": {\n await displayFullValue(`[${index}]`, currentValue);\n break;\n }\n\n case \"clear\": {\n // Remove the item\n items.splice(index, 1);\n break;\n }\n\n case \"setNull\": {\n items[index] = null as T;\n break;\n }\n\n case \"reset\":\n case \"back\":\n // Do nothing\n break;\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.displayFullValue = displayFullValue;
7
+ exports.promptFieldMenu = promptFieldMenu;
8
+ var _core = require("@inquirer/core");
9
+ var _prompts = require("../prompts.js");
10
+ var _typeGuards = require("../type-guards.js");
11
+ var _formatting = require("../utils/formatting.js");
12
+ var _encryption = require("../encryption.js");
13
+ /**
14
+ * Field menu module for menu-based struct editing.
15
+ * Handles the sub-menu shown when selecting a field with an existing value.
16
+ */
17
+
18
+ /**
19
+ * Options for the field menu prompt.
20
+ */
21
+
22
+ /**
23
+ * Show a sub-menu for a field that has a value.
24
+ * Provides options to edit, view, clear, set null, or reset to default.
25
+ *
26
+ * @param options - Field menu options
27
+ * @returns The user's chosen action
28
+ */
29
+ async function promptFieldMenu(options) {
30
+ const {
31
+ fieldName,
32
+ fieldType,
33
+ state
34
+ } = options;
35
+ const nullable = (0, _typeGuards.isNullable)(fieldType);
36
+ const hasDefaultVal = (0, _typeGuards.hasDefault)(fieldType);
37
+ const defaultVal = hasDefaultVal ? (0, _typeGuards.getDefault)(fieldType) : undefined;
38
+
39
+ // Build the display of current value
40
+ const currentDisplay = state.status === "null" ? "null" : state.status === "set" ? (0, _formatting.formatValuePreview)(state.value, 40) : "[not set]";
41
+ const choices = [];
42
+
43
+ // Always offer edit
44
+ choices.push({
45
+ name: "Edit value",
46
+ value: "edit"
47
+ });
48
+
49
+ // View full value (only if there's a value to view)
50
+ if (state.status === "set") {
51
+ choices.push({
52
+ name: "View full value",
53
+ value: "view"
54
+ });
55
+ }
56
+
57
+ // For nullable fields with value: offer "Set to null" and "Clear value"
58
+ if (nullable && state.status === "set") {
59
+ choices.push({
60
+ name: "Set to null",
61
+ value: "setNull"
62
+ });
63
+ choices.push({
64
+ name: "Clear value (remove from output)",
65
+ value: "clear"
66
+ });
67
+ }
68
+
69
+ // For nullable fields that are null: offer "Clear value" to remove null
70
+ if (nullable && state.status === "null") {
71
+ choices.push({
72
+ name: "Clear value (remove from output)",
73
+ value: "clear"
74
+ });
75
+ }
76
+
77
+ // For non-nullable fields with default: offer "Reset to default"
78
+ if (hasDefaultVal && !nullable && state.status === "set") {
79
+ const defaultPreview = (0, _formatting.formatValuePreview)(defaultVal, 20);
80
+ choices.push({
81
+ name: `Reset to default (${defaultPreview})`,
82
+ value: "reset"
83
+ });
84
+ }
85
+ choices.push(new _core.Separator());
86
+ choices.push({
87
+ name: "Back (keep current)",
88
+ value: "back"
89
+ });
90
+ const selection = await (0, _prompts.selectWithClear)({
91
+ message: `${fieldName}: ${currentDisplay}`,
92
+ choices
93
+ });
94
+
95
+ // Escape returns to menu
96
+ if (selection === null) {
97
+ return {
98
+ action: "back"
99
+ };
100
+ }
101
+ switch (selection) {
102
+ case "edit":
103
+ // Caller will handle the actual editing
104
+ return {
105
+ action: "edit"
106
+ };
107
+ case "view":
108
+ return {
109
+ action: "view"
110
+ };
111
+ case "clear":
112
+ return {
113
+ action: "clear"
114
+ };
115
+ case "setNull":
116
+ return {
117
+ action: "setNull"
118
+ };
119
+ case "reset":
120
+ return {
121
+ action: "reset",
122
+ defaultValue: defaultVal
123
+ };
124
+ case "back":
125
+ default:
126
+ return {
127
+ action: "back"
128
+ };
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Display the full value of a field.
134
+ * Shows formatted JSON and waits for user to press Enter.
135
+ *
136
+ * @param fieldName - The field name
137
+ * @param value - The value to display
138
+ */
139
+ async function displayFullValue(fieldName, value) {
140
+ const header = `Current value of ${fieldName}:`;
141
+ const jsonStr = JSON.stringify(value, _encryption.bigIntReplacer, 2);
142
+ const jsonLines = jsonStr.split("\n").length;
143
+ console.log("");
144
+ console.log(header);
145
+ console.log(jsonStr);
146
+ console.log("");
147
+
148
+ // Wait for user to press Enter
149
+ await (0, _prompts.selectWithClear)({
150
+ message: "Press Enter to continue...",
151
+ choices: [{
152
+ name: "Continue",
153
+ value: "continue"
154
+ }]
155
+ });
156
+
157
+ // Clear all the output lines: empty line + header + json lines + empty line
158
+ const totalLines = 1 + 1 + jsonLines + 1;
159
+ process.stdout.write("\x1b[1A\x1b[2K".repeat(totalLines) + "\x1b[G");
160
+ }
161
+ //# sourceMappingURL=field-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-menu.js","names":["_core","require","_prompts","_typeGuards","_formatting","_encryption","promptFieldMenu","options","fieldName","fieldType","state","nullable","isNullable","hasDefaultVal","hasDefault","defaultVal","getDefault","undefined","currentDisplay","status","formatValuePreview","value","choices","push","name","defaultPreview","Separator","selection","selectWithClear","message","action","defaultValue","displayFullValue","header","jsonStr","JSON","stringify","bigIntReplacer","jsonLines","split","length","console","log","totalLines","process","stdout","write","repeat"],"sources":["../../../../src/Sprinkle/menus/field-menu.ts"],"sourcesContent":["/**\n * Field menu module for menu-based struct editing.\n * Handles the sub-menu shown when selecting a field with an existing value.\n */\n\nimport { Separator } from \"@inquirer/core\";\nimport type { TSchema } from \"@sinclair/typebox\";\nimport { selectWithClear } from \"../prompts.js\";\nimport type { FieldMenuResult, FieldState } from \"../types.js\";\nimport { isNullable, hasDefault, getDefault } from \"../type-guards.js\";\nimport { formatValuePreview } from \"../utils/formatting.js\";\nimport { bigIntReplacer } from \"../encryption.js\";\n\n/**\n * Options for the field menu prompt.\n */\nexport interface FieldMenuOptions<T> {\n /** The field name */\n fieldName: string;\n /** The field's schema */\n fieldType: TSchema;\n /** Current state of the field */\n state: FieldState<T>;\n}\n\n/**\n * Show a sub-menu for a field that has a value.\n * Provides options to edit, view, clear, set null, or reset to default.\n *\n * @param options - Field menu options\n * @returns The user's chosen action\n */\nexport async function promptFieldMenu<T>(\n options: FieldMenuOptions<T>,\n): Promise<FieldMenuResult<T>> {\n const { fieldName, fieldType, state } = options;\n\n const nullable = isNullable(fieldType);\n const hasDefaultVal = hasDefault(fieldType);\n const defaultVal = hasDefaultVal ? getDefault(fieldType) : undefined;\n\n // Build the display of current value\n const currentDisplay =\n state.status === \"null\"\n ? \"null\"\n : state.status === \"set\"\n ? formatValuePreview(state.value, 40)\n : \"[not set]\";\n\n const choices: Array<{ name: string; value: string } | Separator> = [];\n\n // Always offer edit\n choices.push({ name: \"Edit value\", value: \"edit\" });\n\n // View full value (only if there's a value to view)\n if (state.status === \"set\") {\n choices.push({ name: \"View full value\", value: \"view\" });\n }\n\n // For nullable fields with value: offer \"Set to null\" and \"Clear value\"\n if (nullable && state.status === \"set\") {\n choices.push({ name: \"Set to null\", value: \"setNull\" });\n choices.push({ name: \"Clear value (remove from output)\", value: \"clear\" });\n }\n\n // For nullable fields that are null: offer \"Clear value\" to remove null\n if (nullable && state.status === \"null\") {\n choices.push({ name: \"Clear value (remove from output)\", value: \"clear\" });\n }\n\n // For non-nullable fields with default: offer \"Reset to default\"\n if (hasDefaultVal && !nullable && state.status === \"set\") {\n const defaultPreview = formatValuePreview(defaultVal, 20);\n choices.push({\n name: `Reset to default (${defaultPreview})`,\n value: \"reset\",\n });\n }\n\n choices.push(new Separator());\n choices.push({ name: \"Back (keep current)\", value: \"back\" });\n\n const selection = await selectWithClear({\n message: `${fieldName}: ${currentDisplay}`,\n choices,\n });\n\n // Escape returns to menu\n if (selection === null) {\n return { action: \"back\" };\n }\n\n switch (selection) {\n case \"edit\":\n // Caller will handle the actual editing\n return { action: \"edit\" };\n\n case \"view\":\n return { action: \"view\" };\n\n case \"clear\":\n return { action: \"clear\" };\n\n case \"setNull\":\n return { action: \"setNull\" };\n\n case \"reset\":\n return { action: \"reset\", defaultValue: defaultVal as T };\n\n case \"back\":\n default:\n return { action: \"back\" };\n }\n}\n\n/**\n * Display the full value of a field.\n * Shows formatted JSON and waits for user to press Enter.\n *\n * @param fieldName - The field name\n * @param value - The value to display\n */\nexport async function displayFullValue(\n fieldName: string,\n value: unknown,\n): Promise<void> {\n const header = `Current value of ${fieldName}:`;\n const jsonStr = JSON.stringify(value, bigIntReplacer, 2);\n const jsonLines = jsonStr.split(\"\\n\").length;\n\n console.log(\"\");\n console.log(header);\n console.log(jsonStr);\n console.log(\"\");\n\n // Wait for user to press Enter\n await selectWithClear({\n message: \"Press Enter to continue...\",\n choices: [{ name: \"Continue\", value: \"continue\" }],\n });\n\n // Clear all the output lines: empty line + header + json lines + empty line\n const totalLines = 1 + 1 + jsonLines + 1;\n process.stdout.write(\"\\x1b[1A\\x1b[2K\".repeat(totalLines) + \"\\x1b[G\");\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "displayFullValue", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _fieldMenu.displayFullValue;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "promptArray", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _arrayMenu.promptArray;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "promptFieldMenu", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _fieldMenu.promptFieldMenu;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "promptObject", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _objectMenu.promptObject;
28
+ }
29
+ });
30
+ var _fieldMenu = require("./field-menu.js");
31
+ var _objectMenu = require("./object-menu.js");
32
+ var _arrayMenu = require("./array-menu.js");
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["_fieldMenu","require","_objectMenu","_arrayMenu"],"sources":["../../../../src/Sprinkle/menus/index.ts"],"sourcesContent":["/**\n * Menu modules for menu-based struct editing.\n */\n\nexport { promptFieldMenu, displayFullValue } from \"./field-menu.js\";\nexport type { FieldMenuOptions } from \"./field-menu.js\";\n\nexport { promptObject } from \"./object-menu.js\";\nexport type { ObjectMenuOptions, FillFunction } from \"./object-menu.js\";\n\nexport { promptArray } from \"./array-menu.js\";\nexport type { ArrayMenuOptions } from \"./array-menu.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAAA,UAAA,GAAAC,OAAA;AAGA,IAAAC,WAAA,GAAAD,OAAA;AAGA,IAAAE,UAAA,GAAAF,OAAA","ignoreList":[]}
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.promptObject = promptObject;
7
+ var _core = require("@inquirer/core");
8
+ var _prompts = require("../prompts.js");
9
+ var _yoctocolorsCjs = _interopRequireDefault(require("yoctocolors-cjs"));
10
+ var _types = require("../types.js");
11
+ var _typeGuards = require("../type-guards.js");
12
+ var _fieldUtils = require("../utils/field-utils.js");
13
+ var _formatting = require("../utils/formatting.js");
14
+ var _fieldMenu = require("./field-menu.js");
15
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
16
+ /**
17
+ * Object menu module for menu-based struct editing.
18
+ * Shows all fields of an object and allows non-linear editing.
19
+ */
20
+
21
+ /**
22
+ * Type for the fill function that handles individual field types.
23
+ */
24
+
25
+ /**
26
+ * Options for the object menu prompt.
27
+ */
28
+
29
+ /**
30
+ * Show a menu-based editor for an object.
31
+ * Allows non-linear editing of fields with Submit/Cancel.
32
+ *
33
+ * @param options - Object menu options
34
+ * @returns The edited object or cancel result
35
+ */
36
+ async function promptObject(options) {
37
+ const {
38
+ type,
39
+ path,
40
+ defs,
41
+ defaults = {},
42
+ fillField
43
+ } = options;
44
+ const fields = type.properties;
45
+ const fieldNames = Object.keys(fields);
46
+
47
+ // Edge case: empty struct
48
+ if (fieldNames.length === 0) {
49
+ return {
50
+ action: "submit",
51
+ value: {}
52
+ };
53
+ }
54
+
55
+ // Edge case: single required field with no optionals - skip menu
56
+ const requiredFields = fieldNames.filter(name => (0, _fieldUtils.isFieldRequired)(fields[name]));
57
+ const optionalFields = fieldNames.filter(name => !(0, _fieldUtils.isFieldRequired)(fields[name]));
58
+ if (requiredFields.length === 1 && optionalFields.length === 0) {
59
+ const fieldName = requiredFields[0];
60
+ const fieldType = fields[fieldName];
61
+ try {
62
+ const value = await fillField(fieldType, [...path, fieldName], defs, defaults[fieldName]);
63
+ return {
64
+ action: "submit",
65
+ value: {
66
+ [fieldName]: value
67
+ }
68
+ };
69
+ } catch (e) {
70
+ if (e instanceof _types.UserCancelledError) {
71
+ return {
72
+ action: "cancel"
73
+ };
74
+ }
75
+ throw e;
76
+ }
77
+ }
78
+
79
+ // Initialize state for all fields
80
+ const state = new Map();
81
+ for (const fieldName of fieldNames) {
82
+ const fieldType = fields[fieldName];
83
+ // Auto-fill Literal fields with their const value
84
+ if ((0, _typeGuards.isLiteral)(fieldType)) {
85
+ state.set(fieldName, {
86
+ status: "set",
87
+ value: fieldType.const
88
+ });
89
+ } else {
90
+ state.set(fieldName, (0, _fieldUtils.getInitialFieldState)(fieldType, defaults[fieldName]));
91
+ }
92
+ }
93
+
94
+ // Main menu loop
95
+ while (true) {
96
+ const {
97
+ total,
98
+ filled
99
+ } = (0, _fieldUtils.countRequiredFields)(type, state);
100
+ const canSubmit = (0, _fieldUtils.allRequiredFieldsFilled)(type, state);
101
+
102
+ // Build menu choices
103
+ const choices = [];
104
+
105
+ // Add field items
106
+ for (const fieldName of fieldNames) {
107
+ const fieldType = fields[fieldName];
108
+ const fieldState = state.get(fieldName);
109
+ const label = (0, _fieldUtils.buildFieldLabel)(fieldName, fieldType, fieldState);
110
+ choices.push({
111
+ name: label,
112
+ value: `field:${fieldName}`
113
+ });
114
+ }
115
+
116
+ // Add separator and actions
117
+ choices.push(new _core.Separator("\u2500\u2500\u2500 Actions \u2500\u2500\u2500"));
118
+
119
+ // Submit button
120
+ if (canSubmit) {
121
+ choices.push({
122
+ name: "Submit",
123
+ value: "submit"
124
+ });
125
+ } else {
126
+ choices.push({
127
+ name: `Submit (${filled} of ${total} required complete)`,
128
+ value: "submit",
129
+ disabled: true
130
+ });
131
+ }
132
+ choices.push({
133
+ name: "Cancel",
134
+ value: "cancel"
135
+ });
136
+
137
+ // Show breadcrumb header if we're in a nested path
138
+ const breadcrumb = (0, _formatting.formatBreadcrumb)(path);
139
+ if (breadcrumb) {
140
+ console.log(_yoctocolorsCjs.default.dim(`📍 ${breadcrumb}`));
141
+ }
142
+
143
+ // Show menu
144
+ const selection = await (0, _prompts.selectWithClear)({
145
+ message: "Edit:",
146
+ choices
147
+ });
148
+
149
+ // Clear the breadcrumb line too if we printed one
150
+ if (breadcrumb) {
151
+ (0, _prompts.clearLines)(1);
152
+ }
153
+
154
+ // Handle escape
155
+ if (selection === null) {
156
+ // Check if any values have been set
157
+ const hasValues = Array.from(state.values()).some(s => s.status === "set" || s.status === "null");
158
+ if (hasValues) {
159
+ const confirmCancel = await (0, _prompts.confirmWithClear)({
160
+ message: "Discard changes?",
161
+ default: false
162
+ });
163
+ if (confirmCancel === null || confirmCancel === false) {
164
+ continue; // Return to menu
165
+ }
166
+ }
167
+ return {
168
+ action: "cancel"
169
+ };
170
+ }
171
+
172
+ // Handle submit
173
+ if (selection === "submit") {
174
+ if (!canSubmit) {
175
+ continue; // Shouldn't happen due to disabled, but be safe
176
+ }
177
+ const result = buildResultObject(fields, state, defs);
178
+ return {
179
+ action: "submit",
180
+ value: result
181
+ };
182
+ }
183
+
184
+ // Handle cancel
185
+ if (selection === "cancel") {
186
+ const hasValues = Array.from(state.values()).some(s => s.status === "set" || s.status === "null");
187
+ if (hasValues) {
188
+ const confirmCancel = await (0, _prompts.confirmWithClear)({
189
+ message: "Discard changes?",
190
+ default: false
191
+ });
192
+ if (confirmCancel === null || confirmCancel === false) {
193
+ continue;
194
+ }
195
+ }
196
+ return {
197
+ action: "cancel"
198
+ };
199
+ }
200
+
201
+ // Handle field selection
202
+ if (typeof selection === "string" && selection.startsWith("field:")) {
203
+ const fieldName = selection.slice(6);
204
+ const fieldType = fields[fieldName];
205
+ const fieldState = state.get(fieldName);
206
+
207
+ // If field has a value, show field sub-menu
208
+ if (fieldState.status === "set" || fieldState.status === "null") {
209
+ const menuResult = await (0, _fieldMenu.promptFieldMenu)({
210
+ fieldName,
211
+ fieldType,
212
+ state: fieldState
213
+ });
214
+ switch (menuResult.action) {
215
+ case "edit":
216
+ {
217
+ // Edit the field
218
+ try {
219
+ const newValue = await fillField(fieldType, [...path, fieldName], defs, fieldState.status === "set" ? fieldState.value : undefined);
220
+ state.set(fieldName, {
221
+ status: "set",
222
+ value: newValue
223
+ });
224
+ } catch (e) {
225
+ if (e instanceof _types.UserCancelledError) {
226
+ // Return to menu without changing
227
+ continue;
228
+ }
229
+ throw e;
230
+ }
231
+ break;
232
+ }
233
+ case "view":
234
+ {
235
+ if (fieldState.status === "set") {
236
+ await (0, _fieldMenu.displayFullValue)(fieldName, fieldState.value);
237
+ }
238
+ break;
239
+ }
240
+ case "clear":
241
+ {
242
+ state.set(fieldName, {
243
+ status: "unset"
244
+ });
245
+ break;
246
+ }
247
+ case "setNull":
248
+ {
249
+ state.set(fieldName, {
250
+ status: "null"
251
+ });
252
+ break;
253
+ }
254
+ case "reset":
255
+ {
256
+ // Reset to default value - show as unset, will use default on submit
257
+ state.set(fieldName, {
258
+ status: "unset"
259
+ });
260
+ break;
261
+ }
262
+ case "back":
263
+ // Do nothing, return to main menu
264
+ break;
265
+ }
266
+ } else {
267
+ // Field is unset - directly prompt for value
268
+ try {
269
+ const newValue = await fillField(fieldType, [...path, fieldName], defs, defaults[fieldName]);
270
+ // If user skipped an optional field (returned undefined), leave as unset
271
+ if (newValue === undefined) {
272
+ // Don't change state - field remains unset
273
+ } else {
274
+ state.set(fieldName, {
275
+ status: "set",
276
+ value: newValue
277
+ });
278
+ }
279
+ } catch (e) {
280
+ if (e instanceof _types.UserCancelledError) {
281
+ // Return to menu without changing
282
+ continue;
283
+ }
284
+ throw e;
285
+ }
286
+ }
287
+ }
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Build the result object from the state map.
293
+ * Applies defaults for unset fields with defaults.
294
+ */
295
+ function buildResultObject(fields, state, _defs) {
296
+ const result = {};
297
+ for (const [fieldName, fieldType] of Object.entries(fields)) {
298
+ const fieldState = state.get(fieldName);
299
+ if (!fieldState || fieldState.status === "unset") {
300
+ // If optional, skip (undefined)
301
+ if ((0, _typeGuards.isOptional)(fieldType)) {
302
+ continue;
303
+ }
304
+
305
+ // If field has a default, use it
306
+ if ((0, _typeGuards.hasDefault)(fieldType)) {
307
+ result[fieldName] = (0, _typeGuards.getDefault)(fieldType);
308
+ continue;
309
+ }
310
+
311
+ // No value, no default: omit from output
312
+ continue;
313
+ }
314
+ if (fieldState.status === "null") {
315
+ result[fieldName] = null;
316
+ continue;
317
+ }
318
+ if (fieldState.status === "set") {
319
+ result[fieldName] = fieldState.value;
320
+ }
321
+ }
322
+ return result;
323
+ }
324
+ //# sourceMappingURL=object-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-menu.js","names":["_core","require","_prompts","_yoctocolorsCjs","_interopRequireDefault","_types","_typeGuards","_fieldUtils","_formatting","_fieldMenu","e","__esModule","default","promptObject","options","type","path","defs","defaults","fillField","fields","properties","fieldNames","Object","keys","length","action","value","requiredFields","filter","name","isFieldRequired","optionalFields","fieldName","fieldType","UserCancelledError","state","Map","isLiteral","set","status","const","getInitialFieldState","total","filled","countRequiredFields","canSubmit","allRequiredFieldsFilled","choices","fieldState","get","label","buildFieldLabel","push","Separator","disabled","breadcrumb","formatBreadcrumb","console","log","colors","dim","selection","selectWithClear","message","clearLines","hasValues","Array","from","values","some","s","confirmCancel","confirmWithClear","result","buildResultObject","startsWith","slice","menuResult","promptFieldMenu","newValue","undefined","displayFullValue","_defs","entries","isOptional","hasDefault","getDefault"],"sources":["../../../../src/Sprinkle/menus/object-menu.ts"],"sourcesContent":["/**\n * Object menu module for menu-based struct editing.\n * Shows all fields of an object and allows non-linear editing.\n */\n\nimport { Separator } from \"@inquirer/core\";\nimport type { TObject, TSchema } from \"@sinclair/typebox\";\nimport { selectWithClear, confirmWithClear, clearLines } from \"../prompts.js\";\nimport colors from \"yoctocolors-cjs\";\nimport type { FieldState, ObjectMenuResult } from \"../types.js\";\nimport { UserCancelledError } from \"../types.js\";\nimport { isOptional, hasDefault, getDefault, isNullable, isLiteral } from \"../type-guards.js\";\nimport {\n buildFieldLabel,\n countRequiredFields,\n allRequiredFieldsFilled,\n getInitialFieldState,\n isFieldRequired,\n} from \"../utils/field-utils.js\";\nimport { formatBreadcrumb } from \"../utils/formatting.js\";\nimport { promptFieldMenu, displayFullValue } from \"./field-menu.js\";\n\n/**\n * Type for the fill function that handles individual field types.\n */\nexport type FillFunction = <U extends TSchema>(\n type: U,\n path: string[],\n defs: Record<string, TSchema>,\n def?: unknown,\n) => Promise<unknown>;\n\n/**\n * Options for the object menu prompt.\n */\nexport interface ObjectMenuOptions {\n /** The object schema */\n type: TObject;\n /** Current path for display */\n path: string[];\n /** Type definitions for resolving refs */\n defs: Record<string, TSchema>;\n /** Default/existing values */\n defaults?: Record<string, unknown>;\n /** Function to fill individual fields */\n fillField: FillFunction;\n}\n\n/**\n * Show a menu-based editor for an object.\n * Allows non-linear editing of fields with Submit/Cancel.\n *\n * @param options - Object menu options\n * @returns The edited object or cancel result\n */\nexport async function promptObject<T extends Record<string, unknown>>(\n options: ObjectMenuOptions,\n): Promise<ObjectMenuResult<T>> {\n const { type, path, defs, defaults = {}, fillField } = options;\n\n const fields = type.properties as Record<string, TSchema>;\n const fieldNames = Object.keys(fields);\n\n // Edge case: empty struct\n if (fieldNames.length === 0) {\n return { action: \"submit\", value: {} as T };\n }\n\n // Edge case: single required field with no optionals - skip menu\n const requiredFields = fieldNames.filter((name) =>\n isFieldRequired(fields[name]!),\n );\n const optionalFields = fieldNames.filter(\n (name) => !isFieldRequired(fields[name]!),\n );\n\n if (requiredFields.length === 1 && optionalFields.length === 0) {\n const fieldName = requiredFields[0]!;\n const fieldType = fields[fieldName]!;\n try {\n const value = await fillField(\n fieldType,\n [...path, fieldName],\n defs,\n defaults[fieldName],\n );\n return {\n action: \"submit\",\n value: { [fieldName]: value } as T,\n };\n } catch (e) {\n if (e instanceof UserCancelledError) {\n return { action: \"cancel\" };\n }\n throw e;\n }\n }\n\n // Initialize state for all fields\n const state = new Map<string, FieldState>();\n for (const fieldName of fieldNames) {\n const fieldType = fields[fieldName]!;\n // Auto-fill Literal fields with their const value\n if (isLiteral(fieldType)) {\n state.set(fieldName, { status: \"set\", value: fieldType.const });\n } else {\n state.set(fieldName, getInitialFieldState(fieldType, defaults[fieldName]));\n }\n }\n\n // Main menu loop\n while (true) {\n const { total, filled } = countRequiredFields(type, state);\n const canSubmit = allRequiredFieldsFilled(type, state);\n\n // Build menu choices\n const choices: Array<{ name: string; value: string; disabled?: boolean | string } | Separator> = [];\n\n // Add field items\n for (const fieldName of fieldNames) {\n const fieldType = fields[fieldName]!;\n const fieldState = state.get(fieldName)!;\n const label = buildFieldLabel(fieldName, fieldType, fieldState);\n choices.push({ name: label, value: `field:${fieldName}` });\n }\n\n // Add separator and actions\n choices.push(new Separator(\"\\u2500\\u2500\\u2500 Actions \\u2500\\u2500\\u2500\"));\n\n // Submit button\n if (canSubmit) {\n choices.push({ name: \"Submit\", value: \"submit\" });\n } else {\n choices.push({\n name: `Submit (${filled} of ${total} required complete)`,\n value: \"submit\",\n disabled: true,\n });\n }\n\n choices.push({ name: \"Cancel\", value: \"cancel\" });\n\n // Show breadcrumb header if we're in a nested path\n const breadcrumb = formatBreadcrumb(path);\n if (breadcrumb) {\n console.log(colors.dim(`📍 ${breadcrumb}`));\n }\n\n // Show menu\n const selection = await selectWithClear({\n message: \"Edit:\",\n choices,\n });\n\n // Clear the breadcrumb line too if we printed one\n if (breadcrumb) {\n clearLines(1);\n }\n\n // Handle escape\n if (selection === null) {\n // Check if any values have been set\n const hasValues = Array.from(state.values()).some(\n (s) => s.status === \"set\" || s.status === \"null\",\n );\n\n if (hasValues) {\n const confirmCancel = await confirmWithClear({\n message: \"Discard changes?\",\n default: false,\n });\n if (confirmCancel === null || confirmCancel === false) {\n continue; // Return to menu\n }\n }\n return { action: \"cancel\" };\n }\n\n // Handle submit\n if (selection === \"submit\") {\n if (!canSubmit) {\n continue; // Shouldn't happen due to disabled, but be safe\n }\n const result = buildResultObject(fields, state, defs);\n return { action: \"submit\", value: result as T };\n }\n\n // Handle cancel\n if (selection === \"cancel\") {\n const hasValues = Array.from(state.values()).some(\n (s) => s.status === \"set\" || s.status === \"null\",\n );\n\n if (hasValues) {\n const confirmCancel = await confirmWithClear({\n message: \"Discard changes?\",\n default: false,\n });\n if (confirmCancel === null || confirmCancel === false) {\n continue;\n }\n }\n return { action: \"cancel\" };\n }\n\n // Handle field selection\n if (typeof selection === \"string\" && selection.startsWith(\"field:\")) {\n const fieldName = selection.slice(6);\n const fieldType = fields[fieldName]!;\n const fieldState = state.get(fieldName)!;\n\n // If field has a value, show field sub-menu\n if (fieldState.status === \"set\" || fieldState.status === \"null\") {\n const menuResult = await promptFieldMenu({\n fieldName,\n fieldType,\n state: fieldState,\n });\n\n switch (menuResult.action) {\n case \"edit\": {\n // Edit the field\n try {\n const newValue = await fillField(\n fieldType,\n [...path, fieldName],\n defs,\n fieldState.status === \"set\" ? fieldState.value : undefined,\n );\n state.set(fieldName, { status: \"set\", value: newValue });\n } catch (e) {\n if (e instanceof UserCancelledError) {\n // Return to menu without changing\n continue;\n }\n throw e;\n }\n break;\n }\n\n case \"view\": {\n if (fieldState.status === \"set\") {\n await displayFullValue(fieldName, fieldState.value);\n }\n break;\n }\n\n case \"clear\": {\n state.set(fieldName, { status: \"unset\" });\n break;\n }\n\n case \"setNull\": {\n state.set(fieldName, { status: \"null\" });\n break;\n }\n\n case \"reset\": {\n // Reset to default value - show as unset, will use default on submit\n state.set(fieldName, { status: \"unset\" });\n break;\n }\n\n case \"back\":\n // Do nothing, return to main menu\n break;\n }\n } else {\n // Field is unset - directly prompt for value\n try {\n const newValue = await fillField(\n fieldType,\n [...path, fieldName],\n defs,\n defaults[fieldName],\n );\n // If user skipped an optional field (returned undefined), leave as unset\n if (newValue === undefined) {\n // Don't change state - field remains unset\n } else {\n state.set(fieldName, { status: \"set\", value: newValue });\n }\n } catch (e) {\n if (e instanceof UserCancelledError) {\n // Return to menu without changing\n continue;\n }\n throw e;\n }\n }\n }\n }\n}\n\n/**\n * Build the result object from the state map.\n * Applies defaults for unset fields with defaults.\n */\nfunction buildResultObject(\n fields: Record<string, TSchema>,\n state: Map<string, FieldState>,\n _defs: Record<string, TSchema>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n for (const [fieldName, fieldType] of Object.entries(fields)) {\n const fieldState = state.get(fieldName);\n\n if (!fieldState || fieldState.status === \"unset\") {\n // If optional, skip (undefined)\n if (isOptional(fieldType)) {\n continue;\n }\n\n // If field has a default, use it\n if (hasDefault(fieldType)) {\n result[fieldName] = getDefault(fieldType);\n continue;\n }\n\n // No value, no default: omit from output\n continue;\n }\n\n if (fieldState.status === \"null\") {\n result[fieldName] = null;\n continue;\n }\n\n if (fieldState.status === \"set\") {\n result[fieldName] = fieldState.value;\n }\n }\n\n return result;\n}\n"],"mappings":"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","ignoreList":[]}