unicode-input-toolconverter 0.2.0 → 0.2.3

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 (143) hide show
  1. package/.nyc_output/out.json +8980 -1849
  2. package/CHANGES.md +15 -1
  3. package/README.md +6 -11
  4. package/_locales/en-US/messages.json +153 -6
  5. package/_locales/hu-HU/messages.json +153 -6
  6. package/_locales/pt-BR/messages.json +153 -6
  7. package/_locales/sv-SE/messages.json +153 -6
  8. package/babel.config.json +0 -1
  9. package/browser_action/characterSelection.js +18 -11
  10. package/browser_action/charrefConverters.js +286 -79
  11. package/browser_action/chartBuild.js +97 -27
  12. package/browser_action/encodingBehaviors.js +10 -7
  13. package/browser_action/entityBehaviors.js +42 -16
  14. package/browser_action/index-es.html +13 -1
  15. package/browser_action/index-instrumented.html +13 -1
  16. package/browser_action/index-pages.html +13 -1
  17. package/browser_action/index.html +13 -1
  18. package/browser_action/index.iife.min.js +9 -1
  19. package/browser_action/index.iife.min.js.map +1 -1
  20. package/browser_action/index.instrumented.iife.min.js +1 -1
  21. package/browser_action/index.instrumented.iife.min.js.map +1 -1
  22. package/browser_action/index.js +5 -5
  23. package/browser_action/preferences/prefDefaults.js +12 -3
  24. package/browser_action/service-worker/sw-activateCallback.js +1 -2
  25. package/browser_action/service-worker/sw-resources.json +6 -4
  26. package/browser_action/templateUtils/elements.js +12 -1
  27. package/browser_action/templateUtils/fill.js +6 -0
  28. package/browser_action/templateUtils/validation.js +4 -1
  29. package/browser_action/templates/chartBuild.js +167 -102
  30. package/browser_action/templates/index.js +227 -53
  31. package/browser_action/templatesElementCustomization/widgets.js +40 -15
  32. package/browser_action/unicode/UnicodeConverter.js +99 -73
  33. package/browser_action/unicode/charrefunicodeDb.js +100 -50
  34. package/browser_action/unicode/getScriptInfoForCodePoint.js +13 -4
  35. package/browser_action/unicode/hangul.js +27 -20
  36. package/browser_action/unicode/lastScriptNames.json +1 -1
  37. package/browser_action/unicode/parseUnihanFromTextFileStrings.js +44 -25
  38. package/browser_action/unicode/unicodeFieldInfo.js +112 -90
  39. package/browser_action/unicode/unicodeScripts.js +409 -35
  40. package/browser_action/unicode/unihan.js +4 -3
  41. package/browser_action/unicode/unihanDbPopulate.js +7 -2
  42. package/browser_action/unicode/unihanFields.js +34 -0
  43. package/browser_action/unicodecharref.js +353 -190
  44. package/browser_action/utils/DOMUtils.js +95 -34
  45. package/browser_action/utils/FetchUtils.js +7 -6
  46. package/browser_action/utils/TextUtils.js +4 -4
  47. package/browser_action/utils/TypedArrayUtils.js +9 -5
  48. package/browser_action/utils/semicolonSeparatedToArray.js +3 -3
  49. package/browser_action/utils/setupServiceWorker.js +2 -2
  50. package/eslint.config.js +11 -0
  51. package/icons/openWindow16.png +0 -0
  52. package/icons/openWindow24.png +0 -0
  53. package/lib/background.html +7 -0
  54. package/lib/background.js +2 -2
  55. package/package.json +80 -70
  56. package/pnpm-workspace.yaml +8 -0
  57. package/server.js +66 -51
  58. package/sw.js +97 -56
  59. package/tools/entities-import.js +4 -1
  60. package/tools/findEsResources.js +33 -10
  61. package/tools/fix-sw-resources-vendor-paths.js +60 -0
  62. package/tools/list-locales.js +2 -2
  63. package/tools/parseUnicodeCharts.js +126 -60
  64. package/tools/ucd-import.js +1 -10
  65. package/tools/unicode-charts.html +49 -20
  66. package/tools/unihan-import.js +45 -15
  67. package/tools/write-sw-version.js +16 -0
  68. package/tsconfig.json +23 -0
  69. package/typings/__coverage__.d.ts +5 -0
  70. package/typings/apple-system-profiler.d.ts +17 -0
  71. package/typings/commands.d.ts +19 -0
  72. package/typings/json-6.d.ts +4 -0
  73. package/typings/rollup-plugin-istanbul.d.ts +3 -0
  74. package/vendor/camelcase/index.d.ts +154 -0
  75. package/vendor/camelcase/index.js +137 -23
  76. package/vendor/fflate/esm/browser.d.ts +1539 -0
  77. package/vendor/fflate/esm/browser.js +82 -55
  78. package/vendor/intl-dom/dist/Formatter.d.ts +120 -0
  79. package/vendor/intl-dom/dist/Formatter.d.ts.map +1 -0
  80. package/vendor/intl-dom/dist/collation.d.ts +42 -0
  81. package/vendor/intl-dom/dist/collation.d.ts.map +1 -0
  82. package/vendor/intl-dom/dist/defaultAllSubstitutions.d.ts +52 -0
  83. package/vendor/intl-dom/dist/defaultAllSubstitutions.d.ts.map +1 -0
  84. package/vendor/intl-dom/dist/defaultInsertNodes.d.ts +96 -0
  85. package/vendor/intl-dom/dist/defaultInsertNodes.d.ts.map +1 -0
  86. package/vendor/intl-dom/dist/defaultKeyCheckerConverter.d.ts +17 -0
  87. package/vendor/intl-dom/dist/defaultKeyCheckerConverter.d.ts.map +1 -0
  88. package/vendor/intl-dom/dist/defaultLocaleResolver.d.ts +285 -0
  89. package/vendor/intl-dom/dist/defaultLocaleResolver.d.ts.map +1 -0
  90. package/vendor/intl-dom/dist/findLocaleStrings.d.ts +88 -0
  91. package/vendor/intl-dom/dist/findLocaleStrings.d.ts.map +1 -0
  92. package/vendor/intl-dom/dist/getDOMForLocaleString.d.ts +67 -0
  93. package/vendor/intl-dom/dist/getDOMForLocaleString.d.ts.map +1 -0
  94. package/vendor/intl-dom/dist/getMessageForKeyByStyle.d.ts +73 -0
  95. package/vendor/intl-dom/dist/getMessageForKeyByStyle.d.ts.map +1 -0
  96. package/vendor/intl-dom/dist/getStringFromMessageAndDefaults.d.ts +26 -0
  97. package/vendor/intl-dom/dist/getStringFromMessageAndDefaults.d.ts.map +1 -0
  98. package/vendor/intl-dom/dist/i18n.d.ts +113 -0
  99. package/vendor/intl-dom/dist/i18n.d.ts.map +1 -0
  100. package/vendor/intl-dom/dist/index.d.ts +92 -0
  101. package/vendor/intl-dom/dist/index.d.ts.map +1 -0
  102. package/vendor/intl-dom/dist/index.esm.d.ts +34 -0
  103. package/vendor/intl-dom/dist/index.esm.js +854 -896
  104. package/vendor/intl-dom/dist/index.esm.min.js +4 -0
  105. package/vendor/intl-dom/dist/index.esm.min.js.map +1 -0
  106. package/vendor/intl-dom/dist/index.umd.js +2953 -0
  107. package/vendor/intl-dom/dist/index.umd.min.js +4 -0
  108. package/vendor/intl-dom/dist/index.umd.min.js.map +1 -0
  109. package/vendor/intl-dom/dist/promiseChainForValues.d.ts +34 -0
  110. package/vendor/intl-dom/dist/promiseChainForValues.d.ts.map +1 -0
  111. package/vendor/intl-dom/dist/shared.d.ts +20 -0
  112. package/vendor/intl-dom/dist/shared.d.ts.map +1 -0
  113. package/vendor/intl-dom/dist/utils.d.ts +53 -0
  114. package/vendor/intl-dom/dist/utils.d.ts.map +1 -0
  115. package/vendor/jamilih/dist/jml.d.mts +468 -0
  116. package/vendor/jamilih/dist/{jml-es.js → jml.mjs} +1489 -343
  117. package/vendor/jquery/dist/jquery.js +1677 -2713
  118. package/vendor/json-6/dist/index.mjs +2 -0
  119. package/vendor/miller-columns/CHANGES.md +185 -0
  120. package/vendor/miller-columns/LICENSE-MIT.txt +21 -0
  121. package/vendor/miller-columns/README.md +249 -0
  122. package/vendor/miller-columns/demos/index.html +69 -0
  123. package/vendor/miller-columns/demos/index.js +72 -0
  124. package/vendor/miller-columns/dist/index-es.js +748 -0
  125. package/vendor/miller-columns/dist/index-es.min.d.ts +25 -0
  126. package/vendor/miller-columns/dist/index-es.min.js +7 -1
  127. package/vendor/miller-columns/dist/index-umd.js +757 -0
  128. package/vendor/miller-columns/dist/index-umd.min.js +7 -0
  129. package/vendor/miller-columns/dist/index.d.ts +25 -0
  130. package/vendor/miller-columns/dist/millerColumns.d.ts +10 -0
  131. package/vendor/miller-columns/eslint.config.js +46 -0
  132. package/vendor/miller-columns/fix-declarations.js +18 -0
  133. package/vendor/miller-columns/miller-columns.css +24 -1
  134. package/vendor/miller-columns/package.json +73 -0
  135. package/vendor/miller-columns/pnpm-workspace.yaml +2 -0
  136. package/vendor/miller-columns/src/index.js +642 -0
  137. package/vendor/miller-columns/src/millerColumns.ts +12 -0
  138. package/vendor/miller-columns/tsconfig-prod.json +23 -0
  139. package/vendor/miller-columns/tsconfig.json +21 -0
  140. package/vendor/simple-prefs/dist/index.esm.d.ts +1 -0
  141. package/vendor/simple-prefs/dist/index.esm.js +164 -216
  142. package/vendor/simple-prefs/dist/simple-prefs.d.ts +117 -0
  143. package/lgtm.yml +0 -5
@@ -1,5 +1,5 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
3
 
4
4
  // eslint-disable-next-line no-shadow -- Remove?
5
5
  import fetch from 'node-fetch';
@@ -18,8 +18,8 @@ const {JSDOM} = jsdom;
18
18
  function getChromeSafeLocaleKey (key) {
19
19
  return key.replaceAll(
20
20
  String.raw`\n`, ''
21
- ).replaceAll(/\s+/gu, ' '). // Getting some extra WS
22
- replaceAll(/\W/gu, '_');
21
+ ).replaceAll(/\s+/gv, ' '). // Getting some extra WS
22
+ replaceAll(/\W/gv, '_');
23
23
  }
24
24
 
25
25
  let text;
@@ -47,23 +47,38 @@ const uniqueTextPlaceholder = localize
47
47
  ? '___placeholder___'
48
48
  : ''; // We know it is not present inside Unicode script names!
49
49
 
50
+ /**
51
+ * @param {string} txt
52
+ */
50
53
  const cleanupText = (txt) => {
51
54
  return txt.trim().
52
- replace(/(?<initWS>\s)\s+/u, '$<initWS>').
53
- replace(/\s*\((?:ASCII|Odia)\)$/u, '').
54
- replace(/\s\(\d\.?\d*MB\)$/u, ''); // Remove MB size
55
+ replace(/(?<initWS>\s)\s+/v, '$<initWS>').
56
+ replace(/\s*\((?:ASCII|Odia)\)$/v, '').
57
+ replace(/\s\(\d\.?\d*MB\)$/v, ''); // Remove MB size
55
58
  };
56
59
 
60
+ /**
61
+ * @type {{
62
+ * script: string,
63
+ * startRange: string
64
+ * }[]}
65
+ */
57
66
  const scriptsAndStartRanges = [];
58
67
 
59
68
  const jamilih = scriptMaps.map((scriptMap) => {
60
69
  const majorHeading = cleanupText(
61
- scriptMap.previousElementSibling.textContent
70
+ /** @type {HTMLElement} */
71
+ (scriptMap.previousElementSibling).textContent
62
72
  );
63
73
  // const scriptGroups = [...scriptMap.querySelectorAll('table td p')];
64
74
 
65
- const scriptGroups = [...scriptMap.querySelectorAll('table td p.sg')];
75
+ // Note: as of the Unicode 18.0 charts redesign, `p.sg` sits directly in
76
+ // `table.map`'s own `td` (no more nested `table`), so this must not
77
+ // require an extra `table` ancestor or it silently matches nothing.
78
+ const scriptGroups = [...scriptMap.querySelectorAll(':scope td p.sg')];
66
79
  // sg, mb, pb/sb
80
+
81
+ /** @type {import('jamilih/dist/jml.js').JamilihChildren|null} */
67
82
  let lastChildren;
68
83
  return ['li', [
69
84
  majorHeading,
@@ -87,11 +102,12 @@ const jamilih = scriptMaps.map((scriptMap) => {
87
102
  );
88
103
  } else if (scriptGroup.matches('.pb,.sb')) {
89
104
  cleanedText = cleanupText(scriptGroup.textContent);
90
- const children = [
105
+ // eslint-disable-next-line @stylistic/max-len -- Long
106
+ const children = /** @type {import('jamilih/dist/jml.js').JamilihChildren} */ ([
91
107
  ['i', [
92
108
  uniqueTextPlaceholder + cleanedText
93
109
  ]]
94
- ];
110
+ ]);
95
111
  if (!lastChildren) { // A few rare cases to handle, e.g., "Other"
96
112
  lists.push(
97
113
  ['li', {title}, children]
@@ -100,18 +116,27 @@ const jamilih = scriptMaps.map((scriptMap) => {
100
116
  if (!lastChildren[1]) {
101
117
  lastChildren[1] = ['ul', []];
102
118
  }
103
- lastChildren[1][1].push(
119
+ /** @type {import('jamilih/dist/jml.js').JamilihChildren} */ (
120
+ /** @type {import('jamilih/dist/jml.js').JamilihArray} */
121
+ (lastChildren[1])[1]
122
+ ).push(
104
123
  ['li', {title}, children]
105
124
  );
106
125
  }
107
126
  }
108
127
  if (cleanedText && title) {
128
+ // Range separators are inconsistent across entries: some use
129
+ // a plain hyphen, others an en dash (U+2013).
109
130
  scriptsAndStartRanges.push({
110
131
  script: getChromeSafeLocaleKey(cleanedText),
111
- startRange: title.replace(/-.*$/u, '')
132
+ startRange: title.replace(/[\-–].*$/v, '')
112
133
  });
113
134
  }
114
- scriptGroup = scriptGroup.nextElementSibling;
135
+
136
+ // May actually be `null` too, but next condition will catch
137
+ scriptGroup = /** @type {HTMLElement} */ (
138
+ scriptGroup.nextElementSibling
139
+ );
115
140
  } while (scriptGroup && !scriptGroup.matches('p.sg'));
116
141
  lastChildren = null;
117
142
  if (!lists.length) { // Just be safe
@@ -126,14 +151,15 @@ const jamilih = scriptMaps.map((scriptMap) => {
126
151
  // console.log('m', majorHeading, scriptGroups);
127
152
 
128
153
  /**
129
- * @typedef {JSON} LocaleFileContents
130
- * @todo Indicate more precise format
131
- */
154
+ * @typedef {{
155
+ * body: Record<string, {message: string, description?: string}>
156
+ * }} LocaleFileContents
157
+ */
132
158
 
133
159
  /**
134
160
  * @param {string[]} localeFiles
135
- * @param {LocaleFileContents} localeFileContents
136
- * @returns {Promise<void>}
161
+ * @param {LocaleFileContents[]} localeFileContents
162
+ * @returns {Promise<void[]>}
137
163
  */
138
164
  async function saveLocalesWithoutDupes (localeFiles, localeFileContents) {
139
165
  return await Promise.all(
@@ -147,13 +173,40 @@ async function saveLocalesWithoutDupes (localeFiles, localeFileContents) {
147
173
 
148
174
  /**
149
175
  * @param {string[]} newScriptNames
150
- * @param {LocaleFileContents} localeFileContents
176
+ * @param {LocaleFileContents[]} localeFileContents
151
177
  * @returns {Promise<void>}
152
178
  */
153
179
  async function deleteUnusedScriptNames (newScriptNames, localeFileContents) {
154
- const {lastScriptNames} = JSON.parse(
180
+ // eslint-disable-next-line prefer-destructuring -- TS
181
+ const lastScriptNames = /** @type {string[]} */ (JSON.parse(
155
182
  await fs.readFile(lastScriptNamesFile, 'utf8')
156
- );
183
+ ).lastScriptNames);
184
+
185
+ // Safety guard: a parsing failure (e.g., unicode.org restructuring the
186
+ // charts page, as happened for the Unicode 18.0 redesign, breaking the
187
+ // `scriptGroups` selector above) can silently yield few or no
188
+ // `newScriptNames`. Without this check, every "missing" script name
189
+ // would look "removed from the standard" and get deleted from every
190
+ // locale file. Script counts barely change between Unicode versions,
191
+ // so a drop this large almost certainly means parsing broke, not that
192
+ // the scripts really vanished.
193
+ const survivingCount = lastScriptNames.filter(
194
+ (lastScriptName) => newScriptNames.includes(lastScriptName)
195
+ ).length;
196
+ const survivalRatio = lastScriptNames.length > 0
197
+ ? survivingCount / lastScriptNames.length
198
+ : 1;
199
+ if (survivalRatio < 0.5) {
200
+ throw new Error(
201
+ `Refusing to update: only ${survivingCount} of ` +
202
+ `${lastScriptNames.length} previously known script names were found ` +
203
+ `in this run (parsed ${newScriptNames.length} total). This usually ` +
204
+ 'means the unicode.org charts page structure changed and the ' +
205
+ 'scraper needs fixing, not that the scripts were actually removed ' +
206
+ 'from the standard. No files were written.'
207
+ );
208
+ }
209
+
157
210
  lastScriptNames.forEach((lastScriptName) => {
158
211
  if (!newScriptNames.includes(lastScriptName)) {
159
212
  localeFileContents.forEach((lfc) => {
@@ -171,6 +224,9 @@ await fs.writeFile(
171
224
  // Do not edit this file; this is an auto-generated file used to
172
225
  // build a hierarchy of script names. It is built by
173
226
  // \`parseUnicodeCharts.js\` using ${chartsURL}.
227
+ /**
228
+ * @param {import('intl-dom').I18NCallback} _
229
+ */
174
230
  function unicodeScripts (_) {
175
231
  return ` + (localize
176
232
  ? await (async () => {
@@ -181,34 +237,38 @@ function unicodeScripts (_) {
181
237
  const localeFiles = dirs.map(
182
238
  (dir) => path.join(localesDir, dir, 'messages.json')
183
239
  );
184
- const localeFileContents = (
240
+ const localeFileContents = /** @type {LocaleFileContents[]} */ ((
185
241
  await Promise.all(localeFiles.map((localeFile) => {
186
242
  return fs.readFile(localeFile, 'utf8');
187
243
  }))
188
244
  ).map((fileContents) => {
189
245
  return JSON.parse(fileContents);
190
- });
246
+ }));
191
247
 
192
- const dirResults = (
248
+ const dirResults = /** @type {{path: string, keys: string[]}[]} */ (
193
249
  await recurseDirectory({directory: 'browser_action'})
194
250
  ).filter(({keys}) => {
195
251
  return keys.length;
196
252
  });
197
253
  // console.log('dirResults', JSON.stringify(dirResults, null, 2));
254
+
255
+ /** @type {Record<string, {paths: string[], locales: string[]}>} */
198
256
  const keyMap = {};
199
257
  dirResults.forEach(({path: pth, keys}) => {
200
258
  keys.forEach((key) => {
201
259
  localeFileContents.forEach((lfc, i) => {
202
- if (!(key in lfc.body)) {
203
- if (!keyMap[key]) {
204
- keyMap[key] = {paths: [], locales: []};
205
- }
206
- if (!keyMap[key].paths.includes(pth)) {
207
- keyMap[key].paths.push(pth);
208
- }
209
- if (!keyMap[key].locales.includes(localeFiles[i])) {
210
- keyMap[key].locales.push(localeFiles[i]);
211
- }
260
+ if (Object.hasOwn(lfc.body, key)) {
261
+ return;
262
+ }
263
+
264
+ if (!Object.hasOwn(keyMap, key)) {
265
+ keyMap[key] = {paths: [], locales: []};
266
+ }
267
+ if (!keyMap[key].paths.includes(pth)) {
268
+ keyMap[key].paths.push(pth);
269
+ }
270
+ if (!keyMap[key].locales.includes(localeFiles[i])) {
271
+ keyMap[key].locales.push(localeFiles[i]);
212
272
  }
213
273
  });
214
274
  });
@@ -229,12 +289,12 @@ function unicodeScripts (_) {
229
289
  return;
230
290
  }
231
291
  Object.keys(lfc.body).forEach((localeKey) => {
232
- if (!dirResults.some(({
292
+ if (dirResults.every(({
233
293
  keys
234
294
  // path: pth
235
295
  }) => {
236
296
  // console.log('keys', keys);
237
- return keys.includes(localeKey);
297
+ return !keys.includes(localeKey);
238
298
  })) {
239
299
  // Working:
240
300
  // console.log(`Locale key "${localeKey}" not present in keys
@@ -243,11 +303,12 @@ function unicodeScripts (_) {
243
303
  });
244
304
  });
245
305
 
306
+ /** @type {string[]} */
246
307
  const newScriptNames = [];
247
308
  const ret = JSON.stringify(['ul', jamilih], null, 2).replaceAll(
248
309
  new RegExp(
249
310
  String.raw`^(\s*)"` + uniqueTextPlaceholder + '(.*)"(,)?$',
250
- 'gum'
311
+ 'gvm'
251
312
  ),
252
313
  (_, initialWS, key, possibleComma = '') => {
253
314
  const chromeSafeLocaleKey = getChromeSafeLocaleKey(key);
@@ -273,7 +334,7 @@ function unicodeScripts (_) {
273
334
  if (lfc.body.langCode.message !== 'hu-HU') {
274
335
  // return;
275
336
  }
276
- if (!(chromeSafeLocaleKey in lfc.body)) {
337
+ if (!Object.hasOwn(lfc.body, chromeSafeLocaleKey)) {
277
338
  lfc.body[chromeSafeLocaleKey] = {
278
339
  message: key
279
340
  };
@@ -335,29 +396,29 @@ scriptsAndStartRanges.forEach(({script, startRange}) => {
335
396
  } else if (num < 0x${startRange}) {
336
397
  codePointStart = '${lastStartRange}';
337
398
  script = _('${lastScript}');${
338
- // Not in chart:
339
- // startRange === 'DB80' ? "surrogate = _('High_Private_Use_Surrogate')" :
340
- lastStartRange === 'D800'
341
- ? `
399
+ // Not in chart:
400
+ // startRange === 'DB80' ? "surrogate = _('High_Private_Use_Surrogate')" :
401
+ lastStartRange === 'D800'
402
+ ? `
342
403
  surrogate = _('High_Surrogate');`
343
- : lastStartRange === 'DC00'
344
- ? `
404
+ : lastStartRange === 'DC00'
405
+ ? `
345
406
  surrogate = _('Low_Surrogate');`
346
- : ['E000', 'F0000', '100000'].includes(lastStartRange)
347
- ? `
407
+ : ['E000', 'F0000', '100000'].includes(lastStartRange)
408
+ ? `
348
409
  privateuse = true;`
349
- : ''
350
- }`;
410
+ : ''
411
+ }`;
351
412
  lastStartRange = startRange;
352
413
  lastScript = script;
353
414
  });
354
415
 
355
416
  /**
356
- * @param {PlainObject} cfg
417
+ * @param {object} cfg
357
418
  * @param {string} cfg.directory
358
419
  * @param {string} [cfg.basePath]
359
- * @param {{path, keys}} cfg.results
360
- * @returns {Promise<{path, keys}|void>}
420
+ * @param {{path: string, keys: string[]}[]} [cfg.results]
421
+ * @returns {Promise<{path: string, keys: string[]}[]|void>}
361
422
  */
362
423
  async function recurseDirectory ({directory, basePath = './', results}) {
363
424
  const dirPath = path.join(basePath, directory);
@@ -370,26 +431,31 @@ async function recurseDirectory ({directory, basePath = './', results}) {
370
431
  await Promise.all(
371
432
  filesAndDirs.filter((fileOrDir) => {
372
433
  // Is a directory or JavaScript file
373
- return !fileOrDir.includes('.') || (/\.js$/u).test(fileOrDir);
434
+ return !fileOrDir.includes('.') || (/\.js$/v).test(fileOrDir);
374
435
  }).map(async (fileOrDir) => {
375
436
  if (!fileOrDir.includes('.')) { // Should check `isDirectory()` or such
376
- return recurseDirectory({
377
- directory: fileOrDir,
378
- basePath: dirPath,
379
- results
380
- });
437
+ return /** @type {Promise<{path: string, keys: string[]}[]>} */ (
438
+ recurseDirectory({
439
+ directory: fileOrDir,
440
+ basePath: dirPath,
441
+ results
442
+ })
443
+ );
381
444
  }
382
445
  const pth = path.join(dirPath, fileOrDir);
383
446
  const contents = await fs.readFile(pth, 'utf8');
384
447
 
385
448
  const i18nRegex = // /_\((?:['"]([^'"]*)['"])\)/g;
386
449
  // Todo: Works to find variable forms:
387
- /_\((?:['"](?<key1>[^'"]*)['"]|(?<key2>[^"')][^{)]*|[^{)]*[^"')]))\)/gu;
450
+ /_\((?:['"](?<key1>[^'"]*)['"]|(?<key2>[^"'\)][^\{\)]*|[^\{\)]*[^"'\)]))\)/gv;
388
451
 
452
+ /** @type {string[]} */
389
453
  const keys = [];
390
454
  let result;
391
455
  while ((result = (i18nRegex.exec(contents))) !== null) {
392
- keys.push(result.groups.key1 || result.groups.key2);
456
+ keys.push(/** @type {{key1: string}} */ (
457
+ result.groups
458
+ ).key1 || /** @type {{key2: string}} */ (result.groups).key2);
393
459
  }
394
460
  results.push({path: pth, keys});
395
461
  return undefined;
@@ -2,23 +2,14 @@
2
2
  // this file for the browser, but we're keeping this file for demonstrating
3
3
  // an approach for live-obtaining the live version.
4
4
 
5
- import fs from 'fs/promises';
6
-
7
5
  import download from 'download';
8
- import extract from 'extract-zip';
9
6
 
10
7
  const args = process.argv.slice(2);
11
8
 
12
9
  const targetDir = `${process.cwd()}/download/UCD`;
13
- const ucdZip = `${targetDir}/UCD.zip`;
14
10
 
15
11
  if (args.includes('download')) {
16
12
  await download(
17
- 'https://www.unicode.org/Public/UCD/latest/ucd/UCD.zip', targetDir
13
+ 'https://www.unicode.org/Public/UCD/latest/ucd/UCD.zip', targetDir, {extract: true}
18
14
  );
19
15
  }
20
-
21
- if (args.includes('extract') || args.includes('download')) {
22
- await extract(ucdZip, {dir: targetDir});
23
- await fs.unlink(ucdZip);
24
- }