@es-joy/jsoe 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 (80) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.cjs +2 -0
  3. package/.nyc_output/out.json +121296 -0
  4. package/CHANGES.md +10 -0
  5. package/README.md +47 -21
  6. package/cypress.config.ts +13 -0
  7. package/demo/index-instrumented.html +29 -0
  8. package/demo/index.html +10 -1
  9. package/demo/index.js +482 -126
  10. package/dist/formatAndTypeChoices.d.ts +10 -4
  11. package/dist/formatAndTypeChoices.d.ts.map +1 -1
  12. package/dist/formats/json.d.ts.map +1 -1
  13. package/dist/formats/structuredCloning.d.ts +2 -1
  14. package/dist/formats/structuredCloning.d.ts.map +1 -1
  15. package/dist/fundamentalTypes/arrayType.d.ts +6 -37
  16. package/dist/fundamentalTypes/arrayType.d.ts.map +1 -1
  17. package/dist/fundamentalTypes/dateType.d.ts.map +1 -1
  18. package/dist/fundamentalTypes/errorType.d.ts +6 -0
  19. package/dist/fundamentalTypes/errorType.d.ts.map +1 -0
  20. package/dist/fundamentalTypes/mapType.d.ts +6 -0
  21. package/dist/fundamentalTypes/mapType.d.ts.map +1 -0
  22. package/dist/fundamentalTypes/nullType.d.ts.map +1 -1
  23. package/dist/fundamentalTypes/objectReferenceType.d.ts.map +1 -1
  24. package/dist/fundamentalTypes/setType.d.ts +6 -0
  25. package/dist/fundamentalTypes/setType.d.ts.map +1 -0
  26. package/dist/fundamentalTypes/sparseUndefinedType.d.ts.map +1 -1
  27. package/dist/fundamentalTypes/undefinedType.d.ts.map +1 -1
  28. package/dist/subTypes/blobHTMLType.d.ts +12 -6
  29. package/dist/subTypes/blobHTMLType.d.ts.map +1 -1
  30. package/dist/superTypes/SpecialNumberType.d.ts +14 -0
  31. package/dist/superTypes/SpecialNumberType.d.ts.map +1 -0
  32. package/dist/superTypes/SpecialRealNumberType.d.ts +6 -0
  33. package/dist/superTypes/SpecialRealNumberType.d.ts.map +1 -0
  34. package/dist/superTypes/errorsSpecialType.d.ts +8 -0
  35. package/dist/superTypes/errorsSpecialType.d.ts.map +1 -0
  36. package/dist/typeChoices.d.ts +4 -2
  37. package/dist/typeChoices.d.ts.map +1 -1
  38. package/dist/types.d.ts +85 -233
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/utils/dialogs.d.ts +22 -22
  41. package/dist/utils/dialogs.d.ts.map +1 -1
  42. package/dist/utils/templateUtils.d.ts +6 -6
  43. package/dist/utils/templateUtils.d.ts.map +1 -1
  44. package/dist/vendor-imports.d.ts +1 -1
  45. package/package.json +39 -34
  46. package/rollup.config.js +14 -2
  47. package/server.js +1 -1
  48. package/src/formatAndTypeChoices.js +14 -13
  49. package/src/formats/indexedDBKey.js +2 -2
  50. package/src/formats/json.js +1 -2
  51. package/src/formats/structuredCloning.js +104 -29
  52. package/src/formats.js +2 -2
  53. package/src/fundamentalTypes/arrayReferenceType.js +3 -3
  54. package/src/fundamentalTypes/arrayType.js +384 -79
  55. package/src/fundamentalTypes/dateType.js +4 -6
  56. package/src/fundamentalTypes/errorType.js +416 -0
  57. package/src/fundamentalTypes/mapType.js +34 -0
  58. package/src/fundamentalTypes/nullType.js +1 -2
  59. package/src/fundamentalTypes/objectReferenceType.js +2 -1
  60. package/src/fundamentalTypes/regexpType.js +2 -2
  61. package/src/fundamentalTypes/setType.js +34 -0
  62. package/src/fundamentalTypes/sparseUndefinedType.js +2 -3
  63. package/src/fundamentalTypes/undefinedType.js +2 -3
  64. package/src/jsoe.css +3 -0
  65. package/src/subTypes/blobHTMLType.js +37 -33
  66. package/src/subTypes/falseType.js +2 -2
  67. package/src/subTypes/trueType.js +2 -2
  68. package/src/superTypes/{SpecialNumberSuperType.js → SpecialNumberType.js} +1 -1
  69. package/src/superTypes/{SpecialRealNumberSuperType.js → SpecialRealNumberType.js} +3 -2
  70. package/src/superTypes/errorsSpecialType.js +768 -0
  71. package/src/typeChoices.js +27 -20
  72. package/src/types.js +72 -40
  73. package/src/utils/dialogs.js +11 -12
  74. package/src/utils/jsonPointer.js +3 -3
  75. package/src/utils/templateUtils.js +4 -4
  76. package/src/vendor-imports.js +2 -2
  77. package/tsconfig.json +1 -1
  78. package/typings/CypressPlugins.d.ts +10 -0
  79. package/vendor/jamilih/dist/jml-es.js +126 -106
  80. package/vendor/typeson-registry/dist/index.js +188 -44
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@es-joy/jsoe",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "types": "./dist/index.d.ts",
6
6
  "main": "./src/index.js",
@@ -13,7 +13,8 @@
13
13
  "description": "Editing of arbitrary JavaScript objects",
14
14
  "scripts": {
15
15
  "tsc": "tsc",
16
- "eslint": "eslint --ext=js,cjs,md,html .",
16
+ "tsc-cypress": "tsc -p cypress/tsconfig.json",
17
+ "eslint": "eslint .",
17
18
  "lint": "npm run eslint --",
18
19
  "coverage": "open-cli http://localhost:8087/coverage/lcov-report/",
19
20
  "open": "open-cli http://localhost:8087/demo/",
@@ -26,11 +27,11 @@
26
27
  "instrument-remove-instrumented": "rimraf instrumented",
27
28
  "instrument-remove": "run-p -c instrument-remove-cache instrument-remove-instrumented",
28
29
  "copy-pages": "cp node_modules/sceditor/minified/themes/default.min.css vendor/sceditor/minified/themes/default.min.css && cp node_modules/sceditor/minified/sceditor.min.js vendor/sceditor/minified/sceditor.min.js && cp node_modules/sceditor/minified/formats/bbcode.js vendor/sceditor/minified/formats/bbcode.js && cp node_modules/sceditor/minified/formats/xhtml.js vendor/sceditor/minified/formats/xhtml.js",
29
- "copy-index": "cp src/index-instrumented.html instrumented/index.html",
30
+ "copy-index": "echo \"Copy our index.html file too? \"",
30
31
  "copy-jamilih": "cp node_modules/jamilih/dist/jml-es.js vendor/jamilih/dist/jml-es.js",
31
32
  "copy-typeson-registry": "cp node_modules/typeson-registry/dist/index.js vendor/typeson-registry/dist/index.js",
32
33
  "copy": "run-p copy-jamilih copy-typeson-registry",
33
- "instrument": "run-s -c instrument-remove instrument-add copy-index",
34
+ "instrument": "run-s -c instrument-remove instrument-add copy-index rollup",
34
35
  "cypress:log": "ELECTRON_ENABLE_LOGGING=1 cypress run; nyc report",
35
36
  "cypress": "cypress run; nyc report",
36
37
  "test": "npm run eslint && npm run rollup && npm run cypress"
@@ -39,58 +40,62 @@
39
40
  "cover 100%"
40
41
  ],
41
42
  "nyc": {
43
+ "excludeAfterRemap": true,
42
44
  "exclude": [
43
- "node_modules/**"
45
+ "node_modules/**",
46
+ "src/fundamentalTypes/sparseUndefinedType.js"
44
47
  ]
45
48
  },
46
49
  "dependencies": {
47
50
  "@brettz9/node-static": "^0.1.1",
48
- "jamilih": "0.58.1",
51
+ "jamilih": "0.58.2",
49
52
  "sceditor": "3.2.0",
50
- "typeson-registry": "7.2.1"
53
+ "typeson-registry": "9.1.1"
51
54
  },
52
55
  "devDependencies": {
53
- "@babel/core": "^7.22.5",
54
- "@babel/plugin-transform-modules-commonjs": "^7.22.5",
55
- "@babel/preset-env": "^7.22.5",
56
- "@babel/register": "^7.22.5",
56
+ "@babel/core": "^7.23.3",
57
+ "@babel/plugin-transform-modules-commonjs": "^7.23.3",
58
+ "@babel/preset-env": "^7.23.3",
59
+ "@babel/register": "^7.22.15",
57
60
  "@brettz9/eslint-plugin": "^1.0.4",
58
- "@cypress/code-coverage": "^3.10.7",
59
- "@rollup/plugin-babel": "^6.0.3",
60
- "@rollup/plugin-commonjs": "^25.0.1",
61
- "@rollup/plugin-node-resolve": "^15.1.0",
62
- "@types/jsdom": "^21.1.1",
63
- "axe-core": "^4.7.2",
64
- "cypress": "^12.14.0",
65
- "cypress-axe": "^1.4.0",
66
- "eslint": "^8.42.0",
67
- "eslint-config-ash-nazg": "^34.15.0",
61
+ "@cypress/code-coverage": "^3.12.10",
62
+ "@rollup/plugin-babel": "^6.0.4",
63
+ "@rollup/plugin-commonjs": "^25.0.7",
64
+ "@rollup/plugin-node-resolve": "^15.2.3",
65
+ "@stylistic/eslint-plugin": "^1.4.0",
66
+ "@types/jsdom": "^21.1.5",
67
+ "@types/node": "^20.9.2",
68
+ "axe-core": "^4.8.2",
69
+ "cypress": "^13.5.1",
70
+ "cypress-axe": "^1.5.0",
71
+ "eslint": "^8.54.0",
72
+ "eslint-config-ash-nazg": "^35.1.0",
68
73
  "eslint-config-standard": "^17.1.0",
69
- "eslint-plugin-array-func": "^3.1.8",
70
- "eslint-plugin-compat": "^4.1.4",
71
- "eslint-plugin-cypress": "^2.13.3",
74
+ "eslint-plugin-array-func": "^4.0.0",
75
+ "eslint-plugin-compat": "^4.2.0",
76
+ "eslint-plugin-cypress": "^2.15.1",
72
77
  "eslint-plugin-eslint-comments": "^3.2.0",
73
78
  "eslint-plugin-html": "^7.1.0",
74
- "eslint-plugin-import": "^2.27.5",
75
- "eslint-plugin-jsdoc": "^46.2.6",
76
- "eslint-plugin-markdown": "^3.0.0",
77
- "eslint-plugin-n": "^16.0.0",
79
+ "eslint-plugin-import": "^2.29.0",
80
+ "eslint-plugin-jsdoc": "^46.9.0",
81
+ "eslint-plugin-markdown": "^3.0.1",
82
+ "eslint-plugin-n": "^16.3.1",
78
83
  "eslint-plugin-no-unsanitized": "^4.0.2",
79
84
  "eslint-plugin-no-use-extend-native": "^0.5.0",
80
85
  "eslint-plugin-promise": "^6.1.1",
81
- "eslint-plugin-sonarjs": "^0.19.0",
86
+ "eslint-plugin-sonarjs": "^0.23.0",
82
87
  "eslint-plugin-standard": "^4.1.0",
83
- "eslint-plugin-unicorn": "^47.0.0",
88
+ "eslint-plugin-unicorn": "^49.0.0",
84
89
  "fast-deep-equal": "^3.1.3",
85
90
  "jsdom": "^21.1.1",
86
91
  "npm-run-all": "^4.1.5",
87
92
  "nyc": "^15.1.0",
88
93
  "open-cli": "^7.2.0",
89
- "rimraf": "^5.0.1",
90
- "rollup": "3.25.0",
91
- "rollup-plugin-istanbul": "^4.0.0",
94
+ "rimraf": "^5.0.5",
95
+ "rollup": "4.5.0",
96
+ "rollup-plugin-istanbul": "^5.0.0",
92
97
  "rollup-plugin-node-builtins": "^2.1.2",
93
- "typescript": "^5.1.3"
98
+ "typescript": "^5.2.2"
94
99
  },
95
100
  "repository": {
96
101
  "type": "git",
package/rollup.config.js CHANGED
@@ -3,8 +3,20 @@ import {nodeResolve} from '@rollup/plugin-node-resolve';
3
3
  import commonjs from '@rollup/plugin-commonjs';
4
4
  // import babel from 'rollup-plugin-babel';
5
5
  // import {terser} from 'rollup-plugin-terser';
6
+ import istanbul from 'rollup-plugin-istanbul';
6
7
 
7
- export default {
8
+ export default [{
9
+ input: 'demo/index.js',
10
+ output: {
11
+ file: 'instrumented/demo/index.js',
12
+ format: 'es'
13
+ },
14
+ plugins: [
15
+ istanbul(),
16
+ nodeResolve(),
17
+ commonjs()
18
+ ]
19
+ }, {
8
20
  input: 'node_modules/fast-deep-equal/es6/index.js',
9
21
  output: {
10
22
  file: 'src/deepEqual.js',
@@ -26,4 +38,4 @@ export default {
26
38
  include: 'node_modules/**'
27
39
  })
28
40
  ]
29
- };
41
+ }];
package/server.js CHANGED
@@ -9,7 +9,7 @@ const fileServer = new statik.Server();
9
9
 
10
10
  http.createServer(function (request, response) {
11
11
  request.addListener('end', function () {
12
- fileServer.serve(request, response, function (e, res) {
12
+ fileServer.serve(request, response, function (e /* , res */) {
13
13
  if (e && (e.status === 404)) { // If the file wasn't found
14
14
  fileServer.serveFile(
15
15
  instrumented === 'instrumented'
@@ -21,7 +21,7 @@ import {$e, DOM} from './utils/templateUtils.js';
21
21
  */
22
22
  export const getFormatAndSchemaChoices = ({schema, hasKeyPath} = {}) => {
23
23
  const hasSchema = typeof schema === 'string';
24
- // eslint-disable-next-line max-len -- Long
24
+ // eslint-disable-next-line @stylistic/max-len -- Long
25
25
  return /** @type {[optText: string, opts: {value: string, selected?: boolean}][]} */ ([
26
26
  ['JSON only', {value: 'json'}],
27
27
  ...(hasKeyPath
@@ -96,7 +96,7 @@ export const getFormatAndSchemaChoices = ({schema, hasKeyPath} = {}) => {
96
96
  * domArray: [formatChoices: FormatChoices, typesHolder: TypesHolder],
97
97
  * getValue: (stateObj: import('./types.js').StateObject,
98
98
  * currentPath: string) => import('./formats.js').StructuredCloneValue,
99
- * getType: () => string|null|undefined,
99
+ * getType: () => string,
100
100
  * validValuesSet: () => boolean,
101
101
  * setValue: SetValue
102
102
  * }} The selector for types and the container for them. Both should be
@@ -111,7 +111,7 @@ export function formatAndTypeChoices ({
111
111
  typeNamespace
112
112
  }) {
113
113
  const format = 'structuredCloning';
114
- const formatChoices = /** @type {HTMLSelectElement} */ (jml('select', {
114
+ const formatChoices = /** @type {FormatChoices} */ (jml('select', {
115
115
  class: 'formatChoices',
116
116
  hidden: singleValue,
117
117
  // is: 'main-type-choices',
@@ -130,9 +130,10 @@ export function formatAndTypeChoices ({
130
130
  */
131
131
 
132
132
  /**
133
- * @typedef {HTMLSelectElement} FormatChoices
134
- * @property {SetFormat} $setFormat
135
- * @property {TypeChoiceBuilder} $buildTypeChoices
133
+ * @typedef {HTMLSelectElement & {
134
+ * $setFormat: SetFormat,
135
+ * $buildTypeChoices: TypeChoiceBuilder
136
+ * }} FormatChoices
136
137
  */
137
138
 
138
139
  /**
@@ -227,7 +228,7 @@ export function formatAndTypeChoices ({
227
228
  * @returns {import('./formats.js').StructuredCloneValue}
228
229
  */
229
230
  getValue (stateObj, currentPath) {
230
- // eslint-disable-next-line max-len -- Long
231
+ // eslint-disable-next-line @stylistic/max-len -- Long
231
232
  const root = /** @type {HTMLDivElement & {$getTypeRoot: TypeRootGetter}} */ (
232
233
  typesHolder
233
234
  ).$getTypeRoot();
@@ -241,10 +242,10 @@ export function formatAndTypeChoices ({
241
242
  },
242
243
 
243
244
  /**
244
- * @returns {string|null|undefined}
245
+ * @returns {string}
245
246
  */
246
247
  getType () {
247
- // eslint-disable-next-line max-len -- Long
248
+ // eslint-disable-next-line @stylistic/max-len -- Long
248
249
  const root = /** @type {HTMLDivElement & {$getTypeRoot: TypeRootGetter}} */ (
249
250
  typesHolder
250
251
  ).$getTypeRoot();
@@ -255,7 +256,7 @@ export function formatAndTypeChoices ({
255
256
  * @returns {boolean}
256
257
  */
257
258
  validValuesSet () {
258
- // eslint-disable-next-line max-len -- Long
259
+ // eslint-disable-next-line @stylistic/max-len -- Long
259
260
  const root = /** @type {HTMLDivElement & {$getTypeRoot: TypeRootGetter}} */ (
260
261
  typesHolder
261
262
  ).$getTypeRoot();
@@ -276,12 +277,12 @@ export function formatAndTypeChoices ({
276
277
  stateObj
277
278
  )
278
279
  );
279
- const type = /** @type {string} */ (Types.getTypeForRoot(rootEditUI));
280
- // eslint-disable-next-line max-len -- Long
280
+ const type = Types.getTypeForRoot(rootEditUI);
281
+ // eslint-disable-next-line @stylistic/max-len -- Long
281
282
  const sel = /** @type {HTMLDivElement & {$getTypeSelect: TypeSelectGetter}} */ (
282
283
  typesHolder
283
284
  ).$getTypeSelect();
284
- // eslint-disable-next-line max-len -- Long
285
+ // eslint-disable-next-line @stylistic/max-len -- Long
285
286
  /** @type {HTMLSelectElement & {$addTypeAndEditUI: import('./typeChoices.js').AddTypeAndEditUI}} */ (
286
287
  sel
287
288
  ).$addTypeAndEditUI({type, editUI: rootEditUI});
@@ -36,8 +36,8 @@ const indexedDBKey = {
36
36
  if (!state || ['array'].includes(state)) {
37
37
  return this.types();
38
38
  }
39
- /* istanbul ignore next -- Can't be object, so shouldn't reach here */
40
- return undefined; // Todo: Should this throw?
39
+ // Can't be object, so shouldn't normally reach here
40
+ return undefined;
41
41
  }
42
42
  };
43
43
 
@@ -46,8 +46,7 @@ const json = {
46
46
  if (!state || ['array', 'object'].includes(state)) {
47
47
  return this.types();
48
48
  }
49
- // Todo: Should this throw?
50
- /* istanbul ignore next -- No other states apparently */
49
+ // Shouldn't normally reach here
51
50
  return undefined;
52
51
  }
53
52
  };
@@ -17,9 +17,10 @@ import json from './json.js';
17
17
  * type: import('../types.js').AvailableType,
18
18
  * value: import('../formats.js').StructuredCloneValue,
19
19
  * bringIntoFocus?: boolean,
20
+ * setAValue?: boolean,
20
21
  * schemaContent?: object,
21
22
  * schemaState?: import('../types.js').GetPossibleSchemasForPathAndType
22
- * }) => HTMLElement} AddAndSetArrayElement
23
+ * }) => HTMLElement|null} AddAndSetArrayElement
23
24
  */
24
25
 
25
26
  /**
@@ -44,6 +45,10 @@ const encapsulateObserver = (stateObj) => {
44
45
  * }}}
45
46
  */
46
47
  const parents = {};
48
+
49
+ /** @type {string[]} */
50
+ const mapPaths = [];
51
+
47
52
  return (observerObj) => {
48
53
  const {
49
54
  type,
@@ -57,13 +62,15 @@ const encapsulateObserver = (stateObj) => {
57
62
  endIterateUnsetNumeric,
58
63
  clone
59
64
  } = observerObj;
60
- // console.log('observerObj', observerObj);
61
65
  if ('replaced' in observerObj) {
62
66
  return;
63
67
  }
64
68
  if (cyclic === 'readonly' && !Array.isArray(observerObj.value)) {
65
69
  return;
66
70
  }
71
+ if (cyclic === 'readonly' && type === 'set') {
72
+ return;
73
+ }
67
74
  if (endIterateIn || endIterateOwn) {
68
75
  return;
69
76
  }
@@ -73,6 +80,12 @@ const encapsulateObserver = (stateObj) => {
73
80
  return;
74
81
  }
75
82
 
83
+ // What other situations is this firing twice, and it
84
+ // shouldn't reach here?
85
+ if (observerObj.replacing && type === 'negativeZero') {
86
+ return;
87
+ }
88
+
76
89
  /* istanbul ignore if -- Not part of format */
77
90
  if (type === 'sparseUndefined') { // We'll handle otherwise
78
91
  return;
@@ -119,12 +132,21 @@ const encapsulateObserver = (stateObj) => {
119
132
  const parentPath = li === -1 ? '' : keypath.slice(0, li);
120
133
 
121
134
  const hasChildren = [
122
- 'array', 'object',
135
+ 'array', 'object', 'set', 'map',
123
136
  // 'sparseArrays',
124
137
  'arrayNonindexKeys'
125
138
  ].includes(newType);
126
139
 
140
+ // Maps are followed up by arrays which we don't want as such;
141
+ // we track the paths to avoid reporting these child arrays
142
+ const mapType = type === 'map' &&
143
+ Object.prototype.toString.call(value) === '[object Map]';
144
+ if (mapType) {
145
+ mapPaths.push(keypath);
146
+ }
147
+
127
148
  if (!stateObj.rootUI) {
149
+ // console.log('vvvv0', newType, newValue);
128
150
  stateObj.rootUI = Types.getUIForModeAndType({
129
151
  readonly,
130
152
  typeNamespace,
@@ -152,6 +174,18 @@ const encapsulateObserver = (stateObj) => {
152
174
  * @type {HTMLElement &
153
175
  * {$addAndSetArrayElement: AddAndSetArrayElement}}
154
176
  */ (stateObj.rootUI);
177
+
178
+ // Since we're skipping the array elements, we need to add the
179
+ // map element to the array index where the array children
180
+ // will be found (which we do want)
181
+ if (mapType) {
182
+ /** @type {Map<any, any>} */ [...value].forEach((_, i) => {
183
+ parents[i] = /**
184
+ * @type {HTMLElement &
185
+ * {$addAndSetArrayElement: AddAndSetArrayElement}}
186
+ */ (stateObj.rootUI);
187
+ });
188
+ }
155
189
  return;
156
190
  }
157
191
 
@@ -172,6 +206,22 @@ const encapsulateObserver = (stateObj) => {
172
206
  return;
173
207
  }
174
208
 
209
+ // Skip the array structures immediately following the Map,
210
+ // as map needs to handle
211
+ if (!mapType && mapPaths.some((mapPath) => {
212
+ if (mapPath === keypath ||
213
+ (mapPath === '' && (/^\d+$/u).test(keypath))) {
214
+ return true;
215
+ }
216
+ const trailingIndex = keypath.match(/\.\d+$/u);
217
+ return (trailingIndex && mapPath !== '' &&
218
+ keypath.slice(0, -trailingIndex[0].length) === mapPath);
219
+ })) {
220
+ return;
221
+ }
222
+
223
+ // console.log('vvvv', newType, '::', newValue, '::', newValue?.cause);
224
+
175
225
  const root = ui.$addAndSetArrayElement({
176
226
  propName: arrayOrObjectPropertyName,
177
227
  type: newType,
@@ -188,7 +238,16 @@ const encapsulateObserver = (stateObj) => {
188
238
  })
189
239
  */
190
240
  });
241
+
242
+ /* istanbul ignore if -- Guard for `null` return */
243
+ if (!root) {
244
+ return;
245
+ }
246
+
191
247
  if (!readonly) {
248
+ // Todo: Redundant with `typeObj.setValue`? Ensure `idb-manager`
249
+ // does not need both; this write-only would seem preferable
250
+ // to the block in `arrayType.js` if readonly indeed not needed
192
251
  Types.setValue({
193
252
  type: newType,
194
253
  // eslint-disable-next-line object-shorthand -- TS
@@ -210,6 +269,18 @@ const encapsulateObserver = (stateObj) => {
210
269
  */ (
211
270
  root
212
271
  );
272
+
273
+ // Since we're skipping the array elements, we need to add the
274
+ // map element to the array index where the array children
275
+ // will be found (which we do want)
276
+ if (mapType) {
277
+ /** @type {Map<any, any>} */ [...value].forEach((_, i) => {
278
+ parents[`${keypath}.${i}`] = /**
279
+ * @type {HTMLElement &
280
+ * {$addAndSetArrayElement: AddAndSetArrayElement}}
281
+ */ (root);
282
+ });
283
+ }
213
284
  }
214
285
  });
215
286
  };
@@ -247,7 +318,7 @@ const canonicalToAvailableType = (format, state, valType, v) => {
247
318
  * @type {import('../types.js').AvailableType|undefined}
248
319
  */
249
320
  let ret;
250
- console.log('format, state, valType, v', format, state, valType, v);
321
+ // console.log('format, state, valType, v', format, state, valType, v);
251
322
 
252
323
  /**
253
324
  * @param {string} newValType
@@ -278,9 +349,9 @@ const canonicalToAvailableType = (format, state, valType, v) => {
278
349
  })) {
279
350
  return /** @type {import('../types.js').AvailableType} */ (ret);
280
351
  }
281
- console.log('ret', ret);
352
+ // console.log('ret', ret);
282
353
  allowableTypes.some((allowableType) => {
283
- // eslint-disable-next-line max-len -- Long
354
+ // eslint-disable-next-line @stylistic/max-len -- Long
284
355
  const typeObj = /** @type {import('../types.js').TypeObject & {childTypes: string[]}} */ (
285
356
  Types.availableTypes[allowableType]
286
357
  );
@@ -298,7 +369,7 @@ const canonicalToAvailableType = (format, state, valType, v) => {
298
369
  }
299
370
  return false;
300
371
  });
301
- console.log('ret2', ret);
372
+ // console.log('ret2', ret);
302
373
  if (ret === undefined) {
303
374
  return isInvalid(valType);
304
375
  }
@@ -315,7 +386,7 @@ const canonicalToAvailableType = (format, state, valType, v) => {
315
386
  /** @type {import('../formats.js').Format} */
316
387
  const structuredCloning = {
317
388
  iterate (records, stateObj) {
318
- console.log('records', records);
389
+ // console.log('records', records);
319
390
  if (!stateObj.format) {
320
391
  stateObj.format = 'structuredCloning';
321
392
  }
@@ -348,6 +419,12 @@ const structuredCloning = {
348
419
  });
349
420
  return typesForFormat;
350
421
  }
422
+ // Todo: Could we implement schemas here by introducing new keys to
423
+ // `Types.contexts` which could be used rather than manual
424
+ // handling to determine a delimited group of children
425
+ if (state === 'errorsArray') {
426
+ return ['error', 'errors'];
427
+ }
351
428
  return this.types();
352
429
  /*
353
430
  // Todo (low): These need to specify their own inner contexts
@@ -375,35 +452,33 @@ const structuredCloning = {
375
452
  ...jsonTypes,
376
453
  'undef', // Explicit undefined only
377
454
  'bigint',
378
- 'SpecialNumber', // '`NaN`, `Infinity`, `-Infinity`'},
455
+ 'SpecialNumber', // '`NaN`, `Infinity`, `-Infinity`, `-0`
379
456
  'date',
380
457
  'regexp',
381
458
  'BooleanObject',
382
459
  'NumberObject',
383
460
  'StringObject',
384
- 'blobHTML'
461
+ 'error',
462
+ 'errors',
463
+ 'blobHTML',
464
+ 'set',
465
+ 'map'
385
466
  // Ok, but will need some work
386
- // 'map', 'set',
387
- // 'blob', 'file', 'filelist'
388
- // 'arraybuffer', 'arraybufferview'
467
+ // 'blob', 'file', 'filelist',
468
+ // 'arraybuffer',
389
469
  // 'dataview', 'imagedata', 'imagebitmap',
390
470
  /*
391
- // Typed Arrays
392
- 'int8array',
393
- 'uint8array',
394
- 'uint8clampedarray',
395
- 'int16array',
396
- 'uint16array',
397
- 'int32array',
398
- 'uint32array',
399
- 'float32array',
400
- 'float64array',
401
-
402
- // Intl (imperfect)
403
- 'IntlCollator',
404
- 'IntlDateTimeFormat',
405
- 'IntlNumberFormat'
406
- */
471
+ // Typed Arrays
472
+ 'int8array',
473
+ 'uint8array',
474
+ 'uint8clampedarray',
475
+ 'int16array',
476
+ 'uint16array',
477
+ 'int32array',
478
+ 'uint32array',
479
+ 'float32array',
480
+ 'float64array',
481
+ */
407
482
  ];
408
483
  }
409
484
  };
package/src/formats.js CHANGED
@@ -56,8 +56,8 @@ const Formats = {
56
56
  * @returns {Promise<Element>}
57
57
  */
58
58
  export async function getControlsForFormatAndValue (format, record, stateObj) {
59
- return await Formats.availableFormats[format]
60
- .iterate(record, {
59
+ return await Formats.availableFormats[format].
60
+ iterate(record, {
61
61
  ...stateObj,
62
62
  // This had been before `stateObj` but should apparently have precedence
63
63
  // or just avoid passing `format` to this function
@@ -35,7 +35,7 @@ const arrayReferenceType = {
35
35
  structuredCloning: {
36
36
  // after: 'sparseArrays',
37
37
  after: 'arrayNonindexKeys',
38
- contexts: ['arrayNonindexKeys', 'object']
38
+ contexts: ['arrayNonindexKeys', 'object', 'set']
39
39
  // contexts: ['sparseArrays', 'object']
40
40
  }
41
41
  },
@@ -47,7 +47,7 @@ const arrayReferenceType = {
47
47
  },
48
48
  getValue ({root, stateObj, currentPath}) {
49
49
  const referentPath = this.getInput({root}).value;
50
- // eslint-disable-next-line max-len -- Long
50
+ // eslint-disable-next-line @stylistic/max-len -- Long
51
51
  /* istanbul ignore else -- ArrayRef will not be a root, so should have stateObj */
52
52
  if (stateObj) {
53
53
  if (!stateObj.paths) {
@@ -97,7 +97,7 @@ const arrayReferenceType = {
97
97
  'arrayNonindexKeys'
98
98
  // 'sparseArrays'
99
99
  ].includes(
100
- /** @type {string} */ (Types.getTypeForRoot(referent))
100
+ Types.getTypeForRoot(referent)
101
101
  );
102
102
  };
103
103
  let message;