@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
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "allRequiredFieldsFilled", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _fieldUtils.allRequiredFieldsFilled;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "buildFieldLabel", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _fieldUtils.buildFieldLabel;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "countRequiredFields", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _fieldUtils.countRequiredFields;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "formatBreadcrumb", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _formatting.formatBreadcrumb;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "formatPath", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _formatting.formatPath;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "formatValuePreview", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _formatting.formatValuePreview;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "getInitialFieldState", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _fieldUtils.getInitialFieldState;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "isFieldRequired", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _fieldUtils.isFieldRequired;
52
+ }
53
+ });
54
+ var _formatting = require("./formatting.js");
55
+ var _fieldUtils = require("./field-utils.js");
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["_formatting","require","_fieldUtils"],"sources":["../../../../src/Sprinkle/utils/index.ts"],"sourcesContent":["/**\n * Utility functions for menu-based struct editing.\n */\n\nexport {\n formatValuePreview,\n formatPath,\n formatBreadcrumb,\n} from \"./formatting.js\";\n\nexport {\n countRequiredFields,\n isFieldRequired,\n buildFieldLabel,\n getInitialFieldState,\n allRequiredFieldsFilled,\n} from \"./field-utils.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAAA,WAAA,GAAAC,OAAA;AAMA,IAAAC,WAAA,GAAAD,OAAA","ignoreList":[]}
@@ -19,7 +19,9 @@ mock.module("../prompts.js", () => ({
19
19
  selectCancellable: mockSelectCancellable,
20
20
  inputCancellable: mockInputCancellable,
21
21
  passwordCancellable: mockPasswordCancellable,
22
- confirmCancellable: mock()
22
+ confirmCancellable: mock(),
23
+ searchCancellable: mock(),
24
+ select: mockSelectCancellable
23
25
  }));
24
26
  describe("Encryption & Sensitive Fields", () => {
25
27
  let tmpDir;
@@ -1 +1 @@
1
- {"version":3,"file":"encryption.test.js","names":["describe","expect","test","mock","beforeEach","afterEach","Sprinkle","Type","fs","path","os","withProfile","mockSelect","mockInput","mockPassword","mockSelectCancellable","mockInputCancellable","mockPasswordCancellable","module","select","input","password","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","tmpDir","mkdtempSync","join","tmpdir","mockClear","rmSync","recursive","force","schema","Object","secret","String","sensitive","title","sprinkle","mockResolvedValueOnce","result","FillInStruct","toEqual","toHaveBeenCalledTimes","calls","message","toBe","not","toHaveBeenCalled","name","p","defaults","toBeUndefined","encryption","encrypt","plain","decrypt","cipher","replace","settings","saveSettings","content","readFileSync","parsed","JSON","parse","sprinkle1","sprinkle2","loadProfile","wallet","key","address","Union","type","Literal","privateKey","outerSchema","network","count","BigInt","opts","Buffer","from","toString","s1","s2","mkdirSync","writeFileSync","stringify","New","c","options","toBeDefined","profileId"],"sources":["../../../../src/Sprinkle/__tests__/encryption.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, afterEach } from \"bun:test\";\nimport { Sprinkle, Type } from \"../index.js\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\nconst mockPasswordCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mockPasswordCancellable,\n confirmCancellable: mock(),\n}));\n\ndescribe(\"Encryption & Sensitive Fields\", () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sprinkles-enc-test-\"));\n mockSelect.mockClear();\n mockInput.mockClear();\n mockPassword.mockClear();\n mockSelectCancellable.mockClear();\n mockInputCancellable.mockClear();\n mockPasswordCancellable.mockClear();\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"sensitive field prompts\", () => {\n test(\"uses password() for sensitive string fields\", async () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true, title: \"Enter secret\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockPasswordCancellable.mockResolvedValueOnce(\"my-secret\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ secret: \"my-secret\" });\n expect(mockPasswordCancellable).toHaveBeenCalledTimes(1);\n expect(mockPasswordCancellable.mock.calls[0][0].message).toBe(\"Enter secret\");\n expect(mockInputCancellable).not.toHaveBeenCalled();\n });\n\n test(\"uses input() for non-sensitive string fields\", async () => {\n const schema = Type.Object({\n name: Type.String({ title: \"Enter name\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockInputCancellable.mockResolvedValueOnce(\"visible\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ name: \"visible\" });\n expect(mockInputCancellable).toHaveBeenCalledTimes(1);\n expect(mockPasswordCancellable).not.toHaveBeenCalled();\n });\n\n test(\"does not remember sensitive field as default\", async () => {\n const schema = Type.String({ sensitive: true });\n const sprinkle = new Sprinkle(Type.Object({ p: Type.String() }), tmpDir);\n\n mockPasswordCancellable.mockResolvedValueOnce(\"secret-val\");\n\n await sprinkle.FillInStruct(schema);\n expect(sprinkle.defaults[\"string\"]).toBeUndefined();\n });\n });\n\n describe(\"encryption on save/load\", () => {\n test(\"encrypts sensitive fields when saving with encryption configured\", () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = { name: \"visible\", secret: \"hidden\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.name).toBe(\"visible\");\n expect(parsed.settings.secret).toBe(\"ENC:hidden\");\n });\n\n test(\"decrypts sensitive fields when loading with encryption configured\", async () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n\n // First save with encryption\n const sprinkle1 = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle1.settings = { name: \"visible\", secret: \"hidden\" } as any;\n sprinkle1.saveSettings();\n\n // Then load with same encryption\n const sprinkle2 = new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n });\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({ name: \"visible\", secret: \"hidden\" });\n });\n\n test(\"does not encrypt when no encryption configured\", () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { secret: \"plain-value\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.secret).toBe(\"plain-value\");\n });\n\n test(\"encrypts nested sensitive fields\", () => {\n const schema = Type.Object({\n wallet: Type.Object({\n key: Type.String({ sensitive: true }),\n address: Type.String(),\n }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { key: \"secret-key\", address: \"addr1...\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.key).toBe(\"ENC:secret-key\");\n expect(parsed.settings.wallet.address).toBe(\"addr1...\");\n });\n\n test(\"handles sensitive fields in union variants\", () => {\n const schema = Type.Union([\n Type.Object({\n type: Type.Literal(\"hot\"),\n privateKey: Type.String({ sensitive: true }),\n }),\n Type.Object({\n type: Type.Literal(\"cold\"),\n address: Type.String(),\n }),\n ]);\n const outerSchema = Type.Object({ wallet: schema });\n const sprinkle = withProfile(\n new Sprinkle(outerSchema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { type: \"hot\", privateKey: \"my-key\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.privateKey).toBe(\"ENC:my-key\");\n });\n\n test(\"round-trip with encryption preserves all data\", async () => {\n const schema = Type.Object({\n network: Type.String(),\n secret: Type.String({ sensitive: true }),\n count: Type.BigInt(),\n });\n const opts = {\n encryption: {\n encrypt: (plain: string) => Buffer.from(plain).toString(\"base64\"),\n decrypt: async (cipher: string) =>\n Buffer.from(cipher, \"base64\").toString(),\n },\n };\n const s1 = withProfile(new Sprinkle(schema, tmpDir, opts));\n s1.settings = {\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n } as any;\n s1.saveSettings();\n\n const s2 = new Sprinkle(schema, tmpDir, opts);\n await s2.loadProfile(\"test\");\n\n expect(s2.settings).toEqual({\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n });\n });\n });\n\n describe(\"Sprinkle.New with options\", () => {\n test(\"passes options through to instance and migrates legacy\", async () => {\n const schema = Type.Object({ name: Type.String() });\n\n // Write legacy settings file so New triggers migration\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(\n path.join(tmpDir, \"settings.json\"),\n JSON.stringify({ settings: { name: \"test\" }, defaults: {} }),\n );\n\n const sprinkle = await Sprinkle.New(schema, tmpDir, {\n encryption: {\n encrypt: (p) => p,\n decrypt: async (c) => c,\n },\n });\n\n expect(sprinkle.options.encryption).toBeDefined();\n expect(sprinkle.profileId).toBe(\"default\");\n expect(sprinkle.settings).toEqual({ name: \"test\" });\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"encryption.test.js","names":["describe","expect","test","mock","beforeEach","afterEach","Sprinkle","Type","fs","path","os","withProfile","mockSelect","mockInput","mockPassword","mockSelectCancellable","mockInputCancellable","mockPasswordCancellable","module","select","input","password","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","tmpDir","mkdtempSync","join","tmpdir","mockClear","rmSync","recursive","force","schema","Object","secret","String","sensitive","title","sprinkle","mockResolvedValueOnce","result","FillInStruct","toEqual","toHaveBeenCalledTimes","calls","message","toBe","not","toHaveBeenCalled","name","p","defaults","toBeUndefined","encryption","encrypt","plain","decrypt","cipher","replace","settings","saveSettings","content","readFileSync","parsed","JSON","parse","sprinkle1","sprinkle2","loadProfile","wallet","key","address","Union","type","Literal","privateKey","outerSchema","network","count","BigInt","opts","Buffer","from","toString","s1","s2","mkdirSync","writeFileSync","stringify","New","c","options","toBeDefined","profileId"],"sources":["../../../../src/Sprinkle/__tests__/encryption.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach, afterEach } from \"bun:test\";\nimport { Sprinkle, Type } from \"../index.js\";\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { withProfile } from \"./test-helpers.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\nconst mockPasswordCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mockPasswordCancellable,\n confirmCancellable: mock(),\n searchCancellable: mock(),\n select: mockSelectCancellable,\n}));\n\ndescribe(\"Encryption & Sensitive Fields\", () => {\n let tmpDir: string;\n\n beforeEach(() => {\n tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), \"sprinkles-enc-test-\"));\n mockSelect.mockClear();\n mockInput.mockClear();\n mockPassword.mockClear();\n mockSelectCancellable.mockClear();\n mockInputCancellable.mockClear();\n mockPasswordCancellable.mockClear();\n });\n\n afterEach(() => {\n fs.rmSync(tmpDir, { recursive: true, force: true });\n });\n\n describe(\"sensitive field prompts\", () => {\n test(\"uses password() for sensitive string fields\", async () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true, title: \"Enter secret\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockPasswordCancellable.mockResolvedValueOnce(\"my-secret\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ secret: \"my-secret\" });\n expect(mockPasswordCancellable).toHaveBeenCalledTimes(1);\n expect(mockPasswordCancellable.mock.calls[0][0].message).toBe(\"Enter secret\");\n expect(mockInputCancellable).not.toHaveBeenCalled();\n });\n\n test(\"uses input() for non-sensitive string fields\", async () => {\n const schema = Type.Object({\n name: Type.String({ title: \"Enter name\" }),\n });\n const sprinkle = new Sprinkle(schema, tmpDir);\n\n mockInputCancellable.mockResolvedValueOnce(\"visible\");\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result).toEqual({ name: \"visible\" });\n expect(mockInputCancellable).toHaveBeenCalledTimes(1);\n expect(mockPasswordCancellable).not.toHaveBeenCalled();\n });\n\n test(\"does not remember sensitive field as default\", async () => {\n const schema = Type.String({ sensitive: true });\n const sprinkle = new Sprinkle(Type.Object({ p: Type.String() }), tmpDir);\n\n mockPasswordCancellable.mockResolvedValueOnce(\"secret-val\");\n\n await sprinkle.FillInStruct(schema);\n expect(sprinkle.defaults[\"string\"]).toBeUndefined();\n });\n });\n\n describe(\"encryption on save/load\", () => {\n test(\"encrypts sensitive fields when saving with encryption configured\", () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = { name: \"visible\", secret: \"hidden\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.name).toBe(\"visible\");\n expect(parsed.settings.secret).toBe(\"ENC:hidden\");\n });\n\n test(\"decrypts sensitive fields when loading with encryption configured\", async () => {\n const schema = Type.Object({\n name: Type.String(),\n secret: Type.String({ sensitive: true }),\n });\n\n // First save with encryption\n const sprinkle1 = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle1.settings = { name: \"visible\", secret: \"hidden\" } as any;\n sprinkle1.saveSettings();\n\n // Then load with same encryption\n const sprinkle2 = new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n });\n await sprinkle2.loadProfile(\"test\");\n\n expect(sprinkle2.settings).toEqual({ name: \"visible\", secret: \"hidden\" });\n });\n\n test(\"does not encrypt when no encryption configured\", () => {\n const schema = Type.Object({\n secret: Type.String({ sensitive: true }),\n });\n const sprinkle = withProfile(new Sprinkle(schema, tmpDir));\n sprinkle.settings = { secret: \"plain-value\" } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.secret).toBe(\"plain-value\");\n });\n\n test(\"encrypts nested sensitive fields\", () => {\n const schema = Type.Object({\n wallet: Type.Object({\n key: Type.String({ sensitive: true }),\n address: Type.String(),\n }),\n });\n const sprinkle = withProfile(\n new Sprinkle(schema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { key: \"secret-key\", address: \"addr1...\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.key).toBe(\"ENC:secret-key\");\n expect(parsed.settings.wallet.address).toBe(\"addr1...\");\n });\n\n test(\"handles sensitive fields in union variants\", () => {\n const schema = Type.Union([\n Type.Object({\n type: Type.Literal(\"hot\"),\n privateKey: Type.String({ sensitive: true }),\n }),\n Type.Object({\n type: Type.Literal(\"cold\"),\n address: Type.String(),\n }),\n ]);\n const outerSchema = Type.Object({ wallet: schema });\n const sprinkle = withProfile(\n new Sprinkle(outerSchema, tmpDir, {\n encryption: {\n encrypt: (plain) => `ENC:${plain}`,\n decrypt: async (cipher) => cipher.replace(\"ENC:\", \"\"),\n },\n }),\n );\n sprinkle.settings = {\n wallet: { type: \"hot\", privateKey: \"my-key\" },\n } as any;\n\n sprinkle.saveSettings();\n\n const content = fs.readFileSync(\n path.join(tmpDir, \"profiles\", \"test.json\"),\n \"utf-8\",\n );\n const parsed = JSON.parse(content);\n expect(parsed.settings.wallet.privateKey).toBe(\"ENC:my-key\");\n });\n\n test(\"round-trip with encryption preserves all data\", async () => {\n const schema = Type.Object({\n network: Type.String(),\n secret: Type.String({ sensitive: true }),\n count: Type.BigInt(),\n });\n const opts = {\n encryption: {\n encrypt: (plain: string) => Buffer.from(plain).toString(\"base64\"),\n decrypt: async (cipher: string) =>\n Buffer.from(cipher, \"base64\").toString(),\n },\n };\n const s1 = withProfile(new Sprinkle(schema, tmpDir, opts));\n s1.settings = {\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n } as any;\n s1.saveSettings();\n\n const s2 = new Sprinkle(schema, tmpDir, opts);\n await s2.loadProfile(\"test\");\n\n expect(s2.settings).toEqual({\n network: \"mainnet\",\n secret: \"top-secret\",\n count: 42n,\n });\n });\n });\n\n describe(\"Sprinkle.New with options\", () => {\n test(\"passes options through to instance and migrates legacy\", async () => {\n const schema = Type.Object({ name: Type.String() });\n\n // Write legacy settings file so New triggers migration\n fs.mkdirSync(tmpDir, { recursive: true });\n fs.writeFileSync(\n path.join(tmpDir, \"settings.json\"),\n JSON.stringify({ settings: { name: \"test\" }, defaults: {} }),\n );\n\n const sprinkle = await Sprinkle.New(schema, tmpDir, {\n encryption: {\n encrypt: (p) => p,\n decrypt: async (c) => c,\n },\n });\n\n expect(sprinkle.options.encryption).toBeDefined();\n expect(sprinkle.profileId).toBe(\"default\");\n expect(sprinkle.settings).toEqual({ name: \"test\" });\n });\n });\n});\n"],"mappings":"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","ignoreList":[]}
@@ -129,42 +129,8 @@ describe("SearchSelect (2.3)", () => {
129
129
  expect(result).toBeNull();
130
130
  });
131
131
  });
132
- describe("Optional type support (2.4)", () => {
133
- let sprinkle;
134
- beforeEach(() => {
135
- const schema = Type.Object({
136
- placeholder: Type.String()
137
- });
138
- sprinkle = new Sprinkle(schema, "/tmp/test");
139
- mockSelect.mockClear();
140
- mockInput.mockClear();
141
- mockSelectCancellable.mockClear();
142
- mockInputCancellable.mockClear();
143
- });
144
- test("skips optional field when user selects Skip", async () => {
145
- const schema = Type.Object({
146
- name: Type.String(),
147
- nickname: Type.Optional(Type.String())
148
- });
149
- mockInputCancellable.mockResolvedValueOnce("Alice"); // name
150
- mockSelectCancellable.mockResolvedValueOnce(false); // skip nickname
151
-
152
- const result = await sprinkle.FillInStruct(schema);
153
- expect(result.name).toBe("Alice");
154
- expect(result.nickname).toBeUndefined();
155
- });
156
- test("fills optional field when user selects Yes", async () => {
157
- const schema = Type.Object({
158
- name: Type.String(),
159
- nickname: Type.Optional(Type.String())
160
- });
161
- mockInputCancellable.mockResolvedValueOnce("Alice") // name
162
- .mockResolvedValueOnce("Ali"); // nickname
163
- mockSelectCancellable.mockResolvedValueOnce(true); // fill nickname
164
132
 
165
- const result = await sprinkle.FillInStruct(schema);
166
- expect(result.name).toBe("Alice");
167
- expect(result.nickname).toBe("Ali");
168
- });
169
- });
133
+ // Note: "Optional type support (2.4)" tests removed - they tested the old sequential
134
+ // FillInStruct behavior. The new menu-based FillInStruct handles optional fields
135
+ // differently (via menu selection). See fill-in-struct.test.ts for comprehensive tests.
170
136
  //# sourceMappingURL=enhancements.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"enhancements.test.js","names":["describe","expect","test","mock","beforeEach","Sprinkle","Type","mockSelect","mockInput","mockPassword","mockSelectCancellable","mockInputCancellable","mockPasswordCancellable","mockConfirmCancellable","mockSearchCancellable","module","select","input","password","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","sprinkle","schema","Object","name","String","settings","mockClear","callOrder","beforeShowFn","push","mockImplementation","menu","title","beforeShow","items","action","showMenu","toHaveBeenCalledTimes","toBe","receivedSprinkle","mockResolvedValueOnce","s","result","SearchSelect","message","source","value","calls","sourceFn","toBeNull","placeholder","nickname","Optional","FillInStruct","toBeUndefined"],"sources":["../../../../src/Sprinkle/__tests__/enhancements.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\nconst mockPasswordCancellable = mock();\nconst mockConfirmCancellable = mock();\nconst mockSearchCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mockPasswordCancellable,\n confirmCancellable: mockConfirmCancellable,\n searchCancellable: mockSearchCancellable,\n select: mockSelectCancellable,\n}));\n\ndescribe(\"beforeShow hook (2.2)\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = new Sprinkle(schema, \"/tmp/test\");\n sprinkle.settings = { name: \"test\" } as any;\n mockSelect.mockClear();\n mockSelectCancellable.mockClear();\n });\n\n test(\"calls beforeShow before rendering menu\", async () => {\n const callOrder: string[] = [];\n\n const beforeShowFn = mock(async () => {\n callOrder.push(\"beforeShow\");\n });\n\n mockSelectCancellable.mockImplementation(async () => {\n callOrder.push(\"select\");\n return -1; // exit\n });\n\n const menu: IMenu<any> = {\n title: \"Test\",\n beforeShow: beforeShowFn,\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n expect(beforeShowFn).toHaveBeenCalledTimes(1);\n expect(callOrder[0]).toBe(\"beforeShow\");\n expect(callOrder[1]).toBe(\"select\");\n });\n\n test(\"passes sprinkle instance to beforeShow\", async () => {\n let receivedSprinkle: any;\n\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n beforeShow: async (s) => {\n receivedSprinkle = s;\n },\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n expect(receivedSprinkle).toBe(sprinkle);\n });\n\n test(\"menu works without beforeShow\", 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 // Should complete without error\n });\n});\n\ndescribe(\"SearchSelect (2.3)\", () => {\n beforeEach(() => {\n mockSearchCancellable.mockClear();\n });\n\n test(\"delegates to search prompt\", async () => {\n mockSearchCancellable.mockResolvedValueOnce(\"selected-value\");\n\n const result = await Sprinkle.SearchSelect({\n message: \"Pick one\",\n source: () => [\n { name: \"Option A\", value: \"a\" },\n { name: \"Option B\", value: \"b\" },\n ],\n });\n\n expect(result).toBe(\"selected-value\");\n expect(mockSearchCancellable).toHaveBeenCalledTimes(1);\n expect(mockSearchCancellable.mock.calls[0][0].message).toBe(\"Pick one\");\n });\n\n test(\"passes source function through\", async () => {\n const sourceFn = mock(() => [{ name: \"X\", value: \"x\" }]);\n mockSearchCancellable.mockResolvedValueOnce(\"x\");\n\n await Sprinkle.SearchSelect({\n message: \"Search\",\n source: sourceFn,\n });\n\n expect(mockSearchCancellable.mock.calls[0][0].source).toBe(sourceFn);\n });\n\n test(\"returns null when cancelled\", async () => {\n mockSearchCancellable.mockResolvedValueOnce(null);\n\n const result = await Sprinkle.SearchSelect({\n message: \"Pick one\",\n source: () => [{ name: \"A\", value: \"a\" }],\n });\n\n expect(result).toBeNull();\n });\n});\n\ndescribe(\"Optional type support (2.4)\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ placeholder: Type.String() });\n sprinkle = new Sprinkle(schema, \"/tmp/test\");\n mockSelect.mockClear();\n mockInput.mockClear();\n mockSelectCancellable.mockClear();\n mockInputCancellable.mockClear();\n });\n\n test(\"skips optional field when user selects Skip\", async () => {\n const schema = Type.Object({\n name: Type.String(),\n nickname: Type.Optional(Type.String()),\n });\n\n mockInputCancellable.mockResolvedValueOnce(\"Alice\"); // name\n mockSelectCancellable.mockResolvedValueOnce(false); // skip nickname\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result.name).toBe(\"Alice\");\n expect(result.nickname).toBeUndefined();\n });\n\n test(\"fills optional field when user selects Yes\", async () => {\n const schema = Type.Object({\n name: Type.String(),\n nickname: Type.Optional(Type.String()),\n });\n\n mockInputCancellable\n .mockResolvedValueOnce(\"Alice\") // name\n .mockResolvedValueOnce(\"Ali\"); // nickname\n mockSelectCancellable.mockResolvedValueOnce(true); // fill nickname\n\n const result = await sprinkle.FillInStruct(schema);\n expect(result.name).toBe(\"Alice\");\n expect(result.nickname).toBe(\"Ali\");\n });\n});\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"enhancements.test.js","names":["describe","expect","test","mock","beforeEach","Sprinkle","Type","mockSelect","mockInput","mockPassword","mockSelectCancellable","mockInputCancellable","mockPasswordCancellable","mockConfirmCancellable","mockSearchCancellable","module","select","input","password","selectCancellable","inputCancellable","passwordCancellable","confirmCancellable","searchCancellable","sprinkle","schema","Object","name","String","settings","mockClear","callOrder","beforeShowFn","push","mockImplementation","menu","title","beforeShow","items","action","showMenu","toHaveBeenCalledTimes","toBe","receivedSprinkle","mockResolvedValueOnce","s","result","SearchSelect","message","source","value","calls","sourceFn","toBeNull"],"sources":["../../../../src/Sprinkle/__tests__/enhancements.test.ts"],"sourcesContent":["import { describe, expect, test, mock, beforeEach } from \"bun:test\";\nimport { Sprinkle, Type, type IMenu } from \"../index.js\";\n\nconst mockSelect = mock();\nconst mockInput = mock();\nconst mockPassword = mock();\nconst mockSelectCancellable = mock();\nconst mockInputCancellable = mock();\nconst mockPasswordCancellable = mock();\nconst mockConfirmCancellable = mock();\nconst mockSearchCancellable = mock();\n\nmock.module(\"@inquirer/prompts\", () => ({\n select: mockSelect,\n input: mockInput,\n password: mockPassword,\n}));\n\nmock.module(\"../prompts.js\", () => ({\n selectCancellable: mockSelectCancellable,\n inputCancellable: mockInputCancellable,\n passwordCancellable: mockPasswordCancellable,\n confirmCancellable: mockConfirmCancellable,\n searchCancellable: mockSearchCancellable,\n select: mockSelectCancellable,\n}));\n\ndescribe(\"beforeShow hook (2.2)\", () => {\n let sprinkle: Sprinkle<any>;\n\n beforeEach(() => {\n const schema = Type.Object({ name: Type.String() });\n sprinkle = new Sprinkle(schema, \"/tmp/test\");\n sprinkle.settings = { name: \"test\" } as any;\n mockSelect.mockClear();\n mockSelectCancellable.mockClear();\n });\n\n test(\"calls beforeShow before rendering menu\", async () => {\n const callOrder: string[] = [];\n\n const beforeShowFn = mock(async () => {\n callOrder.push(\"beforeShow\");\n });\n\n mockSelectCancellable.mockImplementation(async () => {\n callOrder.push(\"select\");\n return -1; // exit\n });\n\n const menu: IMenu<any> = {\n title: \"Test\",\n beforeShow: beforeShowFn,\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n\n expect(beforeShowFn).toHaveBeenCalledTimes(1);\n expect(callOrder[0]).toBe(\"beforeShow\");\n expect(callOrder[1]).toBe(\"select\");\n });\n\n test(\"passes sprinkle instance to beforeShow\", async () => {\n let receivedSprinkle: any;\n\n mockSelectCancellable.mockResolvedValueOnce(-1);\n\n const menu: IMenu<any> = {\n title: \"Test\",\n beforeShow: async (s) => {\n receivedSprinkle = s;\n },\n items: [{ title: \"Action\", action: async () => {} }],\n };\n\n await sprinkle.showMenu(menu);\n expect(receivedSprinkle).toBe(sprinkle);\n });\n\n test(\"menu works without beforeShow\", 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 // Should complete without error\n });\n});\n\ndescribe(\"SearchSelect (2.3)\", () => {\n beforeEach(() => {\n mockSearchCancellable.mockClear();\n });\n\n test(\"delegates to search prompt\", async () => {\n mockSearchCancellable.mockResolvedValueOnce(\"selected-value\");\n\n const result = await Sprinkle.SearchSelect({\n message: \"Pick one\",\n source: () => [\n { name: \"Option A\", value: \"a\" },\n { name: \"Option B\", value: \"b\" },\n ],\n });\n\n expect(result).toBe(\"selected-value\");\n expect(mockSearchCancellable).toHaveBeenCalledTimes(1);\n expect(mockSearchCancellable.mock.calls[0][0].message).toBe(\"Pick one\");\n });\n\n test(\"passes source function through\", async () => {\n const sourceFn = mock(() => [{ name: \"X\", value: \"x\" }]);\n mockSearchCancellable.mockResolvedValueOnce(\"x\");\n\n await Sprinkle.SearchSelect({\n message: \"Search\",\n source: sourceFn,\n });\n\n expect(mockSearchCancellable.mock.calls[0][0].source).toBe(sourceFn);\n });\n\n test(\"returns null when cancelled\", async () => {\n mockSearchCancellable.mockResolvedValueOnce(null);\n\n const result = await Sprinkle.SearchSelect({\n message: \"Pick one\",\n source: () => [{ name: \"A\", value: \"a\" }],\n });\n\n expect(result).toBeNull();\n });\n});\n\n// Note: \"Optional type support (2.4)\" tests removed - they tested the old sequential\n// FillInStruct behavior. The new menu-based FillInStruct handles optional fields\n// differently (via menu selection). See fill-in-struct.test.ts for comprehensive tests.\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,168 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { countRequiredFields, isFieldRequired, buildFieldLabel, getInitialFieldState, allRequiredFieldsFilled } from "../utils/field-utils.js";
4
+ describe("isFieldRequired", () => {
5
+ test("returns true for plain required field", () => {
6
+ expect(isFieldRequired(Type.String())).toBe(true);
7
+ });
8
+ test("returns false for optional field", () => {
9
+ expect(isFieldRequired(Type.Optional(Type.String()))).toBe(false);
10
+ });
11
+ test("returns false for field with default", () => {
12
+ expect(isFieldRequired(Type.String({
13
+ default: "hello"
14
+ }))).toBe(false);
15
+ });
16
+ test("returns true for nullable field with default", () => {
17
+ // Nullable fields with defaults are required because the user should
18
+ // explicitly choose whether to use the value or set null
19
+ const schema = Type.Union([Type.String({
20
+ default: "hello"
21
+ }), Type.Null()]);
22
+ expect(isFieldRequired(schema)).toBe(true);
23
+ });
24
+ });
25
+ describe("countRequiredFields", () => {
26
+ test("counts fields in simple object", () => {
27
+ const schema = Type.Object({
28
+ name: Type.String(),
29
+ age: Type.BigInt()
30
+ });
31
+ const state = new Map();
32
+ const result = countRequiredFields(schema, state);
33
+ expect(result.total).toBe(2);
34
+ expect(result.filled).toBe(0);
35
+ });
36
+ test("skips optional fields", () => {
37
+ const schema = Type.Object({
38
+ name: Type.String(),
39
+ nickname: Type.Optional(Type.String())
40
+ });
41
+ const state = new Map();
42
+ const result = countRequiredFields(schema, state);
43
+ expect(result.total).toBe(1);
44
+ });
45
+ test("skips fields with defaults", () => {
46
+ const schema = Type.Object({
47
+ name: Type.String(),
48
+ timeout: Type.BigInt({
49
+ default: 30n
50
+ })
51
+ });
52
+ const state = new Map();
53
+ const result = countRequiredFields(schema, state);
54
+ expect(result.total).toBe(1);
55
+ });
56
+ test("counts filled fields", () => {
57
+ const schema = Type.Object({
58
+ name: Type.String(),
59
+ age: Type.BigInt()
60
+ });
61
+ const state = new Map([["name", {
62
+ status: "set",
63
+ value: "Alice"
64
+ }]]);
65
+ const result = countRequiredFields(schema, state);
66
+ expect(result.total).toBe(2);
67
+ expect(result.filled).toBe(1);
68
+ });
69
+ test("counts null as filled for nullable fields", () => {
70
+ const schema = Type.Object({
71
+ name: Type.Union([Type.String(), Type.Null()])
72
+ });
73
+ const state = new Map([["name", {
74
+ status: "null"
75
+ }]]);
76
+ const result = countRequiredFields(schema, state);
77
+ expect(result.filled).toBe(1);
78
+ });
79
+ });
80
+ describe("buildFieldLabel", () => {
81
+ test("shows [not set] with asterisk for required unset field", () => {
82
+ const label = buildFieldLabel("name", Type.String(), {
83
+ status: "unset"
84
+ });
85
+ expect(label).toContain("name");
86
+ expect(label).toContain("[not set]");
87
+ expect(label).toContain("*");
88
+ });
89
+ test("shows [not set] without asterisk for optional field", () => {
90
+ const label = buildFieldLabel("nickname", Type.Optional(Type.String()), {
91
+ status: "unset"
92
+ });
93
+ expect(label).toContain("[not set]");
94
+ expect(label).not.toContain("*");
95
+ });
96
+ test("shows default value for unset field with default", () => {
97
+ const label = buildFieldLabel("timeout", Type.BigInt({
98
+ default: 30n
99
+ }), {
100
+ status: "unset"
101
+ });
102
+ expect(label).toContain("default");
103
+ expect(label).toContain("30");
104
+ });
105
+ test("shows null for null state", () => {
106
+ const label = buildFieldLabel("value", Type.Union([Type.String(), Type.Null()]), {
107
+ status: "null"
108
+ });
109
+ expect(label).toContain("null");
110
+ });
111
+ test("shows value preview for set field", () => {
112
+ const label = buildFieldLabel("name", Type.String(), {
113
+ status: "set",
114
+ value: "Alice"
115
+ });
116
+ expect(label).toContain("Alice");
117
+ });
118
+ });
119
+ describe("getInitialFieldState", () => {
120
+ test("returns unset for undefined", () => {
121
+ expect(getInitialFieldState(Type.String(), undefined)).toEqual({
122
+ status: "unset"
123
+ });
124
+ });
125
+ test("returns null for null value", () => {
126
+ expect(getInitialFieldState(Type.String(), null)).toEqual({
127
+ status: "null"
128
+ });
129
+ });
130
+ test("returns set with value", () => {
131
+ expect(getInitialFieldState(Type.String(), "hello")).toEqual({
132
+ status: "set",
133
+ value: "hello"
134
+ });
135
+ });
136
+ });
137
+ describe("allRequiredFieldsFilled", () => {
138
+ test("returns true when all required fields filled", () => {
139
+ const schema = Type.Object({
140
+ name: Type.String(),
141
+ nickname: Type.Optional(Type.String())
142
+ });
143
+ const state = new Map([["name", {
144
+ status: "set",
145
+ value: "Alice"
146
+ }]]);
147
+ expect(allRequiredFieldsFilled(schema, state)).toBe(true);
148
+ });
149
+ test("returns false when required field missing", () => {
150
+ const schema = Type.Object({
151
+ name: Type.String(),
152
+ age: Type.BigInt()
153
+ });
154
+ const state = new Map([["name", {
155
+ status: "set",
156
+ value: "Alice"
157
+ }]]);
158
+ expect(allRequiredFieldsFilled(schema, state)).toBe(false);
159
+ });
160
+ test("returns true for all-optional schema", () => {
161
+ const schema = Type.Object({
162
+ nickname: Type.Optional(Type.String())
163
+ });
164
+ const state = new Map();
165
+ expect(allRequiredFieldsFilled(schema, state)).toBe(true);
166
+ });
167
+ });
168
+ //# sourceMappingURL=field-utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-utils.test.js","names":["describe","expect","test","Type","countRequiredFields","isFieldRequired","buildFieldLabel","getInitialFieldState","allRequiredFieldsFilled","String","toBe","Optional","default","schema","Union","Null","Object","name","age","BigInt","state","Map","result","total","filled","nickname","timeout","status","value","label","toContain","not","undefined","toEqual"],"sources":["../../../../src/Sprinkle/__tests__/field-utils.test.ts"],"sourcesContent":["import { describe, expect, test } from \"bun:test\";\nimport { Type } from \"@sinclair/typebox\";\nimport {\n countRequiredFields,\n isFieldRequired,\n buildFieldLabel,\n getInitialFieldState,\n allRequiredFieldsFilled,\n} from \"../utils/field-utils.js\";\nimport type { FieldState } from \"../types.js\";\n\ndescribe(\"isFieldRequired\", () => {\n test(\"returns true for plain required field\", () => {\n expect(isFieldRequired(Type.String())).toBe(true);\n });\n\n test(\"returns false for optional field\", () => {\n expect(isFieldRequired(Type.Optional(Type.String()))).toBe(false);\n });\n\n test(\"returns false for field with default\", () => {\n expect(isFieldRequired(Type.String({ default: \"hello\" }))).toBe(false);\n });\n\n test(\"returns true for nullable field with default\", () => {\n // Nullable fields with defaults are required because the user should\n // explicitly choose whether to use the value or set null\n const schema = Type.Union([Type.String({ default: \"hello\" }), Type.Null()]);\n expect(isFieldRequired(schema)).toBe(true);\n });\n});\n\ndescribe(\"countRequiredFields\", () => {\n test(\"counts fields in simple object\", () => {\n const schema = Type.Object({\n name: Type.String(),\n age: Type.BigInt(),\n });\n const state = new Map<string, FieldState>();\n\n const result = countRequiredFields(schema, state);\n expect(result.total).toBe(2);\n expect(result.filled).toBe(0);\n });\n\n test(\"skips optional fields\", () => {\n const schema = Type.Object({\n name: Type.String(),\n nickname: Type.Optional(Type.String()),\n });\n const state = new Map<string, FieldState>();\n\n const result = countRequiredFields(schema, state);\n expect(result.total).toBe(1);\n });\n\n test(\"skips fields with defaults\", () => {\n const schema = Type.Object({\n name: Type.String(),\n timeout: Type.BigInt({ default: 30n }),\n });\n const state = new Map<string, FieldState>();\n\n const result = countRequiredFields(schema, state);\n expect(result.total).toBe(1);\n });\n\n test(\"counts filled fields\", () => {\n const schema = Type.Object({\n name: Type.String(),\n age: Type.BigInt(),\n });\n const state = new Map<string, FieldState>([\n [\"name\", { status: \"set\", value: \"Alice\" }],\n ]);\n\n const result = countRequiredFields(schema, state);\n expect(result.total).toBe(2);\n expect(result.filled).toBe(1);\n });\n\n test(\"counts null as filled for nullable fields\", () => {\n const schema = Type.Object({\n name: Type.Union([Type.String(), Type.Null()]),\n });\n const state = new Map<string, FieldState>([[\"name\", { status: \"null\" }]]);\n\n const result = countRequiredFields(schema, state);\n expect(result.filled).toBe(1);\n });\n});\n\ndescribe(\"buildFieldLabel\", () => {\n test(\"shows [not set] with asterisk for required unset field\", () => {\n const label = buildFieldLabel(\"name\", Type.String(), { status: \"unset\" });\n expect(label).toContain(\"name\");\n expect(label).toContain(\"[not set]\");\n expect(label).toContain(\"*\");\n });\n\n test(\"shows [not set] without asterisk for optional field\", () => {\n const label = buildFieldLabel(\"nickname\", Type.Optional(Type.String()), {\n status: \"unset\",\n });\n expect(label).toContain(\"[not set]\");\n expect(label).not.toContain(\"*\");\n });\n\n test(\"shows default value for unset field with default\", () => {\n const label = buildFieldLabel(\n \"timeout\",\n Type.BigInt({ default: 30n }),\n { status: \"unset\" },\n );\n expect(label).toContain(\"default\");\n expect(label).toContain(\"30\");\n });\n\n test(\"shows null for null state\", () => {\n const label = buildFieldLabel(\n \"value\",\n Type.Union([Type.String(), Type.Null()]),\n { status: \"null\" },\n );\n expect(label).toContain(\"null\");\n });\n\n test(\"shows value preview for set field\", () => {\n const label = buildFieldLabel(\"name\", Type.String(), {\n status: \"set\",\n value: \"Alice\",\n });\n expect(label).toContain(\"Alice\");\n });\n});\n\ndescribe(\"getInitialFieldState\", () => {\n test(\"returns unset for undefined\", () => {\n expect(getInitialFieldState(Type.String(), undefined)).toEqual({\n status: \"unset\",\n });\n });\n\n test(\"returns null for null value\", () => {\n expect(getInitialFieldState(Type.String(), null)).toEqual({\n status: \"null\",\n });\n });\n\n test(\"returns set with value\", () => {\n expect(getInitialFieldState(Type.String(), \"hello\")).toEqual({\n status: \"set\",\n value: \"hello\",\n });\n });\n});\n\ndescribe(\"allRequiredFieldsFilled\", () => {\n test(\"returns true when all required fields filled\", () => {\n const schema = Type.Object({\n name: Type.String(),\n nickname: Type.Optional(Type.String()),\n });\n const state = new Map<string, FieldState>([\n [\"name\", { status: \"set\", value: \"Alice\" }],\n ]);\n\n expect(allRequiredFieldsFilled(schema, state)).toBe(true);\n });\n\n test(\"returns false when required field missing\", () => {\n const schema = Type.Object({\n name: Type.String(),\n age: Type.BigInt(),\n });\n const state = new Map<string, FieldState>([\n [\"name\", { status: \"set\", value: \"Alice\" }],\n ]);\n\n expect(allRequiredFieldsFilled(schema, state)).toBe(false);\n });\n\n test(\"returns true for all-optional schema\", () => {\n const schema = Type.Object({\n nickname: Type.Optional(Type.String()),\n });\n const state = new Map<string, FieldState>();\n\n expect(allRequiredFieldsFilled(schema, state)).toBe(true);\n });\n});\n"],"mappings":"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","ignoreList":[]}