@holoscript/std 3.1.1 → 7.0.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 (142) hide show
  1. package/LICENSE +21 -0
  2. package/dist/__tests__/EconomicPrimitives.test.d.ts +2 -0
  3. package/dist/__tests__/EconomicTraits.test.d.ts +2 -0
  4. package/dist/__tests__/SimulationLabPrimitives.test.d.ts +2 -0
  5. package/dist/__tests__/collections.test.d.ts +2 -0
  6. package/dist/__tests__/events.test.d.ts +2 -0
  7. package/dist/__tests__/index.test.d.ts +2 -0
  8. package/dist/__tests__/index.test.d.ts.map +1 -0
  9. package/dist/__tests__/materials.test.d.ts +2 -0
  10. package/dist/__tests__/math.test.d.ts +2 -0
  11. package/dist/__tests__/physics.test.d.ts +2 -0
  12. package/dist/__tests__/spatial.test.d.ts +2 -0
  13. package/dist/__tests__/standard-library-fundamentals.test.d.ts +2 -0
  14. package/dist/__tests__/standard-library-fundamentals.test.d.ts.map +1 -0
  15. package/dist/__tests__/string-and-time-utilities.test.d.ts +2 -0
  16. package/dist/__tests__/string-and-time-utilities.test.d.ts.map +1 -0
  17. package/dist/__tests__/string-decoupled.test.d.ts +2 -0
  18. package/dist/__tests__/string.test.d.ts +2 -0
  19. package/dist/__tests__/time.test.d.ts +2 -0
  20. package/dist/chunk-DZHAVOCH.js +686 -0
  21. package/dist/chunk-DZHAVOCH.js.map +1 -0
  22. package/dist/chunk-P4O3WNG2.js +287 -0
  23. package/dist/chunk-P4O3WNG2.js.map +1 -0
  24. package/dist/chunk-PFX2JM4X.js +683 -0
  25. package/dist/chunk-PFX2JM4X.js.map +1 -0
  26. package/dist/chunk-PR4QN5HX.js +43 -0
  27. package/dist/chunk-PR4QN5HX.js.map +1 -0
  28. package/dist/chunk-WS6W35YC.js +443 -0
  29. package/dist/chunk-WS6W35YC.js.map +1 -0
  30. package/dist/chunk-XBA4ARST.js +9313 -0
  31. package/dist/chunk-XBA4ARST.js.map +1 -0
  32. package/dist/chunk-XJIFG7G3.js +348 -0
  33. package/dist/chunk-XJIFG7G3.js.map +1 -0
  34. package/dist/chunk-ZXVZAQCZ.js +470 -0
  35. package/dist/chunk-ZXVZAQCZ.js.map +1 -0
  36. package/dist/collections.cjs +715 -0
  37. package/dist/collections.cjs.map +1 -0
  38. package/dist/collections.d.ts +177 -0
  39. package/dist/collections.js +18 -0
  40. package/dist/collections.js.map +1 -0
  41. package/dist/events.d.ts +32 -0
  42. package/dist/fs/__tests__/file-watch-system.test.d.ts +2 -0
  43. package/dist/fs/__tests__/file-watch-system.test.d.ts.map +1 -0
  44. package/dist/fs/__tests__/path-utilities.test.d.ts +2 -0
  45. package/dist/fs/__tests__/path-utilities.test.d.ts.map +1 -0
  46. package/dist/fs/__tests__/path.test.d.ts +2 -0
  47. package/dist/fs/__tests__/path.test.d.ts.map +1 -0
  48. package/dist/fs/fs.d.ts +288 -0
  49. package/dist/fs/fs.d.ts.map +1 -0
  50. package/dist/fs/index.cjs +9338 -0
  51. package/dist/fs/index.cjs.map +1 -0
  52. package/dist/fs/index.d.ts +51 -0
  53. package/dist/fs/index.d.ts.map +1 -0
  54. package/dist/fs/index.js +204 -0
  55. package/dist/fs/index.js.map +1 -0
  56. package/dist/fs/path.d.ts +135 -0
  57. package/dist/fs/path.d.ts.map +1 -0
  58. package/dist/fs/watch.d.ts +133 -0
  59. package/dist/fs/watch.d.ts.map +1 -0
  60. package/dist/index.cjs +13326 -0
  61. package/dist/index.cjs.map +1 -0
  62. package/dist/index.d.ts +102 -0
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +1275 -190
  65. package/dist/index.js.map +1 -0
  66. package/dist/materials.d.ts +50 -0
  67. package/dist/math.cjs +595 -0
  68. package/dist/math.cjs.map +1 -0
  69. package/dist/math.d.ts +162 -0
  70. package/dist/math.js +54 -0
  71. package/dist/math.js.map +1 -0
  72. package/dist/physics.d.ts +59 -0
  73. package/dist/spatial.d.ts +82 -0
  74. package/dist/string.basic.test.d.ts +5 -0
  75. package/dist/string.basic.test.d.ts.map +1 -0
  76. package/dist/string.cjs +422 -0
  77. package/dist/string.cjs.map +1 -0
  78. package/dist/string.d.ts +212 -0
  79. package/dist/string.d.ts.map +1 -1
  80. package/dist/string.js +108 -0
  81. package/dist/string.js.map +1 -0
  82. package/dist/string.test.d.ts +5 -0
  83. package/dist/string.test.d.ts.map +1 -0
  84. package/dist/time.cjs +512 -0
  85. package/dist/time.cjs.map +1 -0
  86. package/dist/time.d.ts +215 -0
  87. package/dist/time.js +44 -0
  88. package/dist/time.js.map +1 -0
  89. package/dist/traits/ARTraits.d.ts +14 -0
  90. package/dist/traits/EconomicPrimitives.cjs +335 -0
  91. package/dist/traits/EconomicPrimitives.cjs.map +1 -0
  92. package/dist/traits/EconomicPrimitives.d.ts +345 -0
  93. package/dist/traits/EconomicPrimitives.js +56 -0
  94. package/dist/traits/EconomicPrimitives.js.map +1 -0
  95. package/dist/traits/EconomicTraits.cjs +471 -0
  96. package/dist/traits/EconomicTraits.cjs.map +1 -0
  97. package/dist/traits/EconomicTraits.d.ts +71 -0
  98. package/dist/traits/EconomicTraits.js +18 -0
  99. package/dist/traits/EconomicTraits.js.map +1 -0
  100. package/dist/traits/IoTTraits.d.ts +14 -0
  101. package/dist/traits/SimulationLabPrimitives.d.ts +187 -0
  102. package/dist/traits/SimulationLabTraits.d.ts +42 -0
  103. package/dist/traits/VRRTraits.d.ts +150 -0
  104. package/dist/traits/__tests__/ARTraits.test.d.ts +2 -0
  105. package/dist/traits/__tests__/ARTraits.test.d.ts.map +1 -0
  106. package/dist/traits/__tests__/EconomicPrimitives.test.d.ts +2 -0
  107. package/dist/traits/__tests__/EconomicPrimitives.test.d.ts.map +1 -0
  108. package/dist/traits/__tests__/EconomicTraits.test.d.ts +2 -0
  109. package/dist/traits/__tests__/EconomicTraits.test.d.ts.map +1 -0
  110. package/dist/types.d.ts +202 -0
  111. package/dist/types.d.ts.map +1 -1
  112. package/error-utf8.log +6 -0
  113. package/error.log +0 -0
  114. package/package.json +35 -18
  115. package/src/__tests__/index.test.ts +14 -0
  116. package/src/__tests__/{Sprint33.test.ts → standard-library-fundamentals.test.ts} +91 -74
  117. package/src/__tests__/{Sprint56.test.ts → string-and-time-utilities.test.ts} +64 -64
  118. package/src/__tests__/string-decoupled.test.ts +6 -9
  119. package/src/fs/__tests__/file-watch-system.test.ts +675 -0
  120. package/src/fs/__tests__/path-utilities.test.ts +375 -0
  121. package/src/fs/__tests__/path.test.ts +287 -0
  122. package/src/fs/fs.ts +692 -0
  123. package/src/fs/index.ts +194 -0
  124. package/src/fs/path.ts +310 -0
  125. package/src/fs/watch.ts +413 -0
  126. package/src/index.ts +3 -1
  127. package/src/math.ts +1 -1
  128. package/src/string.basic.test.ts +1 -1
  129. package/src/string.test.ts +4 -4
  130. package/src/string.ts +32 -17
  131. package/src/time.ts +1 -1
  132. package/src/traits/ARTraits.ts +2 -2
  133. package/src/traits/IoTTraits.ts +2 -2
  134. package/src/traits/VRRTraits.ts +2 -2
  135. package/src/traits/__tests__/ARTraits.test.ts +8 -0
  136. package/src/traits/__tests__/EconomicPrimitives.test.ts +14 -0
  137. package/src/traits/__tests__/EconomicTraits.test.ts +16 -0
  138. package/src/types.ts +10 -3
  139. package/std_error.log +5 -0
  140. package/tsup.config.ts +20 -0
  141. package/dist/__tests__/Sprint33.test.d.ts.map +0 -1
  142. package/dist/__tests__/Sprint56.test.d.ts.map +0 -1
package/package.json CHANGED
@@ -1,46 +1,53 @@
1
1
  {
2
2
  "name": "@holoscript/std",
3
- "version": "3.1.1",
3
+ "version": "7.0.0",
4
4
  "description": "HoloScript Standard Library - Core types and utilities",
5
- "main": "dist/index.js",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.js",
6
7
  "types": "dist/index.d.ts",
7
8
  "type": "module",
8
9
  "exports": {
9
10
  ".": {
10
11
  "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
12
14
  },
13
15
  "./math": {
14
16
  "types": "./dist/math.d.ts",
15
- "import": "./dist/math.js"
17
+ "import": "./dist/math.js",
18
+ "require": "./dist/math.cjs"
16
19
  },
17
20
  "./collections": {
18
21
  "types": "./dist/collections.d.ts",
19
- "import": "./dist/collections.js"
22
+ "import": "./dist/collections.js",
23
+ "require": "./dist/collections.cjs"
20
24
  },
21
25
  "./string": {
22
26
  "types": "./dist/string.d.ts",
23
- "import": "./dist/string.js"
27
+ "import": "./dist/string.js",
28
+ "require": "./dist/string.cjs"
24
29
  },
25
30
  "./time": {
26
31
  "types": "./dist/time.d.ts",
27
- "import": "./dist/time.js"
32
+ "import": "./dist/time.js",
33
+ "require": "./dist/time.cjs"
28
34
  },
29
35
  "./economic": {
30
36
  "types": "./dist/traits/EconomicPrimitives.d.ts",
31
- "import": "./dist/traits/EconomicPrimitives.js"
37
+ "import": "./dist/traits/EconomicPrimitives.js",
38
+ "require": "./dist/traits/EconomicPrimitives.cjs"
32
39
  },
33
40
  "./economic-traits": {
34
41
  "types": "./dist/traits/EconomicTraits.d.ts",
35
- "import": "./dist/traits/EconomicTraits.js"
42
+ "import": "./dist/traits/EconomicTraits.js",
43
+ "require": "./dist/traits/EconomicTraits.cjs"
44
+ },
45
+ "./fs": {
46
+ "types": "./dist/fs/index.d.ts",
47
+ "import": "./dist/fs/index.js",
48
+ "require": "./dist/fs/index.cjs"
36
49
  }
37
50
  },
38
- "scripts": {
39
- "build": "tsc",
40
- "watch": "tsc -w",
41
- "clean": "rm -rf dist",
42
- "test": "vitest run --passWithNoTests"
43
- },
44
51
  "keywords": [
45
52
  "holoscript",
46
53
  "std",
@@ -55,12 +62,22 @@
55
62
  "license": "MIT",
56
63
  "repository": {
57
64
  "type": "git",
58
- "url": "https://github.com/brianonbased-dev/Holoscript.git",
65
+ "url": "https://github.com/brianonbased-dev/HoloScript.git",
59
66
  "directory": "packages/std"
60
67
  },
61
68
  "devDependencies": {
62
69
  "@types/node": "^24.10.1",
63
70
  "typescript": "~5.9.3",
64
- "vitest": "^4.0.18"
71
+ "vitest": "^4.1.0"
72
+ },
73
+ "homepage": "https://github.com/brianonbased-dev/HoloScript#readme",
74
+ "bugs": {
75
+ "url": "https://github.com/brianonbased-dev/HoloScript/issues"
76
+ },
77
+ "scripts": {
78
+ "build": "tsup && tsc --emitDeclarationOnly --declarationDir dist --skipLibCheck",
79
+ "watch": "tsc -w",
80
+ "clean": "rm -rf dist",
81
+ "test": "vitest run --passWithNoTests"
65
82
  }
66
- }
83
+ }
@@ -0,0 +1,14 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import * as std from '../index.js';
3
+
4
+ describe('std/index', () => {
5
+ it('should export standard types and math', () => {
6
+ expect(std).toBeDefined();
7
+ expect(std.PI).toBeGreaterThan(3.14);
8
+ });
9
+
10
+ it('should export string utilities', () => {
11
+ expect(std.capitalize('holo')).toBe('Holo');
12
+ expect(typeof std.lerp).toBe('function');
13
+ });
14
+ });
@@ -1,12 +1,12 @@
1
- /**
2
- * Sprint 33 — @holoscript/std acceptance tests
1
+ /**
2
+ * @holoscript/std acceptance tests
3
3
  * Covers: types, collections, math, string, time
4
4
  */
5
5
  import { describe, it, expect, vi, beforeEach } from 'vitest';
6
6
 
7
- // ─────────────────────────────────────────────
7
+ // ─────────────────────────────────────────────
8
8
  // types.ts
9
- // ─────────────────────────────────────────────
9
+ // ─────────────────────────────────────────────
10
10
  import {
11
11
  vec2,
12
12
  vec3,
@@ -26,14 +26,14 @@ import {
26
26
  colorToHex,
27
27
  } from '../types.js';
28
28
 
29
- // ─────────────────────────────────────────────
29
+ // ─────────────────────────────────────────────
30
30
  // collections.ts
31
- // ─────────────────────────────────────────────
31
+ // ─────────────────────────────────────────────
32
32
  import { List, HoloMap, HoloSet, SpatialGrid, PriorityQueue } from '../collections.js';
33
33
 
34
- // ─────────────────────────────────────────────
34
+ // ─────────────────────────────────────────────
35
35
  // math.ts
36
- // ─────────────────────────────────────────────
36
+ // ─────────────────────────────────────────────
37
37
  import {
38
38
  PI,
39
39
  TAU,
@@ -60,9 +60,9 @@ import {
60
60
  random,
61
61
  } from '../math.js';
62
62
 
63
- // ─────────────────────────────────────────────
63
+ // ─────────────────────────────────────────────
64
64
  // string.ts
65
- // ─────────────────────────────────────────────
65
+ // ─────────────────────────────────────────────
66
66
  import {
67
67
  capitalize,
68
68
  titleCase,
@@ -113,9 +113,9 @@ import {
113
113
  uuid,
114
114
  } from '../string.js';
115
115
 
116
- // ─────────────────────────────────────────────
116
+ // ─────────────────────────────────────────────
117
117
  // time.ts
118
- // ─────────────────────────────────────────────
118
+ // ─────────────────────────────────────────────
119
119
  import {
120
120
  now,
121
121
  sleep,
@@ -127,10 +127,10 @@ import {
127
127
  DateTime,
128
128
  } from '../time.js';
129
129
 
130
- // ═══════════════════════════════════════════════
130
+ // ═══════════════════════════════════════════════
131
131
  // types.ts
132
- // ═══════════════════════════════════════════════
133
- describe('types factory functions', () => {
132
+ // ═══════════════════════════════════════════════
133
+ describe('types — factory functions', () => {
134
134
  it('vec2 defaults to (0,0)', () => {
135
135
  const v = vec2();
136
136
  expect(v.x).toBe(0);
@@ -203,13 +203,18 @@ describe('types — factory functions', () => {
203
203
  });
204
204
  });
205
205
 
206
- describe('types conversion utilities', () => {
206
+ describe('types — conversion utilities', () => {
207
207
  it('vec3ToArray / arrayToVec3 round-trip', () => {
208
208
  const v = vec3(1, 2, 3);
209
209
  const arr = vec3ToArray(v);
210
210
  expect(arr).toEqual([1, 2, 3]);
211
211
  const v2 = arrayToVec3(arr);
212
- expect(v2).toEqual({ x: 1, y: 2, z: 3 });
212
+ // vec3() returns an Array-backed Vec3 with non-enumerable x/y/z accessors
213
+ // (types.ts:195). toEqual on {x,y,z} therefore fails on structure
214
+ // mismatch — assert each accessor instead to test the behavioral contract.
215
+ expect(v2.x).toBe(1);
216
+ expect(v2.y).toBe(2);
217
+ expect(v2.z).toBe(3);
213
218
  });
214
219
 
215
220
  it('quatToArray / arrayToQuat round-trip', () => {
@@ -236,9 +241,9 @@ describe('types — conversion utilities', () => {
236
241
  });
237
242
  });
238
243
 
239
- // ═══════════════════════════════════════════════
240
- // collections List
241
- // ═══════════════════════════════════════════════
244
+ // ═══════════════════════════════════════════════
245
+ // collections — List
246
+ // ═══════════════════════════════════════════════
242
247
  describe('List', () => {
243
248
  it('creates empty list', () => {
244
249
  const l = new List<number>();
@@ -363,9 +368,9 @@ describe('List', () => {
363
368
  });
364
369
  });
365
370
 
366
- // ═══════════════════════════════════════════════
367
- // collections HoloMap
368
- // ═══════════════════════════════════════════════
371
+ // ═══════════════════════════════════════════════
372
+ // collections — HoloMap
373
+ // ═══════════════════════════════════════════════
369
374
  describe('HoloMap', () => {
370
375
  it('creates empty map', () => {
371
376
  const m = new HoloMap<string, number>();
@@ -435,9 +440,9 @@ describe('HoloMap', () => {
435
440
  });
436
441
  });
437
442
 
438
- // ═══════════════════════════════════════════════
439
- // collections HoloSet
440
- // ═══════════════════════════════════════════════
443
+ // ═══════════════════════════════════════════════
444
+ // collections — HoloSet
445
+ // ═══════════════════════════════════════════════
441
446
  describe('HoloSet', () => {
442
447
  it('creates empty set', () => {
443
448
  const s = new HoloSet<number>();
@@ -516,9 +521,9 @@ describe('HoloSet', () => {
516
521
  });
517
522
  });
518
523
 
519
- // ═══════════════════════════════════════════════
520
- // collections PriorityQueue
521
- // ═══════════════════════════════════════════════
524
+ // ═══════════════════════════════════════════════
525
+ // collections — PriorityQueue
526
+ // ═══════════════════════════════════════════════
522
527
  describe('PriorityQueue', () => {
523
528
  it('minHeap dequeues lowest priority first', () => {
524
529
  const pq = PriorityQueue.minHeap<string>();
@@ -561,9 +566,9 @@ describe('PriorityQueue', () => {
561
566
  });
562
567
  });
563
568
 
564
- // ═══════════════════════════════════════════════
565
- // collections SpatialGrid
566
- // ═══════════════════════════════════════════════
569
+ // ═══════════════════════════════════════════════
570
+ // collections — SpatialGrid
571
+ // ═══════════════════════════════════════════════
567
572
  describe('SpatialGrid', () => {
568
573
  it('insert and query by radius', () => {
569
574
  const grid = new SpatialGrid<string>(1.0);
@@ -592,9 +597,9 @@ describe('SpatialGrid', () => {
592
597
  });
593
598
  });
594
599
 
595
- // ═══════════════════════════════════════════════
596
- // math constants
597
- // ═══════════════════════════════════════════════
600
+ // ═══════════════════════════════════════════════
601
+ // math — constants
602
+ // ═══════════════════════════════════════════════
598
603
  describe('math constants', () => {
599
604
  it('PI is ~3.14159', () => expect(PI).toBeCloseTo(3.14159, 4));
600
605
  it('TAU is 2*PI', () => expect(TAU).toBeCloseTo(PI * 2, 10));
@@ -604,10 +609,10 @@ describe('math constants', () => {
604
609
  it('EPSILON is small', () => expect(EPSILON).toBeGreaterThan(0));
605
610
  });
606
611
 
607
- // ═══════════════════════════════════════════════
608
- // math basic functions
609
- // ═══════════════════════════════════════════════
610
- describe('math basic functions', () => {
612
+ // ═══════════════════════════════════════════════
613
+ // math — basic functions
614
+ // ═══════════════════════════════════════════════
615
+ describe('math — basic functions', () => {
611
616
  it('clamp', () => {
612
617
  expect(clamp(5, 0, 10)).toBe(5);
613
618
  expect(clamp(-5, 0, 10)).toBe(0);
@@ -664,9 +669,9 @@ describe('math — basic functions', () => {
664
669
  });
665
670
  });
666
671
 
667
- // ═══════════════════════════════════════════════
668
- // math vec2Math
669
- // ═══════════════════════════════════════════════
672
+ // ═══════════════════════════════════════════════
673
+ // math — vec2Math
674
+ // ═══════════════════════════════════════════════
670
675
  describe('vec2Math', () => {
671
676
  it('add', () => {
672
677
  const r = vec2Math.add({ x: 1, y: 2 }, { x: 3, y: 4 });
@@ -712,13 +717,21 @@ describe('vec2Math', () => {
712
717
  });
713
718
  });
714
719
 
715
- // ═══════════════════════════════════════════════
716
- // math vec3Math
717
- // ═══════════════════════════════════════════════
720
+ // ═══════════════════════════════════════════════
721
+ // math — vec3Math
722
+ // ═══════════════════════════════════════════════
718
723
  describe('vec3Math', () => {
719
724
  it('zero / one factory functions', () => {
720
- expect(vec3Math.zero()).toEqual({ x: 0, y: 0, z: 0 });
721
- expect(vec3Math.one()).toEqual({ x: 1, y: 1, z: 1 });
725
+ // vec3() is Array-backed with non-enumerable x/y/z (types.ts:195); test
726
+ // accessor contract rather than object structure.
727
+ const z = vec3Math.zero();
728
+ expect(z.x).toBe(0);
729
+ expect(z.y).toBe(0);
730
+ expect(z.z).toBe(0);
731
+ const o = vec3Math.one();
732
+ expect(o.x).toBe(1);
733
+ expect(o.y).toBe(1);
734
+ expect(o.z).toBe(1);
722
735
  });
723
736
 
724
737
  it('up / down / forward / back factory functions', () => {
@@ -729,8 +742,12 @@ describe('vec3Math', () => {
729
742
  });
730
743
 
731
744
  it('add', () => {
745
+ // vec3Math.add returns a vec3() (Array-backed with non-enumerable x/y/z).
746
+ // Assert accessor contract instead of object structure.
732
747
  const r = vec3Math.add({ x: 1, y: 2, z: 3 }, { x: 4, y: 5, z: 6 });
733
- expect(r).toEqual({ x: 5, y: 7, z: 9 });
748
+ expect(r.x).toBe(5);
749
+ expect(r.y).toBe(7);
750
+ expect(r.z).toBe(9);
734
751
  });
735
752
 
736
753
  it('sub', () => {
@@ -776,9 +793,9 @@ describe('vec3Math', () => {
776
793
  });
777
794
  });
778
795
 
779
- // ═══════════════════════════════════════════════
780
- // math quatMath
781
- // ═══════════════════════════════════════════════
796
+ // ═══════════════════════════════════════════════
797
+ // math — quatMath
798
+ // ═══════════════════════════════════════════════
782
799
  describe('quatMath', () => {
783
800
  it('identity quaternion', () => {
784
801
  const q = quatMath.identity();
@@ -827,9 +844,9 @@ describe('quatMath', () => {
827
844
  });
828
845
  });
829
846
 
830
- // ═══════════════════════════════════════════════
831
- // math aabbMath
832
- // ═══════════════════════════════════════════════
847
+ // ═══════════════════════════════════════════════
848
+ // math — aabbMath
849
+ // ═══════════════════════════════════════════════
833
850
  describe('aabbMath', () => {
834
851
  const box = { min: { x: 0, y: 0, z: 0 }, max: { x: 2, y: 2, z: 2 } };
835
852
 
@@ -875,9 +892,9 @@ describe('aabbMath', () => {
875
892
  });
876
893
  });
877
894
 
878
- // ═══════════════════════════════════════════════
879
- // math noise
880
- // ═══════════════════════════════════════════════
895
+ // ═══════════════════════════════════════════════
896
+ // math — noise
897
+ // ═══════════════════════════════════════════════
881
898
  describe('noise', () => {
882
899
  it('perlin2d returns value in range', () => {
883
900
  const v = noise.perlin2d(0.5, 0.5);
@@ -912,9 +929,9 @@ describe('noise', () => {
912
929
  });
913
930
  });
914
931
 
915
- // ═══════════════════════════════════════════════
916
- // math random
917
- // ═══════════════════════════════════════════════
932
+ // ═══════════════════════════════════════════════
933
+ // math — random
934
+ // ═══════════════════════════════════════════════
918
935
  describe('random', () => {
919
936
  it('float returns [0,1)', () => {
920
937
  for (let i = 0; i < 20; i++) {
@@ -976,10 +993,10 @@ describe('random', () => {
976
993
  });
977
994
  });
978
995
 
979
- // ═══════════════════════════════════════════════
996
+ // ═══════════════════════════════════════════════
980
997
  // string utilities
981
- // ═══════════════════════════════════════════════
982
- describe('string case conversion', () => {
998
+ // ═══════════════════════════════════════════════
999
+ describe('string — case conversion', () => {
983
1000
  it('capitalize', () => expect(capitalize('hello world')).toBe('Hello world'));
984
1001
  it('titleCase', () => expect(titleCase('hello world')).toBe('Hello World'));
985
1002
  it('camelCase', () => expect(camelCase('hello world')).toBe('helloWorld'));
@@ -989,7 +1006,7 @@ describe('string — case conversion', () => {
989
1006
  it('constantCase', () => expect(constantCase('helloWorld')).toBe('HELLO_WORLD'));
990
1007
  });
991
1008
 
992
- describe('string padding and truncation', () => {
1009
+ describe('string — padding and truncation', () => {
993
1010
  it('padLeft', () => expect(padLeft('hi', 5)).toBe(' hi'));
994
1011
  it('padRight', () => expect(padRight('hi', 5)).toBe('hi '));
995
1012
  it('center', () => {
@@ -1007,7 +1024,7 @@ describe('string — padding and truncation', () => {
1007
1024
  });
1008
1025
  });
1009
1026
 
1010
- describe('string checks', () => {
1027
+ describe('string — checks', () => {
1011
1028
  it('isBlank / isNotBlank', () => {
1012
1029
  expect(isBlank('')).toBe(true);
1013
1030
  expect(isBlank(' ')).toBe(true);
@@ -1049,7 +1066,7 @@ describe('string — checks', () => {
1049
1066
  });
1050
1067
  });
1051
1068
 
1052
- describe('string manipulation', () => {
1069
+ describe('string — manipulation', () => {
1053
1070
  it('repeat', () => expect(repeat('ab', 3)).toBe('ababab'));
1054
1071
  it('reverse', () => expect(reverse('hello')).toBe('olleh'));
1055
1072
  it('count occurrences', () => expect(count('hello world hello', 'hello')).toBe(2));
@@ -1061,7 +1078,7 @@ describe('string — manipulation', () => {
1061
1078
  it('unwrap', () => expect(unwrap('"hello"', '"')).toBe('hello'));
1062
1079
  });
1063
1080
 
1064
- describe('string splitting', () => {
1081
+ describe('string — splitting', () => {
1065
1082
  it('lines splits by newline', () => {
1066
1083
  const l = lines('a\nb\nc');
1067
1084
  expect(l).toEqual(['a', 'b', 'c']);
@@ -1075,7 +1092,7 @@ describe('string — splitting', () => {
1075
1092
  });
1076
1093
  });
1077
1094
 
1078
- describe('string formatting', () => {
1095
+ describe('string — formatting', () => {
1079
1096
  it('format substitutes named placeholders', () => {
1080
1097
  const result = format('Hello {name}, you are {age}!', { name: 'World', age: 42 });
1081
1098
  expect(result).toContain('World');
@@ -1093,7 +1110,7 @@ describe('string — formatting', () => {
1093
1110
  });
1094
1111
  });
1095
1112
 
1096
- describe('string escaping', () => {
1113
+ describe('string — escaping', () => {
1097
1114
  it('escapeHtml / unescapeHtml', () => {
1098
1115
  const escaped = escapeHtml('<b>hello</b>');
1099
1116
  expect(escaped).toContain('&lt;');
@@ -1111,7 +1128,7 @@ describe('string — escaping', () => {
1111
1128
  });
1112
1129
  });
1113
1130
 
1114
- describe('string similarity', () => {
1131
+ describe('string — similarity', () => {
1115
1132
  it('levenshtein', () => {
1116
1133
  expect(levenshtein('kitten', 'sitting')).toBeGreaterThan(0);
1117
1134
  expect(levenshtein('abc', 'abc')).toBe(0);
@@ -1128,7 +1145,7 @@ describe('string — similarity', () => {
1128
1145
  });
1129
1146
  });
1130
1147
 
1131
- describe('string indentation', () => {
1148
+ describe('string — indentation', () => {
1132
1149
  it('indent adds prefix', () => {
1133
1150
  const s = indent('a\nb', 2);
1134
1151
  expect(s).toContain(' a');
@@ -1149,7 +1166,7 @@ describe('string — indentation', () => {
1149
1166
  });
1150
1167
  });
1151
1168
 
1152
- describe('string generation', () => {
1169
+ describe('string — generation', () => {
1153
1170
  it('randomString generates string of given length', () => {
1154
1171
  const s = randomString(10);
1155
1172
  expect(s.length).toBe(10);
@@ -1162,9 +1179,9 @@ describe('string — generation', () => {
1162
1179
  });
1163
1180
  });
1164
1181
 
1165
- // ═══════════════════════════════════════════════
1182
+ // ═══════════════════════════════════════════════
1166
1183
  // time utilities
1167
- // ═══════════════════════════════════════════════
1184
+ // ═══════════════════════════════════════════════
1168
1185
  describe('now', () => {
1169
1186
  it('returns number', () => {
1170
1187
  expect(typeof now()).toBe('number');