@es-joy/jsoe 0.27.0 → 0.28.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 (148) hide show
  1. package/CHANGES.md +37 -0
  2. package/README.md +3 -1
  3. package/badges/coverage-badge.svg +1 -1
  4. package/badges/tests-badge.svg +1 -0
  5. package/dist/formats/schema.d.ts +11 -0
  6. package/dist/formats/schema.d.ts.map +1 -1
  7. package/dist/formats/structuredCloning.d.ts.map +1 -1
  8. package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
  9. package/dist/fundamentalTypes/stringType.d.ts.map +1 -1
  10. package/dist/index.js +2 -2
  11. package/dist/index.js.map +1 -1
  12. package/dist/typeChoices.d.ts +32 -2
  13. package/dist/typeChoices.d.ts.map +1 -1
  14. package/dist/types.d.ts +8 -2
  15. package/dist/types.d.ts.map +1 -1
  16. package/dist/utils/rawTypesonEditor.d.ts +110 -0
  17. package/dist/utils/rawTypesonEditor.d.ts.map +1 -0
  18. package/dist/vendor-imports.d.ts +4 -0
  19. package/docs/proposals/raw-typeson-edit-view.md +575 -0
  20. package/mmr.json +6 -0
  21. package/package.json +34 -12
  22. package/pnpm-workspace.yaml +32 -30
  23. package/src/formats/schema.js +10 -15
  24. package/src/formats/structuredCloning.js +24 -17
  25. package/src/fundamentalTypes/arrayType.js +119 -23
  26. package/src/fundamentalTypes/blobType.js +16 -16
  27. package/src/fundamentalTypes/fileType.js +13 -13
  28. package/src/fundamentalTypes/regexpType.js +1 -1
  29. package/src/fundamentalTypes/stringType.js +5 -0
  30. package/src/jsoe.css +12 -0
  31. package/src/subTypes/blobHTMLType.js +1 -1
  32. package/src/superTypes/dommatrixType.js +1 -1
  33. package/src/superTypes/errorsSpecialType.js +1 -1
  34. package/src/typeChoices.js +37 -10
  35. package/src/types.js +13 -8
  36. package/src/utils/media.js +3 -3
  37. package/src/utils/rawTypesonEditor.js +669 -0
  38. package/src/vendor-imports.js +12 -0
  39. package/tsconfig.json +1 -1
  40. package/typings/json-6.d.ts +12 -0
  41. package/vendor/@codemirror/autocomplete/dist/index.js +2125 -0
  42. package/vendor/@codemirror/commands/dist/index.js +1826 -0
  43. package/vendor/@codemirror/lang-javascript/dist/index.js +513 -0
  44. package/vendor/@codemirror/language/dist/index.js +2693 -0
  45. package/vendor/@codemirror/lint/dist/index.js +956 -0
  46. package/vendor/@codemirror/search/dist/index.js +1238 -0
  47. package/vendor/@codemirror/state/dist/index.js +3947 -0
  48. package/vendor/@codemirror/view/dist/index.js +11867 -0
  49. package/vendor/@lezer/common/dist/index.js +2202 -0
  50. package/vendor/@lezer/highlight/dist/index.js +927 -0
  51. package/vendor/@lezer/javascript/dist/index.js +192 -0
  52. package/vendor/@lezer/lr/dist/index.js +1889 -0
  53. package/vendor/@marijn/find-cluster-break/src/index.js +87 -0
  54. package/vendor/codemirror/dist/index.js +96 -0
  55. package/vendor/crelt/index.js +28 -0
  56. package/vendor/jamilih/dist/jml.mjs +898 -25
  57. package/vendor/json-6/dist/index.mjs +1783 -0
  58. package/vendor/style-mod/src/style-mod.js +172 -0
  59. package/vendor/w3c-keyname/index.js +119 -0
  60. package/vendor/zod/classic/checks.d.ts +1 -1
  61. package/vendor/zod/classic/checks.js +1 -1
  62. package/vendor/zod/classic/schemas.d.ts +2 -6
  63. package/vendor/zod/classic/schemas.js +9 -13
  64. package/vendor/zod/core/api.d.ts +8 -4
  65. package/vendor/zod/core/api.js +11 -23
  66. package/vendor/zod/core/checks.d.ts +16 -0
  67. package/vendor/zod/core/checks.js +31 -0
  68. package/vendor/zod/core/compile.js +20 -24
  69. package/vendor/zod/core/core.js +1 -1
  70. package/vendor/zod/core/json-schema-processors.d.ts +0 -1
  71. package/vendor/zod/core/json-schema-processors.js +8 -43
  72. package/vendor/zod/core/memoizer.js +2 -5
  73. package/vendor/zod/core/regexes.d.ts +1 -0
  74. package/vendor/zod/core/regexes.js +2 -0
  75. package/vendor/zod/core/schemas.d.ts +8 -23
  76. package/vendor/zod/core/schemas.js +39 -80
  77. package/vendor/zod/core/to-json-schema.d.ts +0 -3
  78. package/vendor/zod/core/to-json-schema.js +1 -1
  79. package/vendor/zod/core/util.js +0 -4
  80. package/vendor/zod/core/versions.js +1 -1
  81. package/vendor/zod/core/visit.js +0 -12
  82. package/vendor/zod/locales/ar.js +1 -0
  83. package/vendor/zod/locales/az.js +1 -0
  84. package/vendor/zod/locales/be.js +1 -0
  85. package/vendor/zod/locales/bg.js +1 -0
  86. package/vendor/zod/locales/bn.js +1 -0
  87. package/vendor/zod/locales/ca.js +1 -0
  88. package/vendor/zod/locales/ckb.js +1 -0
  89. package/vendor/zod/locales/cs.js +1 -0
  90. package/vendor/zod/locales/da.js +1 -0
  91. package/vendor/zod/locales/de.js +1 -0
  92. package/vendor/zod/locales/el.js +1 -0
  93. package/vendor/zod/locales/en.js +1 -0
  94. package/vendor/zod/locales/eo.js +1 -0
  95. package/vendor/zod/locales/es.js +1 -0
  96. package/vendor/zod/locales/fa.js +1 -0
  97. package/vendor/zod/locales/fi.js +1 -0
  98. package/vendor/zod/locales/fr-CA.js +1 -0
  99. package/vendor/zod/locales/fr.js +1 -0
  100. package/vendor/zod/locales/gu.js +1 -0
  101. package/vendor/zod/locales/he.js +1 -0
  102. package/vendor/zod/locales/hi.js +1 -0
  103. package/vendor/zod/locales/hr.js +1 -0
  104. package/vendor/zod/locales/hu.js +1 -0
  105. package/vendor/zod/locales/hy.js +1 -0
  106. package/vendor/zod/locales/id.js +1 -0
  107. package/vendor/zod/locales/is.js +1 -0
  108. package/vendor/zod/locales/it.js +1 -0
  109. package/vendor/zod/locales/ja.js +1 -0
  110. package/vendor/zod/locales/ka.js +1 -0
  111. package/vendor/zod/locales/km.js +1 -0
  112. package/vendor/zod/locales/kn.js +1 -0
  113. package/vendor/zod/locales/ko.js +1 -0
  114. package/vendor/zod/locales/lt.js +1 -0
  115. package/vendor/zod/locales/mk.js +1 -0
  116. package/vendor/zod/locales/ms.js +1 -0
  117. package/vendor/zod/locales/ne.js +1 -0
  118. package/vendor/zod/locales/nl.js +1 -0
  119. package/vendor/zod/locales/nn.js +1 -0
  120. package/vendor/zod/locales/no.js +1 -0
  121. package/vendor/zod/locales/ota.js +1 -0
  122. package/vendor/zod/locales/pl.js +1 -0
  123. package/vendor/zod/locales/ps.js +1 -0
  124. package/vendor/zod/locales/pt-BR.js +1 -0
  125. package/vendor/zod/locales/pt.js +1 -0
  126. package/vendor/zod/locales/ro.js +1 -0
  127. package/vendor/zod/locales/ru.js +1 -0
  128. package/vendor/zod/locales/sk.js +1 -0
  129. package/vendor/zod/locales/sl.js +1 -0
  130. package/vendor/zod/locales/sv.js +1 -0
  131. package/vendor/zod/locales/ta.js +1 -0
  132. package/vendor/zod/locales/tg.js +1 -0
  133. package/vendor/zod/locales/th.js +1 -0
  134. package/vendor/zod/locales/tk.js +1 -0
  135. package/vendor/zod/locales/tr.js +1 -0
  136. package/vendor/zod/locales/uk.js +1 -0
  137. package/vendor/zod/locales/ur.js +1 -0
  138. package/vendor/zod/locales/uz.js +1 -0
  139. package/vendor/zod/locales/vi.js +1 -0
  140. package/vendor/zod/locales/yo.js +1 -0
  141. package/vendor/zod/locales/zh-CN.js +1 -0
  142. package/vendor/zod/locales/zh-TW.js +1 -0
  143. package/vendor/zod/mini/checks.d.ts +1 -1
  144. package/vendor/zod/mini/checks.js +1 -1
  145. package/vendor/zod/mini/schemas.d.ts +2 -5
  146. package/vendor/zod/mini/schemas.js +9 -11
  147. package/vendor/zodexy/dist/esm/index.js +4 -33
  148. package/vendor/zodexy/dist/schema.zodexy.json +1 -17
@@ -232,7 +232,7 @@ function binaryButton (
232
232
  ['textarea', {
233
233
  class: 'view-binary'
234
234
  }, [
235
- /* istanbul ignore next */
235
+ /* istanbul ignore next -- Guard */
236
236
  /** @type {string|null} */ (reader.result) ?? ''
237
237
  ]]
238
238
  ]]
@@ -242,11 +242,11 @@ function binaryButton (
242
242
  // Seems not feasible to accurately simulate
243
243
  reader.addEventListener(
244
244
  'error',
245
- /* istanbul ignore next */
245
+ /* istanbul ignore next -- Should not err */
246
246
  async function () {
247
- /* istanbul ignore next */
247
+ /* istanbul ignore next -- Should not err */
248
248
  console.error(reader.error);
249
- /* istanbul ignore next */
249
+ /* istanbul ignore next -- Should not err */
250
250
  await dialogs.alert(/** @type {string} */ (
251
251
  /** @type {DOMException} */ (reader.error).message
252
252
  ));
@@ -341,7 +341,7 @@ const fileType = {
341
341
  'Text source',
342
342
  ['br'],
343
343
  ['textarea', {class: 'view-text'}, [
344
- /* istanbul ignore next */
344
+ /* istanbul ignore next -- Guard */
345
345
  /** @type {string|null} */ (reader.result) ?? ''
346
346
  ]]
347
347
  ]));
@@ -349,11 +349,11 @@ const fileType = {
349
349
  // Seems not feasible to accurately simulate
350
350
  reader.addEventListener(
351
351
  'error',
352
- /* istanbul ignore next */
352
+ /* istanbul ignore next -- Should not err */
353
353
  function () {
354
- /* istanbul ignore next */
354
+ /* istanbul ignore next -- Should not err */
355
355
  console.error(reader.error);
356
- /* istanbul ignore next */
356
+ /* istanbul ignore next -- Should not err */
357
357
  div.append(
358
358
  /** @type {DOMException} */ (reader.error).message
359
359
  );
@@ -882,7 +882,7 @@ const fileType = {
882
882
 
883
883
  if (constraints) {
884
884
  const mediaStream = await getUserMedia(constraints);
885
- /* istanbul ignore if */
885
+ /* istanbul ignore if -- Should be present */
886
886
  if (!mediaStream) {
887
887
  await dialogs.alert('Error getting user media');
888
888
  return;
@@ -930,7 +930,7 @@ const fileType = {
930
930
  const mediaStream = await startScreenCapture(
931
931
  screenShareConstraints
932
932
  );
933
- /* istanbul ignore if */
933
+ /* istanbul ignore if -- Should not err */
934
934
  if (!mediaStream) {
935
935
  await dialogs.alert('Error getting user media');
936
936
  return;
@@ -1010,7 +1010,7 @@ const fileType = {
1010
1010
  'video.previewMedia'
1011
1011
  ));
1012
1012
 
1013
- /* istanbul ignore if */
1013
+ /* istanbul ignore if -- Should not err */
1014
1014
  if (!previewMedia.srcObject) {
1015
1015
  dialogs.alert('No stream found to record');
1016
1016
  return;
@@ -1044,7 +1044,7 @@ const fileType = {
1044
1044
 
1045
1045
  try {
1046
1046
  mediaRecorder.start();
1047
- } catch /* istanbul ignore next */ {
1047
+ } catch /* istanbul ignore next -- Should not err */ {
1048
1048
  dialogs.alert('Error starting media recorder');
1049
1049
  return;
1050
1050
  }
@@ -1195,7 +1195,7 @@ const fileType = {
1195
1195
  ($e(videoContainer, 'img.photo'));
1196
1196
 
1197
1197
  canvas.toBlob((blob) => {
1198
- /* istanbul ignore if */
1198
+ /* istanbul ignore if -- Should not err */
1199
1199
  if (!blob) {
1200
1200
  dialogs.alert('Error converting canvas to Blob');
1201
1201
  return;
@@ -19,7 +19,7 @@ const regexpType = {
19
19
  return toStringTag(x) === 'RegExp';
20
20
  },
21
21
  toValue (s) {
22
- /* istanbul ignore if */
22
+ /* istanbul ignore if -- TS */
23
23
  if (typeof this.stringRegex !== 'function') {
24
24
  throw new TypeError('Guard for TS');
25
25
  }
@@ -128,6 +128,11 @@ const stringType = {
128
128
  }
129
129
  if (kind) {
130
130
  switch (kind) {
131
+ case 'currency_code':
132
+ if (!regexes.currencyCode.test(value)) {
133
+ return `Value doesn't match currency code pattern.`;
134
+ }
135
+ break;
131
136
  case 'credit_card':
132
137
  if (!regexes.creditCard.test(value)) {
133
138
  return `Value doesn't match credit card pattern.`;
package/src/jsoe.css CHANGED
@@ -139,6 +139,18 @@ video.recordedMedia {
139
139
  height: 300px;
140
140
  }
141
141
 
142
+ .jsoe-raw-editor {
143
+ width: 500px;
144
+ max-width: 100%;
145
+ height: 300px;
146
+ overflow: auto;
147
+ border: 1px solid;
148
+ }
149
+
150
+ .jsoe-raw-editor-error:not(:empty) {
151
+ color: #b00;
152
+ }
153
+
142
154
  .visualizer {
143
155
  height: 60px;
144
156
  }
@@ -127,7 +127,7 @@ const blobHTMLType = {
127
127
  jml('textarea', {name: `${typeNamespace}-blobHTML`})
128
128
  );
129
129
  textarea.sceditorInstance = {
130
- /* istanbul ignore next */
130
+ /* istanbul ignore next -- Guard */
131
131
  val () {
132
132
  throw new Error('Not yet instantiated');
133
133
  }
@@ -348,7 +348,7 @@ const dommatrixType = {
348
348
  $on: {
349
349
  click (e) {
350
350
  const {target} = e;
351
- /* istanbul ignore if */
351
+ /* istanbul ignore if -- Guard */
352
352
  if (/** @type {HTMLInputElement} */ (target).type !== 'radio') {
353
353
  return;
354
354
  }
@@ -36,7 +36,7 @@ if (typeof AggregateError !== 'undefined') {
36
36
  specialErrorsMap.set('AggregateError', AggregateError);
37
37
  }
38
38
 
39
- /* istanbul ignore next 5 */
39
+ /* istanbul ignore next 5 -- May not exist */
40
40
  // @ts-expect-error Only use if available
41
41
  if (typeof InternalError !== 'undefined') {
42
42
  // @ts-expect-error Only use if available
@@ -66,17 +66,44 @@ import deepEqual from 'fast-deep-equal/es6/index.js';
66
66
  */
67
67
 
68
68
  /**
69
- * @typedef {HTMLSelectElement & {
69
+ * The `$`-methods every type-choices control exposes, whether it's a real
70
+ * `<select>` (`TypeChoicesElementAPI`) or the `xor` radio group's
71
+ * `<fieldset>` standing in for one (`TypeChoicesControl` — see its comment
72
+ * for why that one is *not* typed as `HTMLSelectElement`).
73
+ * @typedef {{
70
74
  * $addAndValidateEditUI: AddAndValidateEditUI,
75
+ * $addTypeAndEditUI: AddTypeAndEditUI,
71
76
  * $setStyles: SetStyles,
72
77
  * $getTypeRoot: GetTypeRoot,
73
78
  * $getContainer: () => HTMLElement,
74
79
  * $getTopRoot: () => HTMLDivElement,
75
80
  * $addEditUI: AddEditUI,
76
81
  * $validate: Validate,
82
+ * $setType: SetType,
77
83
  * $setTypeNoEditUI: SetTypeNoEditUI,
84
+ * $getValue: GetValue,
78
85
  * $whenReady: WhenReady
79
- * }} TypeChoicesElementAPI
86
+ * }} TypeChoicesAPIMethods
87
+ */
88
+
89
+ /**
90
+ * @typedef {HTMLSelectElement & TypeChoicesAPIMethods} TypeChoicesElementAPI
91
+ */
92
+
93
+ /**
94
+ * The type-choices control surface downstream code actually relies on:
95
+ * the `$`-methods, plus the `value`/`selectedIndex`/`selectedOptions`
96
+ * surface a real `<select>` provides natively. Deliberately *not* typed as
97
+ * `HTMLSelectElement`, because `buildXorTypeChoices` below returns a real
98
+ * `<fieldset>` with that surface shimmed on via `Object.defineProperties`
99
+ * (and the `$`-methods copied by reference from the parallel `<select>`)
100
+ * rather than an actual `<select>` — asserting `HTMLSelectElement` there
101
+ * would be a false claim, not just a loose one.
102
+ * @typedef {HTMLElement & TypeChoicesAPIMethods & {
103
+ * value: string,
104
+ * selectedIndex: number,
105
+ * selectedOptions: ArrayLike<{value: string, dataset?: {idx?: string}}>
106
+ * }} TypeChoicesControl
80
107
  */
81
108
 
82
109
  /**
@@ -126,7 +153,7 @@ import deepEqual from 'fast-deep-equal/es6/index.js';
126
153
  * schemaContent?: import('./formatAndTypeChoices.js').ZodexSchema,
127
154
  * }} cfg
128
155
  * @returns {{
129
- * domArray: [select: HTMLElement, typeContainer: HTMLElement],
156
+ * domArray: [select: TypeChoicesControl, typeContainer: HTMLElement],
130
157
  * getValue: GetValue,
131
158
  * getType: GetType,
132
159
  * validValuesSet: ValidValuesSet,
@@ -166,9 +193,7 @@ function deriveXorBranchLabel (schemaObj, optText, idx) {
166
193
  return String(values[0]);
167
194
  }
168
195
  }
169
- if (schemaObj &&
170
- (schemaObj.type === 'object' || schemaObj.type === 'properties')
171
- ) {
196
+ if (schemaObj && schemaObj.type === 'object') {
172
197
  const {properties} = /** @type {import('zodexy').SzObject} */ (schemaObj);
173
198
  const keys = properties && typeof properties === 'object'
174
199
  ? Object.keys(properties)
@@ -200,9 +225,9 @@ function deriveXorBranchLabel (schemaObj, optText, idx) {
200
225
  * types: InstanceType<typeof import('./types.js').default>,
201
226
  * typeContainer: HTMLElement,
202
227
  * xorSchema: import('zodexy').SzUnion|undefined,
203
- * selectEl: HTMLSelectElement
228
+ * selectEl: TypeChoicesElementAPI
204
229
  * }} cfg
205
- * @returns {HTMLSelectElement}
230
+ * @returns {TypeChoicesControl}
206
231
  */
207
232
  function buildXorTypeChoices ({
208
233
  typeNamespace, keySelectClass, typeOptions, schemaObjs, types,
@@ -359,7 +384,9 @@ function buildXorTypeChoices ({
359
384
  }
360
385
  });
361
386
 
362
- return /** @type {HTMLSelectElement} */ (/** @type {unknown} */ (fieldset));
387
+ return /** @type {TypeChoicesControl} */ (
388
+ /** @type {unknown} */ (fieldset)
389
+ );
363
390
  }
364
391
 
365
392
  /**
@@ -437,7 +464,7 @@ export const buildTypeChoices = ({
437
464
  // match indicator to value changes inside it
438
465
  const typeContainer = jml('div', {class: 'typeContainer'});
439
466
 
440
- const selectEl = /** @type {HTMLSelectElement} */ (jml('select', {
467
+ const selectEl = /** @type {TypeChoicesElementAPI} */ (jml('select', {
441
468
  hidden: requireObject || typeOptions.length === 1,
442
469
  class: `typeChoices-${typeNamespace}${keySelectClass
443
470
  ? ' ' + keySelectClass
package/src/types.js CHANGED
@@ -438,17 +438,28 @@ class Types {
438
438
  /**
439
439
  * @param {{
440
440
  * useZodexyErrorMessages?: boolean,
441
- * useZodexyErrorMessagesInTypes?: boolean
441
+ * useZodexyErrorMessagesInTypes?: boolean,
442
+ * allowUnsafeEval?: boolean,
443
+ * showRawTypesonControls?: boolean
442
444
  * }} [cfg]
443
445
  */
444
446
  constructor ({
445
447
  useZodexyErrorMessages = false,
446
- useZodexyErrorMessagesInTypes = false
448
+ useZodexyErrorMessagesInTypes = false,
449
+ allowUnsafeEval = false,
450
+ showRawTypesonControls = true
447
451
  } = {}) {
448
452
  this.formats = new Formats(); // Todo: Make customizable and test
449
453
 
450
454
  this.useZodexyErrorMessages = useZodexyErrorMessages;
451
455
  this.useZodexyErrorMessagesInTypes = useZodexyErrorMessagesInTypes;
456
+ // Gates the eval-mode sub-feature of the raw Typeson edit/view buttons
457
+ // (`src/utils/rawTypesonEditor.js`); disabled by default since eval'ing
458
+ // arbitrary user-supplied text is inherently unsafe.
459
+ this.allowUnsafeEval = allowUnsafeEval;
460
+ // Master on/off switch for the raw Typeson edit/view buttons themselves;
461
+ // when `false` neither button is rendered anywhere in the tree.
462
+ this.showRawTypesonControls = showRawTypesonControls;
452
463
  /** @type {WeakMap<RootElement, import('./formats/schema.js').ZodexSchema>} */
453
464
  this.schemasForRoots = new WeakMap();
454
465
 
@@ -721,12 +732,6 @@ class Types {
721
732
  // `record`/`tuple` are not shown as their own pull-down entries; they render
722
733
  // as `Object`/`Array` (their schema, incl. child descriptions, informs the
723
734
  // layout — see `arrayType.js`).
724
- // `z.properties()` likewise renders through the `object` type/UI; when the
725
- // schema supplies no label of its own, name it "Properties" so it is not
726
- // shown as an indistinguishable "Object".
727
- if (type === 'object' && schemaContent?.type === 'properties') {
728
- optInfo[0] = 'Properties';
729
- }
730
735
 
731
736
  const schemaContentLabel = resolveSchemaMeta(schemaContent).label;
732
737
  if (schemaContentLabel) {
@@ -77,9 +77,9 @@ async function getUserMedia (constraints) {
77
77
  try {
78
78
  stream = await navigator.mediaDevices.getUserMedia(constraints);
79
79
  } catch (err) {
80
- /* istanbul ignore next */
80
+ /* istanbul ignore next -- Should be present */
81
81
  console.error('err', err);
82
- /* istanbul ignore next */
82
+ /* istanbul ignore next -- Should be present */
83
83
  return null;
84
84
  }
85
85
  return stream;
@@ -96,7 +96,7 @@ async function startScreenCapture (displayMediaOptions) {
96
96
  captureStream =
97
97
  await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
98
98
  } catch (err) {
99
- /* istanbul ignore next */
99
+ /* istanbul ignore next -- Should not err */
100
100
  console.error(`Error: ${err}`);
101
101
  }
102
102
  return captureStream;