@sundaeswap/sprinkles 0.5.0 → 0.6.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 (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 +242 -87
  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 +135 -91
  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 +243 -88
  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 +102 -93
  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 +252 -103
  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 +131 -119
  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
@@ -23,6 +23,11 @@ var _exportNames = {
23
23
  isTuple: true,
24
24
  isUnion: true,
25
25
  isSensitive: true,
26
+ isNull: true,
27
+ isNullable: true,
28
+ unwrapNullable: true,
29
+ hasDefault: true,
30
+ getDefault: true,
26
31
  GetProvider: true,
27
32
  GetWallet: true,
28
33
  GetBlaze: true
@@ -82,6 +87,18 @@ Object.defineProperty(exports, "WalletSettingsSchema", {
82
87
  return _schemas.WalletSettingsSchema;
83
88
  }
84
89
  });
90
+ Object.defineProperty(exports, "getDefault", {
91
+ enumerable: true,
92
+ get: function () {
93
+ return _typeGuards.getDefault;
94
+ }
95
+ });
96
+ Object.defineProperty(exports, "hasDefault", {
97
+ enumerable: true,
98
+ get: function () {
99
+ return _typeGuards.hasDefault;
100
+ }
101
+ });
85
102
  Object.defineProperty(exports, "isArray", {
86
103
  enumerable: true,
87
104
  get: function () {
@@ -106,6 +123,18 @@ Object.defineProperty(exports, "isLiteral", {
106
123
  return _typeGuards.isLiteral;
107
124
  }
108
125
  });
126
+ Object.defineProperty(exports, "isNull", {
127
+ enumerable: true,
128
+ get: function () {
129
+ return _typeGuards.isNull;
130
+ }
131
+ });
132
+ Object.defineProperty(exports, "isNullable", {
133
+ enumerable: true,
134
+ get: function () {
135
+ return _typeGuards.isNullable;
136
+ }
137
+ });
109
138
  Object.defineProperty(exports, "isObject", {
110
139
  enumerable: true,
111
140
  get: function () {
@@ -154,9 +183,16 @@ Object.defineProperty(exports, "isUnion", {
154
183
  return _typeGuards.isUnion;
155
184
  }
156
185
  });
186
+ Object.defineProperty(exports, "unwrapNullable", {
187
+ enumerable: true,
188
+ get: function () {
189
+ return _typeGuards.unwrapNullable;
190
+ }
191
+ });
157
192
  var _sdk = require("@blaze-cardano/sdk");
158
193
  var _core = require("@blaze-cardano/core");
159
194
  var _prompts = require("./prompts.js");
195
+ var _yoctocolorsCjs = _interopRequireDefault(require("yoctocolors-cjs"));
160
196
  var _typebox = require("@sinclair/typebox");
161
197
  Object.keys(_typebox).forEach(function (key) {
162
198
  if (key === "default" || key === "__esModule") return;
@@ -177,6 +213,9 @@ var _typeGuards = require("./type-guards.js");
177
213
  var _wallet = require("./wallet.js");
178
214
  var _encryption = require("./encryption.js");
179
215
  var _txDialog = require("./tx-dialog.js");
216
+ var _index = require("./menus/index.js");
217
+ var _formatting = require("./utils/formatting.js");
218
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
180
219
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
181
220
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
182
221
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
@@ -187,6 +226,7 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
187
226
  // Import and re-export wallet utilities
188
227
  // Import encryption utilities
189
228
  // Import tx-dialog utilities
229
+ // Import menu modules
190
230
  class Sprinkle {
191
231
  constructor(type, storagePath, options) {
192
232
  _defineProperty(this, "storagePath", void 0);
@@ -509,9 +549,13 @@ class Sprinkle {
509
549
  // --- Menu ---
510
550
 
511
551
  async showMenu(menu) {
512
- return this._showMenu(menu, true);
552
+ return this._showMenu(menu, true, [menu.title]);
513
553
  }
514
- async _showMenu(menu, main) {
554
+ async _showMenu(menu, main, path, clearPrevious = false) {
555
+ // Clear previous breadcrumb if coming back from action/submenu
556
+ if (clearPrevious) {
557
+ process.stdout.write("\x1b[1A\x1b[2K\x1b[G");
558
+ }
515
559
  if (menu.beforeShow) {
516
560
  await menu.beforeShow(this);
517
561
  }
@@ -543,11 +587,16 @@ class Sprinkle {
543
587
  value: -1
544
588
  });
545
589
  }
546
- const selectionResult = await (0, _prompts.selectCancellable)({
590
+
591
+ // Show breadcrumb
592
+ const breadcrumb = path.join(" > ");
593
+ console.log(_yoctocolorsCjs.default.dim("🍞 " + breadcrumb));
594
+ const selectionResult = await (0, _prompts.selectWithClear)({
547
595
  message: "Select an option:",
548
596
  choices: choices
549
597
  });
550
598
  // Handle escape (null) as Back
599
+ // Don't clear here - let the caller's clearPrevious handle it
551
600
  if (selectionResult === null) {
552
601
  return;
553
602
  }
@@ -558,7 +607,21 @@ class Sprinkle {
558
607
  items: [{
559
608
  title: "View settings",
560
609
  action: async () => {
561
- console.log(JSON.stringify(this.getDisplaySettings(), _encryption.bigIntReplacer, 2));
610
+ const jsonStr = JSON.stringify(this.getDisplaySettings(), _encryption.bigIntReplacer, 2);
611
+ const jsonLines = jsonStr.split("\n").length;
612
+ console.log(jsonStr);
613
+
614
+ // Wait for user to press Enter
615
+ await (0, _prompts.selectWithClear)({
616
+ message: "Press Enter to continue...",
617
+ choices: [{
618
+ name: "Continue",
619
+ value: "continue"
620
+ }]
621
+ });
622
+
623
+ // Clear the JSON output
624
+ process.stdout.write("\x1b[1A\x1b[2K".repeat(jsonLines) + "\x1b[G");
562
625
  }
563
626
  }, {
564
627
  title: "Edit settings",
@@ -599,24 +662,28 @@ class Sprinkle {
599
662
  }
600
663
  }]
601
664
  };
602
- await this._showMenu(settingsMenu, false);
603
- await this._showMenu(menu, main);
665
+ await this._showMenu(settingsMenu, false, [...path, "Settings & Profiles"], true);
666
+ await this._showMenu(menu, main, path, true);
604
667
  return;
605
668
  }
606
669
  if (selection === -1) {
670
+ // Don't clear here - let the caller's clearPrevious handle it
607
671
  return;
608
672
  }
609
673
  const selectedItem = menu.items[selection];
610
674
  if ("action" in selectedItem) {
675
+ // Update breadcrumb to show current action
676
+ process.stdout.write("\x1b[1A\x1b[2K\x1b[G");
677
+ console.log(_yoctocolorsCjs.default.dim("🍞 " + [...path, selectedItem.title].join(" > ")));
611
678
  const result = await selectedItem.action(this);
612
679
  if (result instanceof Sprinkle) {
613
680
  this.settings = result.settings;
614
681
  this.saveSettings();
615
682
  }
616
- await this._showMenu(menu, main);
683
+ await this._showMenu(menu, main, path, true);
617
684
  } else {
618
- await this._showMenu(selectedItem, false);
619
- await this._showMenu(menu, main);
685
+ await this._showMenu(selectedItem, false, [...path, selectedItem.title], true);
686
+ await this._showMenu(menu, main, path, true);
620
687
  }
621
688
  return;
622
689
  }
@@ -771,7 +838,7 @@ class Sprinkle {
771
838
  name: "Cancel",
772
839
  value: "cancel"
773
840
  });
774
- const selection = await (0, _prompts.selectCancellable)({
841
+ const selection = await (0, _prompts.selectWithClear)({
775
842
  message: "Select an option:",
776
843
  choices
777
844
  });
@@ -969,46 +1036,18 @@ class Sprinkle {
969
1036
  }
970
1037
  }
971
1038
  }
1039
+
1040
+ /**
1041
+ * Edit an existing struct value using a menu-based interface.
1042
+ * This is now unified with FillInStruct - both use the same menu system.
1043
+ * @param type - The TypeBox schema
1044
+ * @param current - The current value to edit
1045
+ * @returns The edited value
1046
+ */
972
1047
  async EditStruct(type, current) {
973
- return this._editStruct(type, ["root"], current);
974
- }
975
- async _editStruct(type, path, current) {
976
- if ((0, _typeGuards.isObject)(type)) {
977
- const obj = {};
978
- const fields = type["properties"];
979
- const menuItems = [];
980
- const currentRecord = current;
981
- for (const [field, fieldType] of Object.entries(fields)) {
982
- if (current && field in currentRecord) {
983
- obj[field] = currentRecord[field];
984
- }
985
- const menuTitle = Sprinkle.ExtractMessage(fieldType, `Edit ${field} at ${path.join(".")}`);
986
- if ((0, _typeGuards.isOptional)(fieldType) && current && currentRecord[field] !== undefined) {
987
- menuItems.push({
988
- title: `Clear ${field}`,
989
- action: async sprinkle => {
990
- obj[field] = undefined;
991
- return sprinkle;
992
- }
993
- });
994
- }
995
- menuItems.push({
996
- title: menuTitle,
997
- action: async sprinkle => {
998
- const fieldValue = await sprinkle._editStruct(fieldType, path.concat([field]), current && field in currentRecord ? currentRecord[field] : undefined);
999
- obj[field] = fieldValue;
1000
- return sprinkle;
1001
- }
1002
- });
1003
- }
1004
- const editMenu = {
1005
- title: "Test",
1006
- items: menuItems
1007
- };
1008
- await this._showMenu(editMenu, false);
1009
- return obj;
1010
- }
1011
- return this._fillInStruct(type, path, {}, current);
1048
+ // Use FillInStruct with current values as defaults
1049
+ // The menu system will show existing values and allow editing
1050
+ return this.FillInStruct(type, current);
1012
1051
  }
1013
1052
  async FillInStruct(type, def) {
1014
1053
  return this._fillInStruct(type, ["root"], {}, def);
@@ -1026,8 +1065,9 @@ class Sprinkle {
1026
1065
  return this._fillInStruct(resolvedType, path, defs, def);
1027
1066
  }
1028
1067
  if ((0, _typeGuards.isOptional)(type)) {
1029
- const shouldSet = await (0, _prompts.selectCancellable)({
1030
- message: Sprinkle.ExtractMessage(type, `Set value for ${path.join(".")}?`),
1068
+ const pathDisplay = (0, _formatting.formatPath)(path) || "value";
1069
+ const shouldSet = await (0, _prompts.selectWithClear)({
1070
+ message: Sprinkle.ExtractMessage(type, `Set value for ${pathDisplay}?`),
1031
1071
  choices: [{
1032
1072
  name: "Yes",
1033
1073
  value: true
@@ -1051,6 +1091,7 @@ class Sprinkle {
1051
1091
  return this._fillInStruct(innerType, path, defs, def);
1052
1092
  }
1053
1093
  if ((0, _typeGuards.isUnion)(type)) {
1094
+ const pathDisplay = (0, _formatting.formatPath)(path) || "value";
1054
1095
  const choices = [];
1055
1096
  const resolved = this.resolveType(type, path, defs);
1056
1097
  for (const variant of resolved.anyOf) {
@@ -1059,10 +1100,9 @@ class Sprinkle {
1059
1100
  value: variant
1060
1101
  });
1061
1102
  }
1062
- const selectionResult = await (0, _prompts.selectCancellable)({
1063
- message: Sprinkle.ExtractMessage(resolved, `Enter a choice for ${path.join(".")}`),
1064
- choices: choices,
1065
- default: def ? `${def}` : undefined
1103
+ const selectionResult = await (0, _prompts.selectWithClear)({
1104
+ message: Sprinkle.ExtractMessage(resolved, `Enter a choice for ${pathDisplay}`),
1105
+ choices: choices
1066
1106
  });
1067
1107
  if (selectionResult === null) {
1068
1108
  throw new _types.UserCancelledError();
@@ -1073,7 +1113,7 @@ class Sprinkle {
1073
1113
  if ((0, _typeGuards.isString)(type)) {
1074
1114
  // Special handling for hot wallet private key - offer generation option
1075
1115
  if (type.title === "Hot Wallet Private Key") {
1076
- const choice = await (0, _prompts.selectCancellable)({
1116
+ const choice = await (0, _prompts.selectWithClear)({
1077
1117
  message: "Hot wallet setup:",
1078
1118
  choices: [{
1079
1119
  name: "Enter existing private key",
@@ -1090,7 +1130,7 @@ class Sprinkle {
1090
1130
  return Sprinkle.generateWalletFromMnemonic();
1091
1131
  }
1092
1132
  // Fall through to password prompt for "existing" choice
1093
- const answer = await (0, _prompts.passwordCancellable)({
1133
+ const answer = await (0, _prompts.passwordWithClear)({
1094
1134
  message: "Enter your private key:"
1095
1135
  });
1096
1136
  if (answer === null) {
@@ -1098,15 +1138,16 @@ class Sprinkle {
1098
1138
  }
1099
1139
  return answer;
1100
1140
  }
1141
+ const pathDisplay = (0, _formatting.formatPath)(path) || "value";
1101
1142
  const defaultString = def ? def : this.defaults["string"];
1102
- const message = Sprinkle.ExtractMessage(type, `Enter a string for ${path.join(".")}`);
1143
+ const message = Sprinkle.ExtractMessage(type, `Enter a string for ${pathDisplay}`);
1103
1144
  let answer;
1104
1145
  if ((0, _typeGuards.isSensitive)(type)) {
1105
- answer = await (0, _prompts.passwordCancellable)({
1146
+ answer = await (0, _prompts.passwordWithClear)({
1106
1147
  message
1107
1148
  });
1108
1149
  } else {
1109
- answer = await (0, _prompts.inputCancellable)({
1150
+ answer = await (0, _prompts.inputWithClear)({
1110
1151
  message,
1111
1152
  default: defaultString
1112
1153
  });
@@ -1120,8 +1161,9 @@ class Sprinkle {
1120
1161
  return answer;
1121
1162
  }
1122
1163
  if ((0, _typeGuards.isBigInt)(type)) {
1123
- const answer = await (0, _prompts.inputCancellable)({
1124
- message: Sprinkle.ExtractMessage(type, `Enter a bigint for ${path.join(".")}`),
1164
+ const pathDisplay = (0, _formatting.formatPath)(path) || "value";
1165
+ const answer = await (0, _prompts.inputWithClear)({
1166
+ message: Sprinkle.ExtractMessage(type, `Enter a bigint for ${pathDisplay}`),
1125
1167
  default: def ? def.toString() : undefined,
1126
1168
  validate: s => {
1127
1169
  try {
@@ -1141,39 +1183,40 @@ class Sprinkle {
1141
1183
  return type.const;
1142
1184
  }
1143
1185
  if ((0, _typeGuards.isObject)(type)) {
1144
- const obj = {};
1145
- const fields = type["properties"];
1146
- for (const [field, fieldType] of Object.entries(fields)) {
1147
- const fieldValue = await this._fillInStruct(fieldType, path.concat([field]), defs, def ? def[field] : undefined);
1148
- obj[field] = fieldValue;
1186
+ // Use menu-based editing for objects
1187
+ const defaults = def;
1188
+ const sprinkle = this;
1189
+ const result = await (0, _index.promptObject)({
1190
+ type,
1191
+ path,
1192
+ defs,
1193
+ defaults,
1194
+ fillField: async (fieldType, fieldPath, fieldDefs, fieldDef) => {
1195
+ return sprinkle._fillInStruct(fieldType, fieldPath, fieldDefs, fieldDef);
1196
+ }
1197
+ });
1198
+ if (result.action === "cancel") {
1199
+ throw new _types.UserCancelledError();
1149
1200
  }
1150
- return obj;
1201
+ return result.value;
1151
1202
  }
1152
-
1153
- //TODO: support starting with default values for arrays and allow removal of items
1154
1203
  if ((0, _typeGuards.isArray)(type)) {
1155
- const arr = [];
1156
- const itemType = type.items;
1157
- let addMore = true;
1158
- while (addMore) {
1159
- const itemValue = await this._fillInStruct(itemType, path.concat([`[${arr.length}]`]), defs);
1160
- arr.push(itemValue);
1161
- const continueAnswer = await (0, _prompts.selectCancellable)({
1162
- message: `Add another item to ${path.join(".")}?`,
1163
- choices: [{
1164
- name: "Yes",
1165
- value: true
1166
- }, {
1167
- name: "No",
1168
- value: false
1169
- }]
1170
- });
1171
- if (continueAnswer === null) {
1172
- throw new _types.UserCancelledError();
1204
+ // Use menu-based editing for arrays
1205
+ const defaults = def;
1206
+ const sprinkle = this;
1207
+ const result = await (0, _index.promptArray)({
1208
+ type,
1209
+ path,
1210
+ defs,
1211
+ defaults,
1212
+ fillField: async (itemType, itemPath, itemDefs, itemDef) => {
1213
+ return sprinkle._fillInStruct(itemType, itemPath, itemDefs, itemDef);
1173
1214
  }
1174
- addMore = continueAnswer;
1215
+ });
1216
+ if (result.action === "back") {
1217
+ throw new _types.UserCancelledError();
1175
1218
  }
1176
- return arr;
1219
+ return result.value;
1177
1220
  }
1178
1221
  if ((0, _typeGuards.isTuple)(type)) {
1179
1222
  const items = type.items ?? [];
@@ -1185,7 +1228,8 @@ class Sprinkle {
1185
1228
  }
1186
1229
  return result;
1187
1230
  }
1188
- throw new Error(`Unable to fill in struct for type at path ${path.join(".")}`);
1231
+ const pathDisplay = (0, _formatting.formatPath)(path) || "root";
1232
+ throw new Error(`Unable to fill in struct for type at path ${pathDisplay}`);
1189
1233
  }
1190
1234
  resolveType(type, path, defs) {
1191
1235
  if ((0, _typeGuards.isRef)(type) || (0, _typeGuards.isThis)(type) || (0, _typeGuards.isImport)(type)) {