textbrowser 0.50.0 → 0.51.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 (104) hide show
  1. package/.ncurc.cjs +3 -0
  2. package/CHANGES.md +8 -0
  3. package/dist/WorkInfo-es.js +361 -111
  4. package/dist/activateCallback-es.js +72 -10
  5. package/dist/dist/WorkInfo-es.d.ts +331 -0
  6. package/dist/dist/WorkInfo-es.d.ts.map +1 -0
  7. package/dist/dist/activateCallback-es.d.ts +17 -0
  8. package/dist/dist/activateCallback-es.d.ts.map +1 -0
  9. package/dist/dist/index-es.d.ts +619 -0
  10. package/dist/dist/index-es.d.ts.map +1 -0
  11. package/dist/dist/sw-helper.d.ts +3 -0
  12. package/dist/dist/sw-helper.d.ts.map +1 -0
  13. package/dist/eslint.config.d.ts +126 -0
  14. package/dist/eslint.config.d.ts.map +1 -0
  15. package/dist/index-es.js +959 -195
  16. package/dist/index-es.min.js +2 -2
  17. package/dist/resources/activateCallback.d.ts +23 -0
  18. package/dist/resources/activateCallback.d.ts.map +1 -0
  19. package/dist/resources/index.d.ts +128 -0
  20. package/dist/resources/index.d.ts.map +1 -0
  21. package/dist/resources/resultsDisplay.d.ts +110 -0
  22. package/dist/resources/resultsDisplay.d.ts.map +1 -0
  23. package/dist/resources/templates/index.d.ts +59 -0
  24. package/dist/resources/templates/index.d.ts.map +1 -0
  25. package/dist/resources/templates/languageSelect.d.ts +18 -0
  26. package/dist/resources/templates/languageSelect.d.ts.map +1 -0
  27. package/dist/resources/templates/resultsDisplayClient.d.ts +26 -0
  28. package/dist/resources/templates/resultsDisplayClient.d.ts.map +1 -0
  29. package/dist/resources/templates/resultsDisplayServerOrClient.d.ts +131 -0
  30. package/dist/resources/templates/resultsDisplayServerOrClient.d.ts.map +1 -0
  31. package/dist/resources/templates/utils/dom.d.ts +15 -0
  32. package/dist/resources/templates/utils/dom.d.ts.map +1 -0
  33. package/dist/resources/templates/utils/html.d.ts +3 -0
  34. package/dist/resources/templates/utils/html.d.ts.map +1 -0
  35. package/dist/resources/templates/workDisplay.d.ts +183 -0
  36. package/dist/resources/templates/workDisplay.d.ts.map +1 -0
  37. package/dist/resources/templates/workSelect.d.ts +18 -0
  38. package/dist/resources/templates/workSelect.d.ts.map +1 -0
  39. package/dist/resources/user-sample.d.ts +2 -0
  40. package/dist/resources/user-sample.d.ts.map +1 -0
  41. package/dist/resources/user.d.ts +2 -0
  42. package/dist/resources/user.d.ts.map +1 -0
  43. package/dist/resources/utils/IntlURLSearchParams.d.ts +56 -0
  44. package/dist/resources/utils/IntlURLSearchParams.d.ts.map +1 -0
  45. package/dist/resources/utils/Languages.d.ts +81 -0
  46. package/dist/resources/utils/Languages.d.ts.map +1 -0
  47. package/dist/resources/utils/Metadata.d.ts +133 -0
  48. package/dist/resources/utils/Metadata.d.ts.map +1 -0
  49. package/dist/resources/utils/Params.d.ts +30 -0
  50. package/dist/resources/utils/Params.d.ts.map +1 -0
  51. package/dist/resources/utils/Plugin.d.ts +274 -0
  52. package/dist/resources/utils/Plugin.d.ts.map +1 -0
  53. package/dist/resources/utils/ServiceWorker.d.ts +26 -0
  54. package/dist/resources/utils/ServiceWorker.d.ts.map +1 -0
  55. package/dist/resources/utils/WorkInfo.d.ts +104 -0
  56. package/dist/resources/utils/WorkInfo.d.ts.map +1 -0
  57. package/dist/resources/utils/dialogs.d.ts +155 -0
  58. package/dist/resources/utils/dialogs.d.ts.map +1 -0
  59. package/dist/resources/utils/getLocaleFallbackResults.d.ts +19 -0
  60. package/dist/resources/utils/getLocaleFallbackResults.d.ts.map +1 -0
  61. package/dist/resources/utils/sanitize.d.ts +6 -0
  62. package/dist/resources/utils/sanitize.d.ts.map +1 -0
  63. package/dist/resources/vendor/json-refs-min.d.ts +3 -0
  64. package/dist/resources/vendor/json-refs-min.d.ts.map +1 -0
  65. package/dist/resources/workDisplay.d.ts +81 -0
  66. package/dist/resources/workDisplay.d.ts.map +1 -0
  67. package/dist/resources/workSelect.d.ts +17 -0
  68. package/dist/resources/workSelect.d.ts.map +1 -0
  69. package/dist/rollup.config.d.ts +19 -0
  70. package/dist/rollup.config.d.ts.map +1 -0
  71. package/dist/server/main.d.ts +46 -0
  72. package/dist/server/main.d.ts.map +1 -0
  73. package/dist/sw-helper.d.ts +3 -0
  74. package/dist/sw-helper.d.ts.map +1 -0
  75. package/dist/sw-helper.js +52 -12
  76. package/dist/sw-sample.d.ts +2 -0
  77. package/dist/sw-sample.d.ts.map +1 -0
  78. package/general-schemas/files.jsonschema +6 -0
  79. package/package.json +21 -8
  80. package/resources/activateCallback.js +75 -10
  81. package/resources/index.js +161 -49
  82. package/resources/resultsDisplay.js +517 -152
  83. package/resources/templates/index.js +39 -16
  84. package/resources/templates/languageSelect.js +14 -1
  85. package/resources/templates/resultsDisplayClient.js +22 -3
  86. package/resources/templates/resultsDisplayServerOrClient.js +188 -49
  87. package/resources/templates/utils/dom.js +13 -2
  88. package/resources/templates/workDisplay.js +299 -75
  89. package/resources/templates/workSelect.js +16 -3
  90. package/resources/utils/IntlURLSearchParams.js +46 -4
  91. package/resources/utils/Languages.js +71 -4
  92. package/resources/utils/Metadata.js +219 -22
  93. package/resources/utils/Params.js +70 -23
  94. package/resources/utils/Plugin.js +169 -1
  95. package/resources/utils/ServiceWorker.js +48 -19
  96. package/resources/utils/WorkInfo.js +255 -43
  97. package/resources/utils/dialogs.js +105 -7
  98. package/resources/utils/getLocaleFallbackResults.js +12 -2
  99. package/resources/utils/sanitize.js +4 -0
  100. package/resources/workDisplay.js +151 -25
  101. package/resources/workSelect.js +37 -17
  102. package/server/main.js +111 -19
  103. package/tsconfig.json +30 -0
  104. package/resources/user.js +0 -20
@@ -1,68 +1,69 @@
1
- /* eslint-disable node/no-unsupported-features/es-syntax */
1
+ /**
2
+ * @typedef {JSONValue[]} JSONArray
3
+ */
4
+ /**
5
+ * @typedef {null|boolean|number|string|JSONArray|{[key: string]: JSONValue}} JSONValue
6
+ */
7
+
8
+ /**
9
+ * @callback SimpleJSONCallback
10
+ * @param {...JSONValue} json
11
+ * @returns {void}
12
+ */
13
+
14
+ /**
15
+ * @callback SimpleJSONErrback
16
+ * @param {Error} err
17
+ * @param {string|string[]} jsonURL
18
+ * @returns {JSONValue}
19
+ */
2
20
 
3
21
  /**
4
- * @callback getJSONCallback
5
- * @param {string|string[]} jsonURL
6
- * @param {SimpleJSONCallback} cb
7
- * @param {SimpleJSONErrback} errBack
8
- * @returns {Promise<JSON>}
22
+ * @typedef {((
23
+ * jsonURL: string|string[],
24
+ * cb?: SimpleJSONCallback,
25
+ * errBack?: SimpleJSONErrback
26
+ * ) => Promise<JSONValue>) & {
27
+ * _fetch?: import('./index-polyglot.js').SimpleFetch,
28
+ * hasURLBasePath?: boolean,
29
+ * basePath?: string|false
30
+ * }} getJSONCallback
9
31
  */
10
32
 
11
33
  /**
12
- * @param {PlainObject} cfg
13
- * @param {fetch} cfg.fetch
34
+ * @param {object} [cfg]
35
+ * @param {import('./index-polyglot.js').SimpleFetch} [cfg.fetch]
14
36
  * @returns {getJSONCallback}
15
37
  */
16
- function _await$2$1(value, then, direct) {
17
38
 
39
+ function _await$2$1(value, then, direct) {
18
40
  if (!value || !value.then) {
19
41
  value = Promise.resolve(value);
20
42
  }
21
-
22
43
  return then ? value.then(then) : value;
23
44
  }
24
-
25
45
  function _invoke$1(body, then) {
26
46
  var result = body();
27
-
28
47
  if (result && result.then) {
29
48
  return result.then(then);
30
49
  }
31
-
32
50
  return then(result);
33
51
  }
34
-
35
52
  function _catch$2(body, recover) {
36
53
  try {
37
54
  var result = body();
38
55
  } catch (e) {
39
56
  return recover(e);
40
57
  }
41
-
42
58
  if (result && result.then) {
43
59
  return result.then(void 0, recover);
44
60
  }
45
-
46
61
  return result;
47
62
  }
48
-
49
63
  function buildGetJSONWithFetch({
50
- // eslint-disable-next-line no-shadow
64
+ // eslint-disable-next-line no-shadow, no-undef -- This is a polyfill
51
65
  fetch = typeof window !== 'undefined' ? window.fetch : self.fetch
52
66
  } = {}) {
53
- /**
54
- * @callback SimpleJSONCallback
55
- * @param {JSON} json
56
- * @returns {void}
57
- */
58
-
59
- /**
60
- * @callback SimpleJSONErrback
61
- * @param {Error} err
62
- * @param {string|string[]} jsonURL
63
- * @returns {void}
64
- */
65
-
66
67
  /**
67
68
  * @type {getJSONCallback}
68
69
  */
@@ -73,13 +74,12 @@ function buildGetJSONWithFetch({
73
74
  return _invoke$1(function () {
74
75
  if (Array.isArray(jsonURL)) {
75
76
  return _await$2$1(Promise.all(jsonURL.map(url => {
76
- return getJSON(url);
77
+ return /** @type {getJSONCallback} */getJSON(url);
77
78
  })), function (arrResult) {
78
79
  if (cb) {
79
- // eslint-disable-next-line node/callback-return, node/no-callback-literal, promise/prefer-await-to-callbacks
80
+ // eslint-disable-next-line promise/prefer-await-to-callbacks -- Old-style API
80
81
  cb(...arrResult);
81
82
  }
82
-
83
83
  _exit = true;
84
84
  return arrResult;
85
85
  });
@@ -87,22 +87,22 @@ function buildGetJSONWithFetch({
87
87
  }, function (_result) {
88
88
  return _exit ? _result : _await$2$1(fetch(jsonURL), function (resp) {
89
89
  return _await$2$1(resp.json(), function (result) {
90
- return typeof cb === 'function' // eslint-disable-next-line promise/prefer-await-to-callbacks
91
- ? cb(result) : result; // https://github.com/bcoe/c8/issues/135
92
-
90
+ return typeof cb === 'function'
91
+ // eslint-disable-next-line promise/prefer-await-to-callbacks -- Old-style API
92
+ ? cb(result) : result;
93
+ // https://github.com/bcoe/c8/issues/135
93
94
  /* c8 ignore next */
94
95
  });
95
96
  });
96
97
  });
97
- }, function (e) {
98
+ }, function (err) {
99
+ const e = /** @type {Error} */err;
98
100
  e.message += ` (File: ${jsonURL})`;
99
-
100
101
  if (errBack) {
101
102
  return errBack(e, jsonURL);
102
103
  }
103
-
104
- throw e; // https://github.com/bcoe/c8/issues/135
105
-
104
+ throw e;
105
+ // https://github.com/bcoe/c8/issues/135
106
106
  /* c8 ignore next */
107
107
  }));
108
108
  /* c8 ignore next */
@@ -113,44 +113,43 @@ function buildGetJSONWithFetch({
113
113
  }
114
114
 
115
115
  function _await$1$1(value, then, direct) {
116
-
117
116
  if (!value || !value.then) {
118
117
  value = Promise.resolve(value);
119
118
  }
120
-
121
119
  return then ? value.then(then) : value;
122
120
  }
121
+ /* globals process -- Node */
123
122
 
124
- /* eslint-disable node/no-unsupported-features/node-builtins,
125
- node/no-unsupported-features/es-syntax, compat/compat */
126
123
  // Needed for polyglot support (no `path` in browser); even if
127
124
  // polyglot using dynamic `import` not supported by Rollup (complaining
128
125
  // of inability to do tree-shaking in UMD builds), still useful to delay
129
126
  // path import for our testing, so that test can import this file in
130
127
  // the browser without compilation without it choking
131
- let dirname, isWindows;
132
128
 
133
- function _empty() {}
134
129
  /**
135
- * @param {string} path
136
- * @returns {string}
130
+ * @type {(directory: string) => string}
137
131
  */
132
+ let dirname;
138
133
 
134
+ /** @type {boolean} */
139
135
 
136
+ function _empty() {}
137
+ let isWindows;
140
138
  function _invokeIgnored(body) {
141
139
  var result = body();
142
-
143
140
  if (result && result.then) {
144
141
  return result.then(_empty);
145
142
  }
146
- }
143
+ } /**
144
+ * @param {string} path
145
+ * @returns {string}
146
+ */
147
147
 
148
148
  function _async$1$1(f) {
149
149
  return function () {
150
150
  for (var args = [], i = 0; i < arguments.length; i++) {
151
151
  args[i] = arguments[i];
152
152
  }
153
-
154
153
  try {
155
154
  return Promise.resolve(f.apply(this, args));
156
155
  } catch (e) {
@@ -158,11 +157,10 @@ function _async$1$1(f) {
158
157
  }
159
158
  };
160
159
  }
161
-
162
160
  const setDirname = _async$1$1(function () {
163
161
  return _invokeIgnored(function () {
164
162
  if (!dirname) {
165
- return _await$1$1(import('path'), function (_import) {
163
+ return _await$1$1(import('node:path'), function (_import) {
166
164
  ({
167
165
  dirname
168
166
  } = _import);
@@ -170,23 +168,20 @@ const setDirname = _async$1$1(function () {
170
168
  }
171
169
  });
172
170
  });
173
-
174
171
  function fixWindowsPath(path) {
175
172
  if (!isWindows) {
176
173
  isWindows = process.platform === 'win32';
177
174
  }
178
-
179
- return path.slice( // https://github.com/bcoe/c8/issues/135
180
-
175
+ return path.slice(
176
+ // https://github.com/bcoe/c8/issues/135
181
177
  /* c8 ignore next */
182
178
  isWindows ? 1 : 0);
183
179
  }
180
+
184
181
  /**
185
182
  * @param {string} url
186
183
  * @returns {string}
187
184
  */
188
-
189
-
190
185
  function getDirectoryForURL(url) {
191
186
  // Node should be ok with this, but transpiling
192
187
  // to `require` doesn't work, so detect Windows
@@ -195,37 +190,36 @@ function getDirectoryForURL(url) {
195
190
  return fixWindowsPath(dirname(new URL(url).pathname));
196
191
  }
197
192
 
198
- /* eslint-disable node/no-unsupported-features/es-syntax */
193
+ /* globals window, self -- Polyglot */
199
194
 
200
- function _await$3(value, then, direct) {
195
+ /**
196
+ * @typedef {(url: string) => Promise<Response>} SimpleFetch
197
+ */
201
198
 
199
+ /** @type {{default: SimpleFetch}} */
200
+
201
+ function _await$3(value, then, direct) {
202
202
  if (!value || !value.then) {
203
203
  value = Promise.resolve(value);
204
204
  }
205
-
206
205
  return then ? value.then(then) : value;
207
206
  }
208
-
209
207
  let nodeFetch;
210
208
  /**
211
- * @param {PlainObject} cfg
212
- * @param {string} cfg.baseURL
213
- * @param {string} cfg.cwd
214
- * @returns {getJSONCallback}
209
+ * @param {object} [cfg]
210
+ * @param {string} [cfg.baseURL]
211
+ * @param {string|false} [cfg.cwd]
212
+ * @returns {import('./buildGetJSONWithFetch.js').getJSONCallback}
215
213
  */
216
214
 
217
215
  function _invoke$2(body, then) {
218
216
  var result = body();
219
-
220
217
  if (result && result.then) {
221
218
  return result.then(then);
222
219
  }
223
-
224
220
  return then(result);
225
221
  }
226
-
227
222
  function _call(body, then, direct) {
228
-
229
223
  try {
230
224
  var result = Promise.resolve(body());
231
225
  return then ? result.then(then) : result;
@@ -233,13 +227,11 @@ function _call(body, then, direct) {
233
227
  return Promise.reject(e);
234
228
  }
235
229
  }
236
-
237
230
  function _async$2(f) {
238
231
  return function () {
239
232
  for (var args = [], i = 0; i < arguments.length; i++) {
240
233
  args[i] = arguments[i];
241
234
  }
242
-
243
235
  try {
244
236
  return Promise.resolve(f.apply(this, args));
245
237
  } catch (e) {
@@ -247,24 +239,32 @@ function _async$2(f) {
247
239
  }
248
240
  };
249
241
  }
250
-
251
242
  function buildGetJSON({
252
243
  baseURL,
253
244
  cwd: basePath
254
245
  } = {}) {
255
- const _fetch = typeof window !== 'undefined' || typeof self !== 'undefined' ? typeof window !== 'undefined' ? window.fetch : self.fetch : _async$2(function (jsonURL) {
246
+ const _fetch = typeof window !== 'undefined' || typeof self !== 'undefined' ? typeof window !== 'undefined' ? window.fetch : self.fetch
247
+ // eslint-disable-next-line @stylistic/operator-linebreak -- TS
248
+ :
249
+ /**
250
+ * @param {string} jsonURL
251
+ * @returns {Promise<Response>}
252
+ */
253
+ _async$2(function (jsonURL) {
256
254
  let _exit = false;
257
255
  return _invoke$2(function () {
258
256
  if (/^https?:/u.test(jsonURL)) {
259
257
  return _invoke$2(function () {
260
258
  if (!nodeFetch) {
261
- return _await$3(import('node-fetch'), function (_import) {
259
+ return _await$3(import('node-fetch'), function (
260
+ /** @type {{default: SimpleFetch}} */
261
+ /** @type {unknown} */
262
+ _import) {
262
263
  nodeFetch = _import;
263
264
  });
264
265
  }
265
266
  }, function () {
266
- const _nodeFetch$default = nodeFetch.default(jsonURL);
267
-
267
+ const _nodeFetch$default = /** @type {SimpleFetch} */nodeFetch.default(jsonURL);
268
268
  _exit = true;
269
269
  return _nodeFetch$default;
270
270
  });
@@ -280,48 +280,50 @@ function buildGetJSON({
280
280
  // Filed https://github.com/bergos/file-fetch/issues/12 to see
281
281
  // about getting relative basePaths in `file-fetch` and using
282
282
  // that better-tested package instead
283
+ // @ts-expect-error Todo
284
+ // Don't change to an import as won't resolve for browser testing
285
+ // eslint-disable-next-line promise/avoid-new -- own API
286
+ /* c8 ignore next */
283
287
  return _await$3(import('local-xmlhttprequest'), function (localXMLHttpRequest) {
284
- // eslint-disable-next-line no-shadow
285
- const XMLHttpRequest = localXMLHttpRequest.default({
288
+ const XMLHttpRequest = /* eslint-disable jsdoc/valid-types -- Bug */
289
+ /**
290
+ * @type {{
291
+ * prototype: XMLHttpRequest;
292
+ * new(): XMLHttpRequest
293
+ * }}
294
+ */localXMLHttpRequest.default({
295
+ /* eslint-enable jsdoc/valid-types -- Bug */
286
296
  basePath
287
- }); // Don't change to an import as won't resolve for browser testing
288
- // eslint-disable-next-line promise/avoid-new
289
-
297
+ });
290
298
  return new Promise((resolve, reject) => {
291
299
  const r = new XMLHttpRequest();
292
- r.open('GET', jsonURL, true); // r.responseType = 'json';
300
+ r.open('GET', jsonURL, true);
301
+ // r.responseType = 'json';
293
302
  // eslint-disable-next-line unicorn/prefer-add-event-listener -- May not be available
294
-
295
303
  r.onreadystatechange = function () {
296
304
  // Not sure how to simulate `if`
297
-
298
- /* c8 ignore next */
305
+ /* c8 ignore next 3 */
299
306
  if (r.readyState !== 4) {
300
307
  return;
301
308
  }
302
-
303
309
  if (r.status === 200) {
304
310
  // var json = r.json;
305
311
  const response = r.responseText;
306
- resolve({
312
+ resolve(/** @type {Response} */{
307
313
  json: () => JSON.parse(response)
308
314
  });
309
315
  return;
310
316
  }
311
-
312
317
  reject(new SyntaxError('Failed to fetch URL: ' + jsonURL + 'state: ' + r.readyState + '; status: ' + r.status));
313
318
  };
314
-
315
- r.send(); // https://github.com/bcoe/c8/issues/135
316
-
319
+ r.send();
320
+ // https://github.com/bcoe/c8/issues/135
317
321
  /* c8 ignore next */
318
322
  });
319
- /* c8 ignore next */
320
323
  });
321
324
  });
322
325
  });
323
326
  });
324
-
325
327
  const ret = buildGetJSONWithFetch({
326
328
  fetch: _fetch
327
329
  });
@@ -330,7 +332,6 @@ function buildGetJSON({
330
332
  ret.basePath = basePath;
331
333
  return ret;
332
334
  }
333
-
334
335
  const getJSON = buildGetJSON();
335
336
 
336
337
  function _iterableToArrayLimit(arr, i) {
@@ -3194,12 +3195,23 @@ var i18n = function i18n() {
3194
3195
  };
3195
3196
 
3196
3197
  // Todo: remember this locales choice by cookie?
3198
+
3199
+ /**
3200
+ * @param {{
3201
+ * namespace: string,
3202
+ * preferredLocale: string
3203
+ * }} cfg
3204
+ */
3197
3205
  const getPreferredLanguages = ({namespace, preferredLocale}) => {
3198
3206
  // Todo: Add to this optionally with one-off tag input box
3199
3207
  // Todo: Switch to fallbackLanguages so can default to
3200
3208
  // navigator.languages?
3201
3209
  const langCodes = localStorage.getItem(namespace + '-langCodes');
3202
- const lngs = (langCodes && JSON.parse(langCodes)) || [preferredLocale];
3210
+ const lngs = /** @type {string[]} */ (
3211
+ (langCodes && JSON.parse(langCodes)) || [preferredLocale]
3212
+ );
3213
+
3214
+ /** @type {string[]} */
3203
3215
  const langArr = [];
3204
3216
  lngs.forEach((lng) => {
3205
3217
  // Todo: Check for multiple separate hyphenated
@@ -3233,14 +3245,46 @@ const getCurrDir = () => {
3233
3245
  return window.location.href.replace(/(index\.html)?#.*$/, '');
3234
3246
  };
3235
3247
 
3248
+ /**
3249
+ * @typedef {{
3250
+ * "localization-strings": import('../../server/main.js').LocalizationStrings
3251
+ * table: {browse_fields: (string|{
3252
+ * name?: string,
3253
+ * set: string[],
3254
+ * presort?: boolean
3255
+ * })[]}
3256
+ * fields: {
3257
+ * [key: string]: {
3258
+ * prefer_alias: boolean,
3259
+ * lang: string,
3260
+ * 'fieldvalue-aliases': {
3261
+ * localeKey: string,
3262
+ * [key: string]: string|string[]
3263
+ * }
3264
+ * }
3265
+ * }
3266
+ * }} MetadataObj
3267
+ */
3268
+
3269
+ /**
3270
+ * @param {string[]} lang
3271
+ * @param {MetadataObj} metadataObj
3272
+ * @param {string|string[]} properties
3273
+ * @param {boolean} [allowObjects]
3274
+ * @returns {string|string[]|import('../../server/main.js').LocalizationStrings}
3275
+ */
3236
3276
  const getMetaProp = function getMetaProp (lang, metadataObj, properties, allowObjects) {
3237
3277
  let prop;
3238
3278
  properties = typeof properties === 'string' ? [properties] : properties;
3239
- lang.some((lan) => {
3279
+ for (const lan of lang) {
3240
3280
  const p = [...properties];
3241
- let strings = metadataObj['localization-strings'][lan];
3281
+ let strings = /** @type {string | string[]|import('../../server/main.js').LocalizationStrings} */ (
3282
+ metadataObj['localization-strings'][lan]
3283
+ );
3242
3284
  while (strings && p.length) {
3243
- strings = strings[p.shift()];
3285
+ strings = /** @type {import('../../server/main.js').LocalizationStrings} */ (
3286
+ strings
3287
+ )[/** @type {string} */ (p.shift())];
3244
3288
  }
3245
3289
  // Todo: Fix this allowance for allowObjects (as it does not properly
3246
3290
  // fallback if an object is returned from a language because
@@ -3249,9 +3293,13 @@ const getMetaProp = function getMetaProp (lang, metadataObj, properties, allowOb
3249
3293
  prop = (typeof strings === 'string')
3250
3294
  ? strings
3251
3295
  : undefined;
3252
- return prop;
3253
- });
3254
- return prop;
3296
+ if (prop) {
3297
+ break;
3298
+ }
3299
+ }
3300
+ return /** @type {string|string[]|import('../../server/main.js').LocalizationStrings} */ (
3301
+ prop
3302
+ );
3255
3303
  };
3256
3304
 
3257
3305
  // Use the following to dynamically add specific file schema in place of
@@ -3259,6 +3307,12 @@ const getMetaProp = function getMetaProp (lang, metadataObj, properties, allowOb
3259
3307
  // filesSchema.properties.groups.items.properties.files.items.properties.
3260
3308
  // file.anyOf.splice(1, 1, {$ref: schemaFile});
3261
3309
  // Todo: Allow use of dbs and fileGroup together in base directories?
3310
+
3311
+ /**
3312
+ * @param {string} file
3313
+ * @param {string} property
3314
+ * @param {string} basePath
3315
+ */
3262
3316
  const getMetadata = async (file, property, basePath) => {
3263
3317
  const url = new URL(basePath || getCurrDir());
3264
3318
  url.search = ''; // Clear out query string, e.g., `?fbclid` from Facebook
@@ -3270,6 +3324,13 @@ const getMetadata = async (file, property, basePath) => {
3270
3324
  url.toString(),
3271
3325
  {
3272
3326
  loaderOptions: {
3327
+ /**
3328
+ * @param {{
3329
+ * text: string,
3330
+ * body: any
3331
+ * }} res
3332
+ * @param {(err?: Error, cbValue: any) => void} callback
3333
+ */
3273
3334
  processContent (res, callback) {
3274
3335
  callback(undefined, JSON.parse(
3275
3336
  res.text ||
@@ -3285,16 +3346,37 @@ const getMetadata = async (file, property, basePath) => {
3285
3346
 
3286
3347
  // Todo: Incorporate other methods into this class
3287
3348
  class Metadata {
3349
+ /**
3350
+ * @param {{
3351
+ * metadataObj: MetadataObj
3352
+ * }} cfg
3353
+ */
3288
3354
  constructor ({metadataObj}) {
3289
3355
  this.metadataObj = metadataObj;
3290
3356
  }
3291
3357
 
3358
+ /**
3359
+ * @param {string} field
3360
+ * @returns {string|undefined}
3361
+ */
3292
3362
  getFieldLang (field) {
3293
3363
  const {metadataObj} = this;
3294
3364
  const fields = metadataObj && metadataObj.fields;
3295
3365
  return fields && fields[field] && fields[field].lang;
3296
3366
  }
3297
3367
 
3368
+ /**
3369
+ * @param {{
3370
+ * namespace: string,
3371
+ * preferredLocale: string,
3372
+ * schemaItems: {
3373
+ * title: string,
3374
+ * type: string
3375
+ * }[],
3376
+ * pluginsForWork: import('./Plugin.js').PluginsForWork
3377
+ * }} cfg
3378
+ * @returns {(field: string) => boolean}
3379
+ */
3298
3380
  getFieldMatchesLocale ({
3299
3381
  namespace, preferredLocale, schemaItems,
3300
3382
  pluginsForWork
@@ -3321,7 +3403,9 @@ class Metadata {
3321
3403
  const hasFieldValue = localeStrings &&
3322
3404
  Object.keys(localeStrings).some((lng) => {
3323
3405
  const fv = localeStrings[lng] &&
3324
- localeStrings[lng].fieldvalue;
3406
+ /** @type {import('../../server/main.js').LocalizationStrings} */
3407
+ (/** @type {import('../../server/main.js').LocalizationStrings} */
3408
+ (localeStrings[lng]).fieldvalue);
3325
3409
  return fv && fv[field];
3326
3410
  });
3327
3411
 
@@ -3334,11 +3418,17 @@ class Metadata {
3334
3418
  }
3335
3419
  }
3336
3420
 
3421
+ /**
3422
+ * @param {string} pluginName
3423
+ */
3337
3424
  const escapePluginComponent = (pluginName) => {
3338
3425
  return pluginName.replaceAll('^', '^^'). // Escape our escape
3339
3426
  replaceAll('-', '^0');
3340
3427
  };
3341
3428
 
3429
+ /**
3430
+ * @param {string|undefined} pluginName
3431
+ */
3342
3432
  const unescapePluginComponent = (pluginName) => {
3343
3433
  if (!pluginName) {
3344
3434
  return pluginName;
@@ -3353,18 +3443,50 @@ const unescapePluginComponent = (pluginName) => {
3353
3443
  ).replaceAll('^^', '^');
3354
3444
  };
3355
3445
 
3446
+ /**
3447
+ * @param {{
3448
+ * pluginName: string,
3449
+ * applicableField: string,
3450
+ * targetLanguage: string
3451
+ * }} cfg
3452
+ */
3356
3453
  const escapePlugin = ({pluginName, applicableField, targetLanguage}) => {
3357
3454
  return escapePluginComponent(pluginName) +
3358
3455
  (applicableField ? '-' + escapePluginComponent(applicableField) : '-') +
3359
3456
  (targetLanguage ? '-' + escapePluginComponent(targetLanguage) : '');
3360
3457
  };
3361
3458
 
3459
+ /**
3460
+ * @todo Complete
3461
+ * @typedef {{}} PluginObject
3462
+ */
3463
+
3362
3464
  class PluginsForWork {
3465
+ /**
3466
+ * @param {{
3467
+ * pluginsInWork: [string, {
3468
+ * lang: string,
3469
+ * meta: any,
3470
+ * onByDefault: boolean
3471
+ * }][],
3472
+ * pluginFieldMappings: {
3473
+ * placement: string,
3474
+ * 'applicable-fields': {
3475
+ * }
3476
+ * }[],
3477
+ * pluginObjects: PluginObject[]
3478
+ * }} cfg
3479
+ */
3363
3480
  constructor ({pluginsInWork, pluginFieldMappings, pluginObjects}) {
3364
3481
  this.pluginsInWork = pluginsInWork;
3365
3482
  this.pluginFieldMappings = pluginFieldMappings;
3366
3483
  this.pluginObjects = pluginObjects;
3367
3484
  }
3485
+
3486
+ /**
3487
+ * @param {string} pluginName
3488
+ * @returns {PluginObject}
3489
+ */
3368
3490
  getPluginObject (pluginName) {
3369
3491
  const idx = this.pluginsInWork.findIndex(([name]) => {
3370
3492
  return name === pluginName;
@@ -3372,6 +3494,25 @@ class PluginsForWork {
3372
3494
  const plugin = this.pluginObjects[idx];
3373
3495
  return plugin;
3374
3496
  }
3497
+
3498
+ /**
3499
+ * @param {(cfg: {
3500
+ * plugin: PluginObject,
3501
+ * placement: string,
3502
+ * applicableFields: {
3503
+ * [applicableField: string]: {
3504
+ * targetLanguage: string|string[],
3505
+ * onByDefault: boolean,
3506
+ * meta: any
3507
+ * }
3508
+ * },
3509
+ * pluginName: string,
3510
+ * pluginLang: string,
3511
+ * onByDefaultDefault: boolean,
3512
+ * meta: {}
3513
+ * }) => void} cb
3514
+ * @returns {void}
3515
+ */
3375
3516
  iterateMappings (cb) {
3376
3517
  this.pluginFieldMappings.forEach(({
3377
3518
  placement,
@@ -3398,6 +3539,25 @@ class PluginsForWork {
3398
3539
  });
3399
3540
  });
3400
3541
  }
3542
+
3543
+ /**
3544
+ * @param {{
3545
+ * [applicableField: string]: {
3546
+ * targetLanguage: string|string[],
3547
+ * onByDefault: boolean,
3548
+ * meta: any
3549
+ * }
3550
+ * }} applicableFields
3551
+ * @param {(cfg: {
3552
+ * applicableField: string,
3553
+ * targetLanguage: string,
3554
+ * onByDefault: boolean,
3555
+ * metaApplicableField: {
3556
+ * [key: string]: string
3557
+ * }
3558
+ * }) => void} cb
3559
+ * @returns {boolean}
3560
+ */
3401
3561
  processTargetLanguages (applicableFields, cb) {
3402
3562
  if (!applicableFields) {
3403
3563
  return false;
@@ -3415,9 +3575,25 @@ class PluginsForWork {
3415
3575
  });
3416
3576
  return true;
3417
3577
  }
3578
+
3579
+ /**
3580
+ * @param {{
3581
+ * namespace: string,
3582
+ * field: string
3583
+ * }} cfg
3584
+ * @returns {boolean}
3585
+ */
3418
3586
  isPluginField ({namespace, field}) {
3419
3587
  return field.startsWith(`${namespace}-plugin-`);
3420
3588
  }
3589
+
3590
+ /**
3591
+ * @param {{
3592
+ * namespace: string,
3593
+ * field: string
3594
+ * }} cfg
3595
+ * @returns {[string, string|undefined, string|undefined]}
3596
+ */
3421
3597
  getPluginFieldParts ({namespace, field}) {
3422
3598
  field = field.replace(`${namespace}-plugin-`, '');
3423
3599
  let pluginName, applicableField, targetLanguage;
@@ -3426,20 +3602,64 @@ class PluginsForWork {
3426
3602
  } else {
3427
3603
  pluginName = field;
3428
3604
  }
3429
- return [pluginName, applicableField, targetLanguage].map(unescapePluginComponent);
3605
+ return /** @type {[string, string|undefined, string|undefined]} */ (
3606
+ [pluginName, applicableField, targetLanguage].map(unescapePluginComponent)
3607
+ );
3430
3608
  }
3431
3609
  }
3432
3610
 
3433
3611
  /* globals process -- Node polyglot */
3434
3612
 
3613
+ /**
3614
+ * @typedef {number} Integer
3615
+ */
3616
+ /**
3617
+ * @typedef {{
3618
+ * schema: {$ref: string},
3619
+ * metadata: {$ref: string},
3620
+ * data: (Integer|string)[]
3621
+ * }} WorkTableContainer
3622
+ */
3623
+
3624
+ /**
3625
+ * @typedef {{
3626
+ * file: {
3627
+ * $ref: string
3628
+ * },
3629
+ * schemaFile: string,
3630
+ * metadataFile: string,
3631
+ * name: string,
3632
+ * }} FileData
3633
+ */
3634
+
3635
+ /**
3636
+ * @typedef {{
3637
+ * files: FileData[],
3638
+ * baseDirectory?: string,
3639
+ * schemaBaseDirectory?: string,
3640
+ * metadataBaseDirectory?: string,
3641
+ * }} FileGroup
3642
+ */
3643
+
3644
+ /**
3645
+ * INCOMPLETE typing.
3646
+ * @typedef {{
3647
+ * groups: FileGroup[],
3648
+ * plugins: {[key: string]: {path: string}},
3649
+ * baseDirectory?: string,
3650
+ * schemaBaseDirectory?: string,
3651
+ * metadataBaseDirectory?: string,
3652
+ * }} FilesObject
3653
+ */
3654
+
3435
3655
  /**
3436
3656
  * Imported by the `dist/sw-helper.js`
3437
3657
  * @param {string} files The files.json file path
3438
- * @returns {PlainObject}
3658
+ * @returns {Promise<string[]>}
3439
3659
  */
3440
3660
  const getWorkFiles = async function getWorkFiles (files) {
3441
- const filesObj = await getJSON(files);
3442
- const dataFiles = [];
3661
+ const filesObj = /** @type {FilesObject} */ (await getJSON(files));
3662
+ const dataFiles = /** @type {string[]} */ ([]);
3443
3663
  filesObj.groups.forEach((fileGroup) => {
3444
3664
  fileGroup.files.forEach((fileData) => {
3445
3665
  const {file, schemaFile, metadataFile} =
@@ -3453,6 +3673,11 @@ const getWorkFiles = async function getWorkFiles (files) {
3453
3673
  return dataFiles;
3454
3674
  };
3455
3675
 
3676
+ /**
3677
+ * @param {FilesObject} filesObj
3678
+ * @param {FileGroup} fileGroup
3679
+ * @param {FileData} fileData
3680
+ */
3456
3681
  const getFilePaths = function getFilePaths (filesObj, fileGroup, fileData) {
3457
3682
  const baseDir = (filesObj.baseDirectory || '') + (fileGroup.baseDirectory || '') + '/';
3458
3683
  const schemaBaseDir = (filesObj.schemaBaseDirectory || '') +
@@ -3466,12 +3691,37 @@ const getFilePaths = function getFilePaths (filesObj, fileGroup, fileData) {
3466
3691
  return {file, schemaFile, metadataFile};
3467
3692
  };
3468
3693
 
3694
+ /**
3695
+ * @typedef {{
3696
+ * lang: string[],
3697
+ * fallbackLanguages: string[],
3698
+ * work: string,
3699
+ * files: string,
3700
+ * allowPlugins: boolean|undefined,
3701
+ * basePath: string,
3702
+ * languages: import('./Languages.js').Languages,
3703
+ * preferredLocale: string
3704
+ * }} GetWorkDataOptions
3705
+ */
3706
+
3707
+ /**
3708
+ * @param {GetWorkDataOptions} cfg
3709
+ */
3469
3710
  const getWorkData = async function ({
3470
3711
  lang, fallbackLanguages, work, files, allowPlugins, basePath,
3471
3712
  languages, preferredLocale
3472
3713
  }) {
3473
3714
  const filesObj = await getJSON(files);
3474
- const localizationStrings = filesObj['localization-strings'];
3715
+ const localizationStrings =
3716
+ /**
3717
+ * @type {{
3718
+ * "localization-strings": {
3719
+ * [key: string]: {}
3720
+ * }
3721
+ * }}
3722
+ */ (
3723
+ filesObj
3724
+ )?.['localization-strings'];
3475
3725
 
3476
3726
  const workI18n = await i18n({
3477
3727
  messageStyle: 'plainNested',