tiny-essentials 1.29.1 → 1.29.2

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 (128) hide show
  1. package/changelog/1/29/2.md +82 -0
  2. package/dist/v1/TinyBasicsEs.min.js +1 -1
  3. package/dist/v1/TinyEssentials.min.js +1 -1
  4. package/dist/v1/TinyFetchLoader.min.js +1 -0
  5. package/dist/v1/TinyImageLoader.min.js +1 -0
  6. package/dist/v1/TinyMediaCache.min.js +1 -0
  7. package/dist/v1/TinyMediaLoader.min.js +1 -0
  8. package/dist/v1/basics/index.cjs +5 -0
  9. package/dist/v1/basics/index.d.mts +2 -1
  10. package/dist/v1/basics/index.d.mts.map +1 -1
  11. package/dist/v1/basics/index.mjs +2 -1
  12. package/dist/v1/basics/media/youtube.cjs +275 -0
  13. package/dist/v1/basics/media/youtube.d.mts +107 -0
  14. package/dist/v1/basics/media/youtube.d.mts.map +1 -0
  15. package/dist/v1/basics/media/youtube.mjs +214 -0
  16. package/dist/v1/index.cjs +13 -0
  17. package/dist/v1/index.d.mts +6 -1
  18. package/dist/v1/index.d.mts.map +1 -1
  19. package/dist/v1/index.mjs +7 -2
  20. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.cjs +0 -1
  21. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.d.mts +0 -1
  22. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.d.mts.map +1 -1
  23. package/dist/v1/libs/fs/plugins/OPFS/StorageBucket.mjs +0 -1
  24. package/dist/v1/libs/fs/plugins/OPFS/index.cjs +0 -8
  25. package/dist/v1/libs/fs/plugins/OPFS/index.d.mts +0 -8
  26. package/dist/v1/libs/fs/plugins/OPFS/index.d.mts.map +1 -1
  27. package/dist/v1/libs/fs/plugins/OPFS/index.mjs +0 -8
  28. package/dist/v1/libs/html/TinyHtml.cjs +1 -1
  29. package/dist/v1/libs/html/TinyHtml.d.mts +2 -2
  30. package/dist/v1/libs/html/TinyHtml.d.mts.map +1 -1
  31. package/dist/v1/libs/html/TinyHtml.mjs +1 -1
  32. package/dist/v1/libs/html/loader/TinyMediaLoader.cjs +1999 -0
  33. package/dist/v1/libs/html/loader/TinyMediaLoader.d.mts +999 -0
  34. package/dist/v1/libs/html/loader/TinyMediaLoader.d.mts.map +1 -0
  35. package/dist/v1/libs/html/loader/TinyMediaLoader.mjs +1852 -0
  36. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.cjs +77 -0
  37. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.d.mts +103 -0
  38. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.d.mts.map +1 -0
  39. package/dist/v1/libs/html/loader/beta/formats/TinyAudioLoader.mjs +67 -0
  40. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.cjs +630 -0
  41. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.d.mts +138 -0
  42. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.d.mts.map +1 -0
  43. package/dist/v1/libs/html/loader/beta/formats/TinyContentLoader.mjs +576 -0
  44. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.cjs +70 -0
  45. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.d.mts +100 -0
  46. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.d.mts.map +1 -0
  47. package/dist/v1/libs/html/loader/beta/formats/TinyVideoLoader.mjs +60 -0
  48. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.cjs +946 -0
  49. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.d.mts +67 -0
  50. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.d.mts.map +1 -0
  51. package/dist/v1/libs/html/loader/beta/probe/TinyMediaProbe.mjs +896 -0
  52. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.cjs +225 -0
  53. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.d.mts +149 -0
  54. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.d.mts.map +1 -0
  55. package/dist/v1/libs/html/loader/formats/TinyFetchLoader.mjs +197 -0
  56. package/dist/v1/libs/html/loader/formats/TinyImageLoader.cjs +1454 -0
  57. package/dist/v1/libs/html/loader/formats/TinyImageLoader.d.mts +200 -0
  58. package/dist/v1/libs/html/loader/formats/TinyImageLoader.d.mts.map +1 -0
  59. package/dist/v1/libs/html/loader/formats/TinyImageLoader.mjs +1317 -0
  60. package/dist/v1/libs/html/loader/probe/TinyImageProbe.cjs +668 -0
  61. package/dist/v1/libs/html/loader/probe/TinyImageProbe.d.mts +83 -0
  62. package/dist/v1/libs/html/loader/probe/TinyImageProbe.d.mts.map +1 -0
  63. package/dist/v1/libs/html/loader/probe/TinyImageProbe.mjs +626 -0
  64. package/dist/v1/libs/html/loader/utils/TinyBufferReader.cjs +277 -0
  65. package/dist/v1/libs/html/loader/utils/TinyBufferReader.d.mts +118 -0
  66. package/dist/v1/libs/html/loader/utils/TinyBufferReader.d.mts.map +1 -0
  67. package/dist/v1/libs/html/loader/utils/TinyBufferReader.mjs +247 -0
  68. package/dist/v1/libs/html/loader/utils/TinyIsoBox.cjs +128 -0
  69. package/dist/v1/libs/html/loader/utils/TinyIsoBox.d.mts +49 -0
  70. package/dist/v1/libs/html/loader/utils/TinyIsoBox.d.mts.map +1 -0
  71. package/dist/v1/libs/html/loader/utils/TinyIsoBox.mjs +116 -0
  72. package/dist/v1/libs/html/loader/utils/TinyMediaCache.cjs +796 -0
  73. package/dist/v1/libs/html/loader/utils/TinyMediaCache.d.mts +354 -0
  74. package/dist/v1/libs/html/loader/utils/TinyMediaCache.d.mts.map +1 -0
  75. package/dist/v1/libs/html/loader/utils/TinyMediaCache.mjs +734 -0
  76. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.cjs +302 -0
  77. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.d.mts +256 -0
  78. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.d.mts.map +1 -0
  79. package/dist/v1/libs/html/loader/utils/TinyMediaMirror.mjs +280 -0
  80. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.cjs +194 -0
  81. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.d.mts +138 -0
  82. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.d.mts.map +1 -0
  83. package/dist/v1/libs/html/loader/utils/TinyMediaProgress.mjs +175 -0
  84. package/dist/v1/libs/tools/TinyPkgExportValidator.cjs +359 -55
  85. package/dist/v1/libs/tools/TinyPkgExportValidator.d.mts +64 -6
  86. package/dist/v1/libs/tools/TinyPkgExportValidator.d.mts.map +1 -1
  87. package/dist/v1/libs/tools/TinyPkgExportValidator.mjs +320 -57
  88. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.cjs +0 -1
  89. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.d.mts +0 -1
  90. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.d.mts.map +1 -1
  91. package/dist/v1/libs/worker/engine/TinyWebWorkerEngine.mjs +0 -1
  92. package/dist/v1/webTemplates/bootstrap/5.3/scss/background/_background-grid.scss +15 -0
  93. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/buttons/_buttons-contrast.scss +208 -0
  94. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/buttons/_buttons-ghost.scss +89 -0
  95. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/icon/_cube-icon.scss +65 -0
  96. package/dist/v1/webTemplates/bootstrap/5.3/scss/components/icon/_sphere-pulse.scss +39 -0
  97. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_badges.scss +90 -0
  98. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_bootstrap-overrides.scss +495 -0
  99. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_buttons.scss +390 -0
  100. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_colors.scss +213 -0
  101. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_effects.scss +153 -0
  102. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_forms-tones.scss +69 -0
  103. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_forms.scss +323 -0
  104. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_global.scss +31 -0
  105. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_links.scss +47 -0
  106. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_tables.scss +25 -0
  107. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_theme.scss +21 -0
  108. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_tokens.scss +161 -0
  109. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_utilities.scss +81 -0
  110. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/_variables.scss +63 -0
  111. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_form-tone-mixins.scss +236 -0
  112. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_sizing.scss +68 -0
  113. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_tone-mixins.scss +392 -0
  114. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/_typography.scss +112 -0
  115. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/background/_tiny_gradient_1.scss +131 -0
  116. package/dist/v1/webTemplates/bootstrap/5.3/scss/themes/deepstrap/plugins/colors/_pink.scss +47 -0
  117. package/docs/v1/Exports.md +33 -2
  118. package/docs/v1/README.md +9 -0
  119. package/docs/v1/basics/youtube.md +204 -0
  120. package/docs/v1/libs/html/loader/TinyFetchLoader.md +114 -0
  121. package/docs/v1/libs/html/loader/TinyImageLoader.md +141 -0
  122. package/docs/v1/libs/html/loader/TinyMediaCache.md +166 -0
  123. package/docs/v1/libs/html/loader/TinyMediaLoader.md +300 -0
  124. package/docs/v1/libs/tools/TinyPkgExportValidator.md +55 -0
  125. package/docs/v1/webTemplates/bootstrap/5.3/DeepStrap.md +177 -0
  126. package/package.json +244 -8
  127. /package/dist/v1/webTemplates/bootstrap/5.3/scss/input/{Placeholder-Colors-Fix.scss → _placeholder-colors-fix.scss} +0 -0
  128. /package/dist/v1/webTemplates/bootstrap/5.3/scss/spacing/{Spacing-Plus.scss → _spacing-plus.scss} +0 -0
@@ -1,4 +1,4 @@
1
- import { access, readFile } from 'fs/promises';
1
+ import { readFile, readdir, stat } from 'fs/promises';
2
2
  import { resolve } from 'path';
3
3
  /**
4
4
  * @typedef {Object} ConsoleColors - The color configuration object.
@@ -18,17 +18,44 @@ import { resolve } from 'path';
18
18
  /**
19
19
  * @typedef {Object} DefaultMessages
20
20
  * @property {string} header
21
- * @property {string} divider
22
- * @property {string} itemValid
23
- * @property {string} itemInvalid
24
- * @property {string} itemMissing
25
- * @property {string} successHeader
26
- * @property {string} failureHeader
27
- * @property {string} errorLoad
28
- * @property {string} noExports
29
- * @property {string} errorNotFound
30
- * @property {string} errorParse
31
- * @property {string} errorUnexpected
21
+ * @property {string} divider
22
+ * @property {string} itemValid
23
+ * @property {string} itemInvalid
24
+ * @property {string} itemMissing
25
+ * @property {string} itemSkipped
26
+ * @property {string} itemPattern
27
+ * @property {string} itemInvalidTarget
28
+ * @property {string} successHeader
29
+ * @property {string} failureHeader
30
+ * @property {string} errorLoad
31
+ * @property {string} noExports
32
+ * @property {string} errorNotFound
33
+ * @property {string} errorParse
34
+ * @property {string} errorUnexpected
35
+ */
36
+ /**
37
+ * @typedef {Object} LogContext
38
+ * @property {string} [projectName] - The project name injected automatically.
39
+ * @property {string} [path] - The dotted context path of the export.
40
+ * @property {string} [errorPath] - The raw target string from package.json.
41
+ * @property {string} [target] - The invalid target value.
42
+ * @property {string} [reason] - The machine-readable failure reason.
43
+ * @property {string} [pattern] - The wildcard pattern that matched.
44
+ * @property {string} [message] - A generic message payload.
45
+ * @property {number} [errorCount] - The number of failures found.
46
+ */
47
+ /**
48
+ * The kind of target that was validated.
49
+ * @typedef {'file'|'pattern'|'null'|'invalid'} ExportTargetKind
50
+ */
51
+ /**
52
+ * The validation result of a single export target.
53
+ * @typedef {Object} ExportTargetResult
54
+ * @property {string} path - The dotted context path (e.g. "exports -> . -> import").
55
+ * @property {boolean} valid - Whether the target resolves to an existing file.
56
+ * @property {ExportTargetKind} [kind] - The kind of target that was validated.
57
+ * @property {string} [errorPath] - The raw target string declared in package.json.
58
+ * @property {string} [reason] - A short machine-readable reason code for failures.
32
59
  */
33
60
  /**
34
61
  * Default messages used when no custom messages are provided.
@@ -41,6 +68,9 @@ const DEFAULT_MESSAGES = {
41
68
  itemValid: ` [✔] {path}`,
42
69
  itemInvalid: ` [✘] {path}`,
43
70
  itemMissing: ` Missing: {errorPath}`,
71
+ itemSkipped: ` [-] {path} (excluded by null target)`,
72
+ itemPattern: ` [✔] {path} (pattern: {pattern})`,
73
+ itemInvalidTarget: ` Invalid target: {target} ({reason})`,
44
74
  successHeader: `SUCCESS: All exports are correctly mapped.`,
45
75
  failureHeader: `FAILURE: {errorCount} export(s) are missing or invalid.`,
46
76
  errorLoad: `Error: package.json not loaded in the current directory.`,
@@ -93,9 +123,9 @@ class TinyPkgExportValidator {
93
123
  throw new TypeError('The new configuration must contain the exact same keys as the original color set.');
94
124
  }
95
125
  // 3. Validate that all values are strings
126
+ const colorRecord = /** @type {Record<string, string>} */ (newColors);
96
127
  for (const key of originalKeys) {
97
- // @ts-ignore
98
- if (typeof newColors[key] !== 'string') {
128
+ if (typeof colorRecord[key] !== 'string') {
99
129
  throw new TypeError(`The value for key "${key}" must be a string.`);
100
130
  }
101
131
  }
@@ -109,7 +139,7 @@ class TinyPkgExportValidator {
109
139
  #packageJsonPath;
110
140
  /** @type {string} */
111
141
  #rootDir;
112
- /** @type {Array<{path: string, valid: boolean, errorPath?: string}>} */
142
+ /** @type {ExportTargetResult[]} */
113
143
  #results;
114
144
  /** @type {boolean} */
115
145
  #started = false;
@@ -191,9 +221,9 @@ class TinyPkgExportValidator {
191
221
  throw new TypeError('The "options.messages" property must be a non-null object.');
192
222
  }
193
223
  // Ensure all required keys from DefaultMessages are present and are strings
224
+ const messages = /** @type {Record<string, unknown>} */ (options.messages);
194
225
  for (const key of MESSAGE_KEYS) {
195
- // @ts-ignore
196
- if (typeof options.messages[key] !== 'string') {
226
+ if (typeof messages[key] !== 'string') {
197
227
  throw new TypeError(`The "options.messages.${key}" property must be a string.`);
198
228
  }
199
229
  }
@@ -201,8 +231,9 @@ class TinyPkgExportValidator {
201
231
  }
202
232
  /**
203
233
  * Internal helper to apply template replacements.
234
+ *
204
235
  * @param {string} template - The message template string.
205
- * @param {Object} context - Data for placeholders.
236
+ * @param {LogContext} context - Data for placeholders.
206
237
  * @returns {string} The processed string.
207
238
  * @throws {TypeError} If template is not a string or context is not an object.
208
239
  */
@@ -213,16 +244,19 @@ class TinyPkgExportValidator {
213
244
  if (typeof context !== 'object' || context === null) {
214
245
  throw new TypeError('The context must be a non-null object.');
215
246
  }
247
+ const values = /** @type {Record<string, unknown>} */ (context);
216
248
  return template.replace(/{(\w+)}/g, (match, key) => {
217
- // @ts-ignore
218
- return context[key] !== undefined ? context[key] : match;
249
+ const value = values[key];
250
+ return value !== undefined ? String(value) : match;
219
251
  });
220
252
  }
221
253
  /**
222
254
  * Internal helper to handle console output, coloring, and silent mode.
255
+ *
223
256
  * @param {'error'|'warning'|'success'|'info'|'dim'|'cyan'} type - The log type.
224
257
  * @param {string} templateKey - The key in the messages object.
225
- * @param {Object} [context={}] - Data for the template.
258
+ * @param {LogContext} [context={}] - Data for the template.
259
+ * @returns {void}
226
260
  * @throws {TypeError} If arguments do not match required types or if type is invalid.
227
261
  */
228
262
  #log(type, templateKey, context = {}) {
@@ -238,9 +272,8 @@ class TinyPkgExportValidator {
238
272
  if (typeof context !== 'object' || context === null) {
239
273
  throw new TypeError('The context must be a non-null object.');
240
274
  }
241
- const template =
242
- // @ts-ignore
243
- this.#messages[templateKey] || templateKey;
275
+ const messages = /** @type {Record<string, string>} */ (this.#messages);
276
+ const template = messages[templateKey] ?? templateKey;
244
277
  const message = this.#applyTemplate(template, { ...context, projectName: this.#projectName });
245
278
  switch (type) {
246
279
  case 'error':
@@ -333,21 +366,26 @@ class TinyPkgExportValidator {
333
366
  }
334
367
  /**
335
368
  * Executes the validation process.
336
- * @returns {Promise<boolean>} Returns true if all paths are valid, false otherwise.
369
+ *
370
+ * @returns {Promise<boolean>} True if all paths are valid, false otherwise.
371
+ * @throws {TypeError} If the "exports" field mixes subpath keys with condition keys.
337
372
  */
338
373
  async validate() {
339
374
  if (!this.#started) {
340
375
  this.#log('error', 'errorLoad');
341
- return true;
376
+ return false;
342
377
  }
343
378
  const exports = this.#packageData.exports;
344
- if (!exports) {
379
+ if (exports === undefined || exports === null) {
345
380
  this.#log('warning', 'noExports');
346
381
  return true;
347
382
  }
348
383
  this.#results = [];
349
384
  try {
350
- await this.#traverseExports(exports);
385
+ if (typeof exports === 'object' && !Array.isArray(exports)) {
386
+ this.#assertRootKeys(exports);
387
+ }
388
+ await this.#traverseExports(exports, 'exports', true);
351
389
  }
352
390
  catch (error) {
353
391
  if (error instanceof Error) {
@@ -366,35 +404,234 @@ class TinyPkgExportValidator {
366
404
  return this.#report();
367
405
  }
368
406
  /**
369
- * Recursively traverses the exports object.
407
+ * Ensures the root "exports" object does not mix subpath keys with condition keys.
408
+ *
409
+ * @param {Record<string, unknown>} exportsObject - The root "exports" object.
410
+ * @returns {void}
411
+ * @throws {TypeError} If subpath keys and condition keys are mixed.
412
+ */
413
+ #assertRootKeys(exportsObject) {
414
+ const keys = Object.keys(exportsObject);
415
+ const subpathCount = keys.filter((key) => key.startsWith('.')).length;
416
+ if (subpathCount === 0 || subpathCount === keys.length)
417
+ return;
418
+ throw new TypeError('The "exports" field cannot mix subpath keys ("./x") with condition keys ("import").');
419
+ }
420
+ /**
421
+ * Validates a single key of an exports object.
370
422
  *
371
- * @param {Record<string, any>|string} node - The current node of the exports object.
372
- * @param {string} currentKey - The key (used for log tracking).
423
+ * @param {string} key - The object key to validate.
424
+ * @param {boolean} isRoot - Whether the key belongs to the root "exports" object.
425
+ * @returns {string|null} A reason code when invalid, or null when the key is valid.
426
+ */
427
+ #getKeyError(key, isRoot) {
428
+ if (key.length === 0)
429
+ return 'EMPTY_KEY';
430
+ const isSubpath = key === '.' || key.startsWith('./');
431
+ if (isSubpath) {
432
+ if (!isRoot)
433
+ return 'NESTED_SUBPATH_KEY';
434
+ return null;
435
+ }
436
+ if (key.startsWith('.'))
437
+ return 'INVALID_SUBPATH_KEY';
438
+ if (key.includes(',') || key.includes('/') || key.includes('\\'))
439
+ return 'INVALID_CONDITION';
440
+ return null;
441
+ }
442
+ /**
443
+ * Recursively traverses the exports tree.
444
+ *
445
+ * @param {unknown} node - The current node of the exports tree.
446
+ * @param {string} currentKey - The dotted context path used for reporting.
447
+ * @param {boolean} [isRoot=false] - Whether this node is the root "exports" value.
373
448
  * @returns {Promise<void>}
374
- * @throws {TypeError} If node is not a string or object, or if currentKey is not a string.
449
+ * @throws {TypeError} If currentKey is not a string or node has an unsupported type.
375
450
  */
376
- async #traverseExports(node, currentKey = '') {
451
+ async #traverseExports(node, currentKey, isRoot = false) {
377
452
  if (typeof currentKey !== 'string') {
378
453
  throw new TypeError('The "currentKey" argument must be a string.');
379
454
  }
455
+ // Rule: null is a valid target. It excludes a subpath from a broader pattern.
456
+ if (node === null) {
457
+ this.#results.push({ path: currentKey, valid: true, kind: 'null' });
458
+ return;
459
+ }
460
+ // Rule: a string is a direct file target.
380
461
  if (typeof node === 'string') {
381
- // Base case: the value is a direct path
382
- await this.#checkFileExists(node, currentKey);
462
+ await this.#checkTarget(node, currentKey);
463
+ return;
464
+ }
465
+ // Rule: an array is a fallback list of targets.
466
+ if (Array.isArray(node)) {
467
+ if (node.length === 0) {
468
+ this.#results.push({
469
+ path: currentKey,
470
+ valid: false,
471
+ kind: 'invalid',
472
+ reason: 'EMPTY_ARRAY',
473
+ });
474
+ return;
475
+ }
476
+ for (let index = 0; index < node.length; index += 1) {
477
+ await this.#traverseExports(node[index], `${currentKey}[${index}]`);
478
+ }
479
+ return;
383
480
  }
384
- else if (typeof node === 'object' && node !== null) {
385
- // Recursive case: the value is an object (e.g., { import: '...', require: '...' })
386
- const keys = Object.keys(node);
481
+ // Rule: an object holds subpaths (root only) or conditions.
482
+ if (typeof node === 'object') {
483
+ const record = /** @type {Record<string, unknown>} */ (node);
484
+ const keys = Object.keys(record);
485
+ if (keys.length === 0) {
486
+ this.#results.push({
487
+ path: currentKey,
488
+ valid: false,
489
+ kind: 'invalid',
490
+ reason: 'EMPTY_OBJECT',
491
+ });
492
+ return;
493
+ }
387
494
  for (const key of keys) {
388
- const subKey = currentKey ? `${currentKey} -> ${key}` : key;
389
- await this.#traverseExports(node[key], subKey);
495
+ const keyError = this.#getKeyError(key, isRoot);
496
+ if (keyError !== null) {
497
+ this.#results.push({
498
+ path: `${currentKey} -> ${key}`,
499
+ valid: false,
500
+ kind: 'invalid',
501
+ errorPath: key,
502
+ reason: keyError,
503
+ });
504
+ continue;
505
+ }
506
+ await this.#traverseExports(record[key], `${currentKey} -> ${key}`);
390
507
  }
508
+ return;
391
509
  }
392
- else {
393
- throw new TypeError('The "node" argument must be a string or a non-null object.');
510
+ throw new TypeError('The "node" argument must be a string, an array, or a non-null object.');
511
+ }
512
+ /**
513
+ * Validates a single string target and dispatches it to the correct checker.
514
+ *
515
+ * @param {string} target - The raw target string from package.json.
516
+ * @param {string} context - The dotted context path used for reporting.
517
+ * @returns {Promise<void>}
518
+ */
519
+ async #checkTarget(target, context) {
520
+ const targetError = this.#getTargetError(target);
521
+ if (targetError !== null) {
522
+ this.#results.push({
523
+ path: context,
524
+ valid: false,
525
+ kind: 'invalid',
526
+ errorPath: target,
527
+ reason: targetError,
528
+ });
529
+ return;
394
530
  }
531
+ if (target.includes('*')) {
532
+ await this.#checkPatternTarget(target, context);
533
+ return;
534
+ }
535
+ await this.#checkFileExists(target, context);
536
+ }
537
+ /**
538
+ * Applies the path rules documented by Node.js for export targets.
539
+ *
540
+ * @param {string} target - The raw target string from package.json.
541
+ * @returns {string|null} A reason code when invalid, or null when the target is valid.
542
+ */
543
+ #getTargetError(target) {
544
+ if (target.length === 0)
545
+ return 'EMPTY_TARGET';
546
+ if (target.includes('\\'))
547
+ return 'INVALID_SEGMENT';
548
+ if (target.includes('?') || target.includes('#'))
549
+ return 'INVALID_CHARACTER';
550
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(target))
551
+ return 'URL_SCHEME_NOT_ALLOWED';
552
+ if (!target.startsWith('./'))
553
+ return 'TARGET_NOT_RELATIVE';
554
+ if (target.includes('**'))
555
+ return 'INVALID_PATTERN';
556
+ const segments = target.slice(2).split('/');
557
+ for (const segment of segments) {
558
+ const decoded = this.#safeDecode(segment).toLowerCase();
559
+ if (decoded.length === 0)
560
+ return 'INVALID_SEGMENT';
561
+ if (decoded === '.' || decoded === '..' || decoded === 'node_modules') {
562
+ return 'INVALID_SEGMENT';
563
+ }
564
+ }
565
+ return null;
566
+ }
567
+ /**
568
+ * Decodes a URI component without throwing on malformed input.
569
+ *
570
+ * @param {string} value - The value to decode.
571
+ * @returns {string} The decoded value, or the original value when decoding fails.
572
+ */
573
+ #safeDecode(value) {
574
+ try {
575
+ return decodeURIComponent(value);
576
+ }
577
+ catch {
578
+ return value;
579
+ }
580
+ }
581
+ /**
582
+ * Converts a subpath pattern into an anchored regular expression.
583
+ *
584
+ * @param {string} pattern - The file name pattern (e.g. "*.js").
585
+ * @returns {RegExp} The anchored regular expression.
586
+ */
587
+ #patternToRegExp(pattern) {
588
+ const source = pattern
589
+ .split('*')
590
+ .map((part) => part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))
591
+ .join('.*');
592
+ return new RegExp(`^${source}$`);
395
593
  }
396
594
  /**
397
- * Checks for the existence of a file in the file system.
595
+ * Expands a wildcard target against the file system.
596
+ *
597
+ * @param {string} target - The raw target containing at least one "*".
598
+ * @param {string} context - The dotted context path used for reporting.
599
+ * @returns {Promise<void>}
600
+ */
601
+ async #checkPatternTarget(target, context) {
602
+ const lastSlash = target.lastIndexOf('/');
603
+ const directory = lastSlash === 0 ? '.' : target.slice(0, lastSlash);
604
+ const filePattern = target.slice(lastSlash + 1);
605
+ // When the wildcard lives in a directory segment, fall back to the static prefix.
606
+ const staticDirectory = directory.includes('*')
607
+ ? directory.slice(0, directory.indexOf('*')).replace(/\/[^/]*$/, '') || '.'
608
+ : directory;
609
+ let entries;
610
+ try {
611
+ entries = await readdir(resolve(this.#rootDir, staticDirectory));
612
+ }
613
+ catch {
614
+ this.#results.push({
615
+ path: context,
616
+ valid: false,
617
+ kind: 'invalid',
618
+ errorPath: target,
619
+ reason: 'DIRECTORY_NOT_FOUND',
620
+ });
621
+ return;
622
+ }
623
+ const matcher = this.#patternToRegExp(filePattern);
624
+ const hasMatch = entries.some((entry) => matcher.test(entry));
625
+ this.#results.push({
626
+ path: context,
627
+ valid: hasMatch,
628
+ kind: hasMatch ? 'pattern' : 'invalid',
629
+ errorPath: target,
630
+ reason: hasMatch ? undefined : 'PATTERN_NO_MATCH',
631
+ });
632
+ }
633
+ /**
634
+ * Checks for the existence of a regular file in the file system.
398
635
  *
399
636
  * @param {string} relativePath - The relative path defined in package.json.
400
637
  * @param {string} context - The key context for reporting purposes.
@@ -408,15 +645,29 @@ class TinyPkgExportValidator {
408
645
  if (typeof context !== 'string') {
409
646
  throw new TypeError('The "context" argument must be a string.');
410
647
  }
411
- // Remove potential wildcards (e.g., '*') for literal path validation
412
- const cleanPath = relativePath.replace(/\*/g, '');
413
- const absolutePath = resolve(this.#rootDir, cleanPath);
648
+ const absolutePath = resolve(this.#rootDir, relativePath);
414
649
  try {
415
- await access(absolutePath);
416
- this.#results.push({ path: context, valid: true });
650
+ const stats = await stat(absolutePath);
651
+ if (!stats.isFile()) {
652
+ this.#results.push({
653
+ path: context,
654
+ valid: false,
655
+ kind: 'invalid',
656
+ errorPath: relativePath,
657
+ reason: 'NOT_A_FILE',
658
+ });
659
+ return;
660
+ }
661
+ this.#results.push({ path: context, valid: true, kind: 'file' });
417
662
  }
418
663
  catch {
419
- this.#results.push({ path: context, valid: false, errorPath: relativePath });
664
+ this.#results.push({
665
+ path: context,
666
+ valid: false,
667
+ kind: 'invalid',
668
+ errorPath: relativePath,
669
+ reason: 'FILE_NOT_FOUND',
670
+ });
420
671
  }
421
672
  }
422
673
  /**
@@ -428,24 +679,36 @@ class TinyPkgExportValidator {
428
679
  this.#log('cyan', 'header');
429
680
  let errorCount = 0;
430
681
  for (const result of this.#results) {
682
+ if (result.kind === 'null') {
683
+ this.#log('dim', 'itemSkipped', { path: result.path });
684
+ continue;
685
+ }
431
686
  if (result.valid) {
432
- this.#log('success', 'itemValid', { path: result.path });
687
+ this.#log('success', result.kind === 'pattern' ? 'itemPattern' : 'itemValid', {
688
+ path: result.path,
689
+ pattern: result.errorPath ?? '',
690
+ });
691
+ continue;
433
692
  }
434
- else {
435
- this.#log('error', 'itemInvalid', { path: result.path });
693
+ this.#log('error', 'itemInvalid', { path: result.path });
694
+ if (result.reason === 'FILE_NOT_FOUND') {
436
695
  this.#log('dim', 'itemMissing', { errorPath: result.errorPath });
437
- errorCount++;
438
696
  }
697
+ else {
698
+ this.#log('dim', 'itemInvalidTarget', {
699
+ target: result.errorPath ?? result.path,
700
+ reason: result.reason ?? 'UNKNOWN',
701
+ });
702
+ }
703
+ errorCount++;
439
704
  }
440
705
  this.#log('cyan', 'divider');
441
706
  if (errorCount === 0) {
442
707
  this.#log('success', 'successHeader');
443
708
  return true;
444
709
  }
445
- else {
446
- this.#log('error', 'failureHeader', { errorCount });
447
- return false;
448
- }
710
+ this.#log('error', 'failureHeader', { errorCount });
711
+ return false;
449
712
  }
450
713
  }
451
714
  export default TinyPkgExportValidator;
@@ -172,7 +172,6 @@ class TinyWebWorkerEngine extends TinyPlugin.TinyPluginCore {
172
172
  * signature. The rest parameter keeps it assignable to the inherited
173
173
  * `EventEmitter.emit` contract.
174
174
  *
175
- * @override
176
175
  * @param {string} type - The identifier for the message type.
177
176
  * @param {...any} args - The data content (only the first argument is used).
178
177
  * @returns {boolean} Always true when the message is dispatched.
@@ -100,7 +100,6 @@ declare class TinyWebWorkerEngine extends TinyPluginCore {
100
100
  * signature. The rest parameter keeps it assignable to the inherited
101
101
  * `EventEmitter.emit` contract.
102
102
  *
103
- * @override
104
103
  * @param {string} type - The identifier for the message type.
105
104
  * @param {...any} args - The data content (only the first argument is used).
106
105
  * @returns {boolean} Always true when the message is dispatched.
@@ -1 +1 @@
1
- {"version":3,"file":"TinyWebWorkerEngine.d.mts","sourceRoot":"","sources":["../../../../../../src/v1/libs/worker/engine/TinyWebWorkerEngine.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAIvF,YAAe,cAAc,GAAnB,GAAG,CAAgB;AAK7B,YAAU,eAAe,GACzB,CAAgB,IAAI,EAAZ,MACR,EAAyB,IAAI,AAA7B,CACA,EADQ,cACR,EAAiB,OAAO,AAAxB,CACA,EADQ,MACR,KAAU,OAAO,CAAC,GAAG,CACvB,CAAA;AAGE,YAAkB,iBAAiB,GACnC;;;;IAA4B,IAAI,AAAhC,CACA,EADW,cAAc,CACzB;;;;IAAmB,aAAa,EAArB,MAAM,CACnB;CAAA,CAAA;AAGE,YAAU,kBAAkB,GAC5B,CAA2B,OAAO,EAA1B,iBACR,KAAU,OAAO,CAAC,cAAc,GAAC,SAAS,CAAC,GAAG,CAAC,cAAc,GAAC,SAAS,CACzE,CAAA;AAIE,YAAkB,UAAU,GAC5B;;;;IAAmB,IAAI,EAAZ,MAAM,CACjB;;;;IAAyB,KAAK,EAAnB,YAAY,CACvB;;;;IAA4B,IAAI,AAAhC,CACF,EADa,cAAc,CAC3B;CAAA,CAAA;AAIE,YAAU,eAAe,GACzB,CAAoB,GAAG,EAAf,UACV,QAAA,CAAA;AAkBE,YAAmI,iBAAiB,CAJxH,KAAK,SAAtB,eAAsB,EACd,QAAQ,SAAhB,MAAgB,EACR,aAAa,SAArB,MAAqB,EACd,OAAO,SAAd,GAAG,EAAW,IACf,OAAO,6BAA6B,EAAE,mBAAmB,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAmB;AASpJ,YAAoF,uBAAuB,CAJ/E,KAAK,SAAtB,eAAsB,EACd,QAAQ,SAAhB,MAAgB,EACR,aAAa,SAArB,MAAqB,EACd,OAAO,SAAd,GAAG,EAAW,IACf,UAAU,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAyB;AAf9G;;;;;;;GAOG;AAEH;;;;;;;GAOG;AAEH;;GAEG;AACH,cAAM,mBAAoB,SAAQ,cAAc;;IA0B9C;;;OAGG;IACH,IAAI,OAAO,IAFE,OAAO,CAInB;IAED;;;;;;OAMG;IACH,YAAY,QAAQ,AALjB,CAIF,EAHE;QAA2B,SAAS,AAApC,CACA,EADQ,OAAO,CACf;QAA2B,YAAY,AAAvC,CACA,EADQ,OAAO,CACf;QAAoC,MAAM,AAA1C,CACF,EADU,OAAO,CAAC,OAAO,CAAC,CAC1B;KACwB,EASxB;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAJC,MAID,EAAE,QAAQ,EAHT,kBAGS,QAGnB;IAED;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAHA,MAGA,GAFE,OAAO,CAInB;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,IAAI,EAJZ,MAIY,EAAE,QAAQ,EAHtB,eAGsB,QAGhC;IAED;;;;OAIG;IACH,qBAAqB,CAAC,IAAI,EAHf,MAGe,GAFb,OAAO,CAInB;IAED;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,IAAI,EALE,MAKF,EAAE,GAAG,IAAI,EAJJ,GAAG,EAIC,GAHL,OAAO,CAgBnB;IAED;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EANP,MAMO,EAAE,IAAI,AALrB,CACA,EADQ,cAKa,EAAE,OAAO,AAJ9B,CACA,EADQ,MAI8B,GAH5B,OAAO,CAAC,GAAG,CAAC,CAuBxB;IAED;;;;OAIG;IACH,IAAI,IAHS,IAAI,CAmHhB;CACF;eAEc,mBAAmB"}
1
+ {"version":3,"file":"TinyWebWorkerEngine.d.mts","sourceRoot":"","sources":["../../../../../../src/v1/libs/worker/engine/TinyWebWorkerEngine.mjs"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAIvF,YAAe,cAAc,GAAnB,GAAG,CAAgB;AAK7B,YAAU,eAAe,GACzB,CAAgB,IAAI,EAAZ,MACR,EAAyB,IAAI,AAA7B,CACA,EADQ,cACR,EAAiB,OAAO,AAAxB,CACA,EADQ,MACR,KAAU,OAAO,CAAC,GAAG,CACvB,CAAA;AAGE,YAAkB,iBAAiB,GACnC;;;;IAA4B,IAAI,AAAhC,CACA,EADW,cAAc,CACzB;;;;IAAmB,aAAa,EAArB,MAAM,CACnB;CAAA,CAAA;AAGE,YAAU,kBAAkB,GAC5B,CAA2B,OAAO,EAA1B,iBACR,KAAU,OAAO,CAAC,cAAc,GAAC,SAAS,CAAC,GAAG,CAAC,cAAc,GAAC,SAAS,CACzE,CAAA;AAIE,YAAkB,UAAU,GAC5B;;;;IAAmB,IAAI,EAAZ,MAAM,CACjB;;;;IAAyB,KAAK,EAAnB,YAAY,CACvB;;;;IAA4B,IAAI,AAAhC,CACF,EADa,cAAc,CAC3B;CAAA,CAAA;AAIE,YAAU,eAAe,GACzB,CAAoB,GAAG,EAAf,UACV,QAAA,CAAA;AAkBE,YAAmI,iBAAiB,CAJxH,KAAK,SAAtB,eAAsB,EACd,QAAQ,SAAhB,MAAgB,EACR,aAAa,SAArB,MAAqB,EACd,OAAO,SAAd,GAAG,EAAW,IACf,OAAO,6BAA6B,EAAE,mBAAmB,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAmB;AASpJ,YAAoF,uBAAuB,CAJ/E,KAAK,SAAtB,eAAsB,EACd,QAAQ,SAAhB,MAAgB,EACR,aAAa,SAArB,MAAqB,EACd,OAAO,SAAd,GAAG,EAAW,IACf,UAAU,CAAC,mBAAmB,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAyB;AAf9G;;;;;;;GAOG;AAEH;;;;;;;GAOG;AAEH;;GAEG;AACH,cAAM,mBAAoB,SAAQ,cAAc;;IA0B9C;;;OAGG;IACH,IAAI,OAAO,IAFE,OAAO,CAInB;IAED;;;;;;OAMG;IACH,YAAY,QAAQ,AALjB,CAIF,EAHE;QAA2B,SAAS,AAApC,CACA,EADQ,OAAO,CACf;QAA2B,YAAY,AAAvC,CACA,EADQ,OAAO,CACf;QAAoC,MAAM,AAA1C,CACF,EADU,OAAO,CAAC,OAAO,CAAC,CAC1B;KACwB,EASxB;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,EAJC,MAID,EAAE,QAAQ,EAHT,kBAGS,QAGnB;IAED;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAHA,MAGA,GAFE,OAAO,CAInB;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,IAAI,EAJZ,MAIY,EAAE,QAAQ,EAHtB,eAGsB,QAGhC;IAED;;;;OAIG;IACH,qBAAqB,CAAC,IAAI,EAHf,MAGe,GAFb,OAAO,CAInB;IAED;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,IAAI,EALE,MAKF,EAAE,GAAG,IAAI,EAJJ,GAAG,EAIC,GAHL,OAAO,CAgBnB;IAED;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EANP,MAMO,EAAE,IAAI,AALrB,CACA,EADQ,cAKa,EAAE,OAAO,AAJ9B,CACA,EADQ,MAI8B,GAH5B,OAAO,CAAC,GAAG,CAAC,CAuBxB;IAED;;;;OAIG;IACH,IAAI,IAHS,IAAI,CAmHhB;CACF;eAEc,mBAAmB"}
@@ -148,7 +148,6 @@ class TinyWebWorkerEngine extends TinyPluginCore {
148
148
  * signature. The rest parameter keeps it assignable to the inherited
149
149
  * `EventEmitter.emit` contract.
150
150
  *
151
- * @override
152
151
  * @param {string} type - The identifier for the message type.
153
152
  * @param {...any} args - The data content (only the first argument is used).
154
153
  * @returns {boolean} Always true when the message is dispatched.
@@ -0,0 +1,15 @@
1
+ [data-bs-theme='light'] {
2
+ --pg-grid-line: rgba(20, 22, 40, 0.06);
3
+ }
4
+
5
+ [data-bs-theme='dark'] {
6
+ --pg-grid-line: rgba(255, 255, 255, 0.035);
7
+ }
8
+
9
+ body {
10
+ background-color: var(--pg-surface-alt);
11
+ background-image:
12
+ linear-gradient(var(--pg-grid-line) 1px, transparent 1px),
13
+ linear-gradient(90deg, var(--pg-grid-line) 1px, transparent 1px);
14
+ background-size: 32px 32px;
15
+ }