@holoscript/std 2.1.0 → 6.0.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.
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +197 -0
- package/dist/__tests__/EconomicPrimitives.test.d.ts +2 -0
- package/dist/__tests__/EconomicPrimitives.test.d.ts.map +1 -0
- package/dist/__tests__/EconomicTraits.test.d.ts +2 -0
- package/dist/__tests__/EconomicTraits.test.d.ts.map +1 -0
- package/dist/__tests__/SimulationLabPrimitives.test.d.ts +2 -0
- package/dist/__tests__/SimulationLabPrimitives.test.d.ts.map +1 -0
- package/dist/__tests__/collections.test.d.ts +2 -0
- package/dist/__tests__/collections.test.d.ts.map +1 -0
- package/dist/__tests__/events.test.d.ts +2 -0
- package/dist/__tests__/events.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/materials.test.d.ts +2 -0
- package/dist/__tests__/materials.test.d.ts.map +1 -0
- package/dist/__tests__/math.test.d.ts +2 -0
- package/dist/__tests__/math.test.d.ts.map +1 -0
- package/dist/__tests__/physics.test.d.ts +2 -0
- package/dist/__tests__/physics.test.d.ts.map +1 -0
- package/dist/__tests__/spatial.test.d.ts +2 -0
- package/dist/__tests__/spatial.test.d.ts.map +1 -0
- package/dist/__tests__/standard-library-fundamentals.test.d.ts +2 -0
- package/dist/__tests__/standard-library-fundamentals.test.d.ts.map +1 -0
- package/dist/__tests__/string-and-time-utilities.test.d.ts +2 -0
- package/dist/__tests__/string-and-time-utilities.test.d.ts.map +1 -0
- package/dist/__tests__/string-decoupled.test.d.ts +2 -0
- package/dist/__tests__/string-decoupled.test.d.ts.map +1 -0
- package/dist/__tests__/string.test.d.ts +2 -0
- package/dist/__tests__/string.test.d.ts.map +1 -0
- package/dist/__tests__/time.test.d.ts +2 -0
- package/dist/__tests__/time.test.d.ts.map +1 -0
- package/dist/chunk-7HVUYGPS.js +679 -0
- package/dist/chunk-7HVUYGPS.js.map +1 -0
- package/dist/chunk-P4O3WNG2.js +287 -0
- package/dist/chunk-P4O3WNG2.js.map +1 -0
- package/dist/chunk-PFX2JM4X.js +683 -0
- package/dist/chunk-PFX2JM4X.js.map +1 -0
- package/dist/chunk-W2Q3LUCM.js +348 -0
- package/dist/chunk-W2Q3LUCM.js.map +1 -0
- package/dist/chunk-WS6W35YC.js +443 -0
- package/dist/chunk-WS6W35YC.js.map +1 -0
- package/dist/chunk-ZXVZAQCZ.js +470 -0
- package/dist/chunk-ZXVZAQCZ.js.map +1 -0
- package/dist/collections.cjs +715 -0
- package/dist/collections.cjs.map +1 -0
- package/dist/collections.d.ts.map +1 -1
- package/dist/collections.js +16 -719
- package/dist/collections.js.map +1 -1
- package/dist/events.d.ts +32 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/index.cjs +4101 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +21 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1270 -157
- package/dist/index.js.map +1 -1
- package/dist/materials.d.ts +50 -0
- package/dist/materials.d.ts.map +1 -0
- package/dist/math.cjs +591 -0
- package/dist/math.cjs.map +1 -0
- package/dist/math.d.ts.map +1 -1
- package/dist/math.js +51 -537
- package/dist/math.js.map +1 -1
- package/dist/physics.d.ts +59 -0
- package/dist/physics.d.ts.map +1 -0
- package/dist/spatial.d.ts +82 -0
- package/dist/spatial.d.ts.map +1 -0
- package/dist/string.basic.test.d.ts +5 -0
- package/dist/string.basic.test.d.ts.map +1 -0
- package/dist/string.cjs +422 -0
- package/dist/string.cjs.map +1 -0
- package/dist/string.d.ts +5 -1
- package/dist/string.d.ts.map +1 -1
- package/dist/string.js +106 -442
- package/dist/string.js.map +1 -1
- package/dist/string.test.d.ts +5 -0
- package/dist/string.test.d.ts.map +1 -0
- package/dist/time.cjs +512 -0
- package/dist/time.cjs.map +1 -0
- package/dist/time.d.ts.map +1 -1
- package/dist/time.js +41 -528
- package/dist/time.js.map +1 -1
- package/dist/traits/ARTraits.d.ts +14 -0
- package/dist/traits/ARTraits.d.ts.map +1 -0
- package/dist/traits/EconomicPrimitives.cjs +335 -0
- package/dist/traits/EconomicPrimitives.cjs.map +1 -0
- package/dist/traits/EconomicPrimitives.d.ts +345 -0
- package/dist/traits/EconomicPrimitives.d.ts.map +1 -0
- package/dist/traits/EconomicPrimitives.js +55 -0
- package/dist/traits/EconomicPrimitives.js.map +1 -0
- package/dist/traits/EconomicTraits.cjs +471 -0
- package/dist/traits/EconomicTraits.cjs.map +1 -0
- package/dist/traits/EconomicTraits.d.ts +71 -0
- package/dist/traits/EconomicTraits.d.ts.map +1 -0
- package/dist/traits/EconomicTraits.js +17 -0
- package/dist/traits/EconomicTraits.js.map +1 -0
- package/dist/traits/IoTTraits.d.ts +14 -0
- package/dist/traits/IoTTraits.d.ts.map +1 -0
- package/dist/traits/SimulationLabPrimitives.d.ts +187 -0
- package/dist/traits/SimulationLabPrimitives.d.ts.map +1 -0
- package/dist/traits/SimulationLabTraits.d.ts +42 -0
- package/dist/traits/SimulationLabTraits.d.ts.map +1 -0
- package/dist/traits/VRRTraits.d.ts +150 -0
- package/dist/traits/VRRTraits.d.ts.map +1 -0
- package/dist/traits/__tests__/ARTraits.test.d.ts +2 -0
- package/dist/traits/__tests__/ARTraits.test.d.ts.map +1 -0
- package/dist/traits/__tests__/EconomicPrimitives.test.d.ts +2 -0
- package/dist/traits/__tests__/EconomicPrimitives.test.d.ts.map +1 -0
- package/dist/traits/__tests__/EconomicTraits.test.d.ts +2 -0
- package/dist/traits/__tests__/EconomicTraits.test.d.ts.map +1 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/error-utf8.log +6 -0
- package/error.log +0 -0
- package/package.json +42 -19
- package/src/__tests__/EconomicPrimitives.test.ts +690 -0
- package/src/__tests__/EconomicTraits.test.ts +425 -0
- package/src/__tests__/SimulationLabPrimitives.test.ts +415 -0
- package/src/__tests__/collections.test.ts +182 -0
- package/src/__tests__/events.test.ts +135 -0
- package/src/__tests__/index.test.ts +14 -0
- package/src/__tests__/materials.test.ts +84 -0
- package/src/__tests__/math.test.ts +246 -0
- package/src/__tests__/physics.test.ts +83 -0
- package/src/__tests__/spatial.test.ts +333 -0
- package/src/__tests__/standard-library-fundamentals.test.ts +1301 -0
- package/src/__tests__/string-and-time-utilities.test.ts +1070 -0
- package/src/__tests__/string-decoupled.test.ts +14 -0
- package/src/__tests__/string.test.ts +164 -0
- package/src/__tests__/time.test.ts +110 -0
- package/src/collections.ts +8 -2
- package/src/events.ts +88 -0
- package/src/index.ts +161 -11
- package/src/materials.ts +109 -0
- package/src/math.ts +30 -14
- package/src/physics.ts +141 -0
- package/src/spatial.ts +320 -0
- package/src/string.basic.test.ts +14 -0
- package/src/string.test.ts +335 -0
- package/src/string.ts +45 -13
- package/src/time.ts +10 -11
- package/src/traits/ARTraits.ts +103 -0
- package/src/traits/EconomicPrimitives.ts +755 -0
- package/src/traits/EconomicTraits.ts +552 -0
- package/src/traits/IoTTraits.ts +102 -0
- package/src/traits/SimulationLabPrimitives.ts +650 -0
- package/src/traits/SimulationLabTraits.ts +191 -0
- package/src/traits/VRRTraits.ts +326 -0
- package/src/traits/__tests__/ARTraits.test.ts +14 -0
- package/src/traits/__tests__/EconomicPrimitives.test.ts +14 -0
- package/src/traits/__tests__/EconomicTraits.test.ts +14 -0
- package/src/types.ts +47 -12
- package/std_error.log +5 -0
- package/tsup.config.ts +17 -0
- package/vitest.config.ts +10 -0
- package/dist/types.js +0 -198
- package/dist/types.js.map +0 -1
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Auto-generated test for string-decoupled
|
|
4
|
+
// Source: packages/std/src/string.ts
|
|
5
|
+
|
|
6
|
+
describe('string-decoupled', () => {
|
|
7
|
+
it('should be defined', () => {
|
|
8
|
+
// TODO: Import and test string-decoupled
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should have basic functionality', () => {
|
|
12
|
+
// TODO: Add meaningful tests for string-decoupled
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
isBlank,
|
|
4
|
+
isNotBlank,
|
|
5
|
+
capitalize,
|
|
6
|
+
titleCase,
|
|
7
|
+
camelCase,
|
|
8
|
+
pascalCase,
|
|
9
|
+
snakeCase,
|
|
10
|
+
kebabCase,
|
|
11
|
+
constantCase,
|
|
12
|
+
} from '../string.js';
|
|
13
|
+
|
|
14
|
+
describe('isBlank', () => {
|
|
15
|
+
it('should return true for empty string', () => {
|
|
16
|
+
expect(isBlank('')).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should return true for whitespace only', () => {
|
|
20
|
+
expect(isBlank(' ')).toBe(true);
|
|
21
|
+
expect(isBlank('\t\n')).toBe(true);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should return false for non-empty string', () => {
|
|
25
|
+
expect(isBlank('hello')).toBe(false);
|
|
26
|
+
expect(isBlank(' hello ')).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('isNotBlank', () => {
|
|
31
|
+
it('should return false for empty string', () => {
|
|
32
|
+
expect(isNotBlank('')).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should return false for whitespace only', () => {
|
|
36
|
+
expect(isNotBlank(' ')).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should return true for non-empty string', () => {
|
|
40
|
+
expect(isNotBlank('hello')).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('capitalize', () => {
|
|
45
|
+
it('should capitalize first letter', () => {
|
|
46
|
+
expect(capitalize('hello')).toBe('Hello');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should handle empty string', () => {
|
|
50
|
+
expect(capitalize('')).toBe('');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should handle already capitalized', () => {
|
|
54
|
+
expect(capitalize('Hello')).toBe('Hello');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should handle single character', () => {
|
|
58
|
+
expect(capitalize('a')).toBe('A');
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('titleCase', () => {
|
|
63
|
+
it('should capitalize each word', () => {
|
|
64
|
+
expect(titleCase('hello world')).toBe('Hello World');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should handle multiple spaces', () => {
|
|
68
|
+
expect(titleCase('hello world')).toBe('Hello World');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should handle single word', () => {
|
|
72
|
+
expect(titleCase('hello')).toBe('Hello');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('camelCase', () => {
|
|
77
|
+
it('should convert space-separated to camelCase', () => {
|
|
78
|
+
expect(camelCase('hello world')).toBe('helloWorld');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should convert kebab-case to camelCase', () => {
|
|
82
|
+
expect(camelCase('hello-world')).toBe('helloWorld');
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should convert snake_case to camelCase', () => {
|
|
86
|
+
expect(camelCase('hello_world')).toBe('helloWorld');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should lowercase first letter of PascalCase', () => {
|
|
90
|
+
expect(camelCase('HelloWorld')).toBe('helloWorld');
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('should handle empty string', () => {
|
|
94
|
+
expect(camelCase('')).toBe('');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe('pascalCase', () => {
|
|
99
|
+
it('should convert space-separated to PascalCase', () => {
|
|
100
|
+
expect(pascalCase('hello world')).toBe('HelloWorld');
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it('should convert kebab-case to PascalCase', () => {
|
|
104
|
+
expect(pascalCase('hello-world')).toBe('HelloWorld');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should convert snake_case to PascalCase', () => {
|
|
108
|
+
expect(pascalCase('hello_world')).toBe('HelloWorld');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should handle empty string', () => {
|
|
112
|
+
expect(pascalCase('')).toBe('');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('snakeCase', () => {
|
|
117
|
+
it('should convert space-separated to snake_case', () => {
|
|
118
|
+
expect(snakeCase('hello world')).toBe('hello_world');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should convert camelCase to snake_case', () => {
|
|
122
|
+
expect(snakeCase('helloWorld')).toBe('hello_world');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should convert PascalCase to snake_case', () => {
|
|
126
|
+
expect(snakeCase('HelloWorld')).toBe('hello_world');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should convert kebab-case to snake_case', () => {
|
|
130
|
+
expect(snakeCase('hello-world')).toBe('hello_world');
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
describe('kebabCase', () => {
|
|
135
|
+
it('should convert space-separated to kebab-case', () => {
|
|
136
|
+
expect(kebabCase('hello world')).toBe('hello-world');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should convert camelCase to kebab-case', () => {
|
|
140
|
+
expect(kebabCase('helloWorld')).toBe('hello-world');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should convert PascalCase to kebab-case', () => {
|
|
144
|
+
expect(kebabCase('HelloWorld')).toBe('hello-world');
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should convert snake_case to kebab-case', () => {
|
|
148
|
+
expect(kebabCase('hello_world')).toBe('hello-world');
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe('constantCase', () => {
|
|
153
|
+
it('should convert to SCREAMING_SNAKE_CASE', () => {
|
|
154
|
+
expect(constantCase('hello world')).toBe('HELLO_WORLD');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should convert camelCase to SCREAMING_SNAKE_CASE', () => {
|
|
158
|
+
expect(constantCase('helloWorld')).toBe('HELLO_WORLD');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should convert kebab-case to SCREAMING_SNAKE_CASE', () => {
|
|
162
|
+
expect(constantCase('hello-world')).toBe('HELLO_WORLD');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { now, hrTime, sleep, withTimeout } from '../time.js';
|
|
3
|
+
|
|
4
|
+
describe('now', () => {
|
|
5
|
+
it('should return current timestamp in milliseconds', () => {
|
|
6
|
+
const before = Date.now();
|
|
7
|
+
const result = now();
|
|
8
|
+
const after = Date.now();
|
|
9
|
+
|
|
10
|
+
expect(result).toBeGreaterThanOrEqual(before);
|
|
11
|
+
expect(result).toBeLessThanOrEqual(after);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should return a number', () => {
|
|
15
|
+
expect(typeof now()).toBe('number');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('hrTime', () => {
|
|
20
|
+
it('should return high-resolution timestamp', () => {
|
|
21
|
+
const result = hrTime();
|
|
22
|
+
expect(typeof result).toBe('number');
|
|
23
|
+
expect(result).toBeGreaterThanOrEqual(0);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should increase over time', async () => {
|
|
27
|
+
const t1 = hrTime();
|
|
28
|
+
await sleep(10);
|
|
29
|
+
const t2 = hrTime();
|
|
30
|
+
expect(t2).toBeGreaterThan(t1);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('sleep', () => {
|
|
35
|
+
beforeEach(() => {
|
|
36
|
+
vi.useFakeTimers();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
afterEach(() => {
|
|
40
|
+
vi.useRealTimers();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should return a promise', () => {
|
|
44
|
+
const result = sleep(100);
|
|
45
|
+
expect(result).toBeInstanceOf(Promise);
|
|
46
|
+
vi.runAllTimers();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should resolve after specified time', async () => {
|
|
50
|
+
let resolved = false;
|
|
51
|
+
const promise = sleep(1000).then(() => {
|
|
52
|
+
resolved = true;
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(resolved).toBe(false);
|
|
56
|
+
|
|
57
|
+
vi.advanceTimersByTime(500);
|
|
58
|
+
await Promise.resolve();
|
|
59
|
+
expect(resolved).toBe(false);
|
|
60
|
+
|
|
61
|
+
vi.advanceTimersByTime(500);
|
|
62
|
+
await promise;
|
|
63
|
+
expect(resolved).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('withTimeout', () => {
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
vi.useFakeTimers();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
afterEach(() => {
|
|
73
|
+
vi.useRealTimers();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should resolve if function completes before timeout', async () => {
|
|
77
|
+
const fn = async () => {
|
|
78
|
+
await sleep(50);
|
|
79
|
+
return 'success';
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const promise = withTimeout(fn, 1000);
|
|
83
|
+
vi.advanceTimersByTime(50);
|
|
84
|
+
await vi.runAllTimersAsync();
|
|
85
|
+
|
|
86
|
+
const result = await promise;
|
|
87
|
+
expect(result).toBe('success');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should reject with Timeout error if function takes too long', async () => {
|
|
91
|
+
const fn = async () => {
|
|
92
|
+
await sleep(2000);
|
|
93
|
+
return 'success';
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const promise = withTimeout(fn, 100);
|
|
97
|
+
vi.advanceTimersByTime(100);
|
|
98
|
+
|
|
99
|
+
await expect(promise).rejects.toThrow('Timeout');
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('time utilities - real timers', () => {
|
|
104
|
+
it('sleep should actually wait (short duration)', async () => {
|
|
105
|
+
const start = Date.now();
|
|
106
|
+
await sleep(50);
|
|
107
|
+
const elapsed = Date.now() - start;
|
|
108
|
+
expect(elapsed).toBeGreaterThanOrEqual(40); // Allow some tolerance
|
|
109
|
+
});
|
|
110
|
+
});
|
package/src/collections.ts
CHANGED
|
@@ -825,10 +825,16 @@ export class PriorityQueue<T> {
|
|
|
825
825
|
const rightChild = 2 * index + 2;
|
|
826
826
|
let smallest = index;
|
|
827
827
|
|
|
828
|
-
if (
|
|
828
|
+
if (
|
|
829
|
+
leftChild < this.heap.length &&
|
|
830
|
+
this.compareFn(this.heap[leftChild].priority, this.heap[smallest].priority) < 0
|
|
831
|
+
) {
|
|
829
832
|
smallest = leftChild;
|
|
830
833
|
}
|
|
831
|
-
if (
|
|
834
|
+
if (
|
|
835
|
+
rightChild < this.heap.length &&
|
|
836
|
+
this.compareFn(this.heap[rightChild].priority, this.heap[smallest].priority) < 0
|
|
837
|
+
) {
|
|
832
838
|
smallest = rightChild;
|
|
833
839
|
}
|
|
834
840
|
|
package/src/events.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @holoscript/std — Events Module
|
|
3
|
+
*
|
|
4
|
+
* Provides a typed event bus for HoloScript compositions.
|
|
5
|
+
* Supports emit, on, once, off, and wildcard listeners.
|
|
6
|
+
*
|
|
7
|
+
* @version 0.2.0
|
|
8
|
+
* @module @holoscript/std/events
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export type EventHandler<T = any> = (data: T) => void;
|
|
12
|
+
|
|
13
|
+
interface Listener {
|
|
14
|
+
handler: EventHandler;
|
|
15
|
+
once: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class EventBus {
|
|
19
|
+
private listeners: Map<string, Listener[]> = new Map();
|
|
20
|
+
private wildcardListeners: Listener[] = [];
|
|
21
|
+
|
|
22
|
+
/** Register an event listener. */
|
|
23
|
+
on<T = any>(event: string, handler: EventHandler<T>): () => void {
|
|
24
|
+
if (!this.listeners.has(event)) this.listeners.set(event, []);
|
|
25
|
+
const listener: Listener = { handler, once: false };
|
|
26
|
+
this.listeners.get(event)!.push(listener);
|
|
27
|
+
return () => this.off(event, handler);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Register a one-time event listener. */
|
|
31
|
+
once<T = any>(event: string, handler: EventHandler<T>): () => void {
|
|
32
|
+
if (!this.listeners.has(event)) this.listeners.set(event, []);
|
|
33
|
+
const listener: Listener = { handler, once: true };
|
|
34
|
+
this.listeners.get(event)!.push(listener);
|
|
35
|
+
return () => this.off(event, handler);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Remove an event listener. */
|
|
39
|
+
off(event: string, handler: EventHandler): void {
|
|
40
|
+
const list = this.listeners.get(event);
|
|
41
|
+
if (!list) return;
|
|
42
|
+
this.listeners.set(
|
|
43
|
+
event,
|
|
44
|
+
list.filter((l) => l.handler !== handler)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Emit an event to all registered listeners. */
|
|
49
|
+
emit<T = any>(event: string, data?: T): void {
|
|
50
|
+
// Fire specific listeners
|
|
51
|
+
const list = this.listeners.get(event);
|
|
52
|
+
if (list) {
|
|
53
|
+
const remaining: Listener[] = [];
|
|
54
|
+
for (const l of list) {
|
|
55
|
+
l.handler(data);
|
|
56
|
+
if (!l.once) remaining.push(l);
|
|
57
|
+
}
|
|
58
|
+
this.listeners.set(event, remaining);
|
|
59
|
+
}
|
|
60
|
+
// Fire wildcard listeners
|
|
61
|
+
for (const l of this.wildcardListeners) {
|
|
62
|
+
l.handler({ event, data });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Listen to all events. */
|
|
67
|
+
onAny(handler: EventHandler<{ event: string; data: any }>): () => void {
|
|
68
|
+
const listener: Listener = { handler, once: false };
|
|
69
|
+
this.wildcardListeners.push(listener);
|
|
70
|
+
return () => {
|
|
71
|
+
this.wildcardListeners = this.wildcardListeners.filter((l) => l !== listener);
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Remove all listeners. */
|
|
76
|
+
clear(): void {
|
|
77
|
+
this.listeners.clear();
|
|
78
|
+
this.wildcardListeners = [];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Get count of listeners for an event (or all events). */
|
|
82
|
+
listenerCount(event?: string): number {
|
|
83
|
+
if (event) return (this.listeners.get(event) || []).length;
|
|
84
|
+
let total = this.wildcardListeners.length;
|
|
85
|
+
for (const [, list] of this.listeners) total += list.length;
|
|
86
|
+
return total;
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,25 +2,62 @@
|
|
|
2
2
|
* @holoscript/std - Standard Library for HoloScript Plus
|
|
3
3
|
*
|
|
4
4
|
* Provides core types, math utilities, collections, string operations,
|
|
5
|
-
*
|
|
5
|
+
* time management, spatial math, physics primitives, materials, and events
|
|
6
|
+
* for HoloScript Plus programs.
|
|
6
7
|
*
|
|
7
8
|
* @example
|
|
8
9
|
* ```hsplus
|
|
9
|
-
* import { Vec3,
|
|
10
|
+
* import { Vec3, createPBRMaterial, EventBus } from "@holoscript/std";
|
|
10
11
|
*
|
|
11
12
|
* let position = Vec3(0, 1, 0);
|
|
12
|
-
* let
|
|
13
|
-
*
|
|
14
|
-
* async fn main() {
|
|
15
|
-
* await sleep(1000);
|
|
16
|
-
* print("Done!");
|
|
17
|
-
* }
|
|
13
|
+
* let steel = createPBRMaterial("Steel", "metal");
|
|
14
|
+
* let bus = new EventBus();
|
|
18
15
|
* ```
|
|
19
16
|
*/
|
|
20
17
|
|
|
21
18
|
// Re-export everything from types.js
|
|
22
19
|
export * from './types.js';
|
|
23
20
|
|
|
21
|
+
// Spatial math (v4.2)
|
|
22
|
+
export {
|
|
23
|
+
Vec3,
|
|
24
|
+
Quaternion,
|
|
25
|
+
Transform,
|
|
26
|
+
Ray,
|
|
27
|
+
AABB,
|
|
28
|
+
distance,
|
|
29
|
+
lerp as spatialLerp,
|
|
30
|
+
clamp as spatialClamp,
|
|
31
|
+
degToRad as spatialDegToRad,
|
|
32
|
+
radToDeg as spatialRadToDeg,
|
|
33
|
+
} from './spatial.js';
|
|
34
|
+
|
|
35
|
+
// Physics primitives (v4.2)
|
|
36
|
+
export {
|
|
37
|
+
createBoxCollider,
|
|
38
|
+
createSphereCollider,
|
|
39
|
+
createCapsuleCollider,
|
|
40
|
+
createRigidbody,
|
|
41
|
+
} from './physics.js';
|
|
42
|
+
export type {
|
|
43
|
+
ColliderConfig,
|
|
44
|
+
ColliderShapeType,
|
|
45
|
+
RigidbodyConfig,
|
|
46
|
+
ForceFieldConfig,
|
|
47
|
+
ForceFieldType,
|
|
48
|
+
JointConfig,
|
|
49
|
+
JointType,
|
|
50
|
+
RaycastHit,
|
|
51
|
+
} from './physics.js';
|
|
52
|
+
|
|
53
|
+
// Materials (v4.2)
|
|
54
|
+
export { MATERIAL_PRESETS, createPBRMaterial } from './materials.js';
|
|
55
|
+
export type { PBRMaterial, UnlitMaterial, TextureMapType, TextureConfig } from './materials.js';
|
|
56
|
+
|
|
57
|
+
// Events (v4.2)
|
|
58
|
+
export { EventBus } from './events.js';
|
|
59
|
+
export type { EventHandler } from './events.js';
|
|
60
|
+
|
|
24
61
|
// Math utilities - export objects from math.ts
|
|
25
62
|
export {
|
|
26
63
|
// Constants
|
|
@@ -120,8 +157,114 @@ export {
|
|
|
120
157
|
wordWrap,
|
|
121
158
|
levenshtein,
|
|
122
159
|
similarity,
|
|
160
|
+
extractTraits,
|
|
123
161
|
} from './string.js';
|
|
124
162
|
|
|
163
|
+
// Economic primitives (v4.3)
|
|
164
|
+
export {
|
|
165
|
+
// Tradeable
|
|
166
|
+
generateTxHash,
|
|
167
|
+
executeTrade,
|
|
168
|
+
// Depreciation
|
|
169
|
+
calculateDepreciation,
|
|
170
|
+
depreciatedValue,
|
|
171
|
+
isDestroyed,
|
|
172
|
+
calculateRepairCost,
|
|
173
|
+
DEFAULT_DEPRECIATION,
|
|
174
|
+
// Bonding curves
|
|
175
|
+
bondingCurvePrice,
|
|
176
|
+
bondingCurveBuyCost,
|
|
177
|
+
bondingCurveSellRefund,
|
|
178
|
+
spatialPrice,
|
|
179
|
+
DEFAULT_BONDING_CURVE,
|
|
180
|
+
// Wealth taxation
|
|
181
|
+
calculateTaxRate,
|
|
182
|
+
calculateTaxAmount,
|
|
183
|
+
calculateRedistribution,
|
|
184
|
+
DEFAULT_WEALTH_TAX,
|
|
185
|
+
// PID control
|
|
186
|
+
createPIDState,
|
|
187
|
+
updatePID,
|
|
188
|
+
createDualLoopPIDState,
|
|
189
|
+
updateDualLoopPID,
|
|
190
|
+
DEFAULT_PID,
|
|
191
|
+
// Faucet-sink tracking
|
|
192
|
+
createFaucetSinkMetrics,
|
|
193
|
+
recordFaucet,
|
|
194
|
+
recordSink,
|
|
195
|
+
resetMetricsPeriod,
|
|
196
|
+
} from './traits/EconomicPrimitives.js';
|
|
197
|
+
export type {
|
|
198
|
+
Currency,
|
|
199
|
+
AgentID,
|
|
200
|
+
EconomicResult,
|
|
201
|
+
EconomicError,
|
|
202
|
+
EconomicPermission,
|
|
203
|
+
OwnershipRecord,
|
|
204
|
+
TransferRecord,
|
|
205
|
+
DepreciationConfig,
|
|
206
|
+
BondingCurveType,
|
|
207
|
+
BondingCurveConfig,
|
|
208
|
+
WealthTaxConfig,
|
|
209
|
+
PIDConfig,
|
|
210
|
+
PIDState,
|
|
211
|
+
DualLoopPIDConfig,
|
|
212
|
+
DualLoopPIDState,
|
|
213
|
+
FaucetSinkMetrics,
|
|
214
|
+
} from './traits/EconomicPrimitives.js';
|
|
215
|
+
|
|
216
|
+
// Economic traits (v4.3)
|
|
217
|
+
export {
|
|
218
|
+
EconomicTraits,
|
|
219
|
+
getEconomicTraitNames,
|
|
220
|
+
getEconomicTrait,
|
|
221
|
+
validateTraitComposition,
|
|
222
|
+
getRequiredPermissions,
|
|
223
|
+
} from './traits/EconomicTraits.js';
|
|
224
|
+
export type { EconomicTraitDefinition } from './traits/EconomicTraits.js';
|
|
225
|
+
|
|
226
|
+
// SimulationLab primitives (v4.3)
|
|
227
|
+
export {
|
|
228
|
+
// Statistics
|
|
229
|
+
mean,
|
|
230
|
+
variance,
|
|
231
|
+
standardDeviation,
|
|
232
|
+
standardError,
|
|
233
|
+
cohensD,
|
|
234
|
+
// Statistical tests
|
|
235
|
+
tTest,
|
|
236
|
+
oneSampleTTest,
|
|
237
|
+
mannWhitneyU,
|
|
238
|
+
chiSquaredTest,
|
|
239
|
+
// Parameter sweeps
|
|
240
|
+
expandSweep,
|
|
241
|
+
generateSweepCombinations,
|
|
242
|
+
isParameterRange,
|
|
243
|
+
// Metric aggregation
|
|
244
|
+
extractMetric,
|
|
245
|
+
groupByParameter,
|
|
246
|
+
summarizeMetrics,
|
|
247
|
+
} from './traits/SimulationLabPrimitives.js';
|
|
248
|
+
export type {
|
|
249
|
+
Hypothesis,
|
|
250
|
+
HypothesisDirection,
|
|
251
|
+
SimulationStatus,
|
|
252
|
+
ParameterRange,
|
|
253
|
+
ParameterSet,
|
|
254
|
+
ParameterSweep,
|
|
255
|
+
SimulationMetrics,
|
|
256
|
+
StatisticalResult,
|
|
257
|
+
ExperimentResult,
|
|
258
|
+
} from './traits/SimulationLabPrimitives.js';
|
|
259
|
+
|
|
260
|
+
// SimulationLab traits (v4.3)
|
|
261
|
+
export {
|
|
262
|
+
SimulationLabTraits,
|
|
263
|
+
getSimulationTraitNames,
|
|
264
|
+
getSimulationTrait,
|
|
265
|
+
} from './traits/SimulationLabTraits.js';
|
|
266
|
+
export type { SimulationTraitDefinition } from './traits/SimulationLabTraits.js';
|
|
267
|
+
|
|
125
268
|
// Time utilities
|
|
126
269
|
export {
|
|
127
270
|
now,
|
|
@@ -178,7 +321,10 @@ export function assert(condition: boolean, message?: string): asserts condition
|
|
|
178
321
|
/**
|
|
179
322
|
* Assert a value is not null or undefined
|
|
180
323
|
*/
|
|
181
|
-
export function assertDefined<T>(
|
|
324
|
+
export function assertDefined<T>(
|
|
325
|
+
value: T | null | undefined,
|
|
326
|
+
message?: string
|
|
327
|
+
): asserts value is T {
|
|
182
328
|
if (value === null || value === undefined) {
|
|
183
329
|
throw new Error(message ?? 'Value is null or undefined');
|
|
184
330
|
}
|
|
@@ -266,7 +412,7 @@ export function equals(a: unknown, b: unknown): boolean {
|
|
|
266
412
|
return true;
|
|
267
413
|
}
|
|
268
414
|
|
|
269
|
-
const keysA = Object.keys(a
|
|
415
|
+
const keysA = Object.keys(a);
|
|
270
416
|
const keysB = Object.keys(b as object);
|
|
271
417
|
if (keysA.length !== keysB.length) return false;
|
|
272
418
|
|
|
@@ -299,7 +445,11 @@ export function pipe(value: unknown, ...fns: ((x: unknown) => unknown)[]): unkno
|
|
|
299
445
|
export function compose<A>(): (a: A) => A;
|
|
300
446
|
export function compose<A, B>(fn1: (a: A) => B): (a: A) => B;
|
|
301
447
|
export function compose<A, B, C>(fn2: (b: B) => C, fn1: (a: A) => B): (a: A) => C;
|
|
302
|
-
export function compose<A, B, C, D>(
|
|
448
|
+
export function compose<A, B, C, D>(
|
|
449
|
+
fn3: (c: C) => D,
|
|
450
|
+
fn2: (b: B) => C,
|
|
451
|
+
fn1: (a: A) => B
|
|
452
|
+
): (a: A) => D;
|
|
303
453
|
export function compose(...fns: ((x: unknown) => unknown)[]): (x: unknown) => unknown {
|
|
304
454
|
return (value: unknown) => fns.reduceRight((acc, fn) => fn(acc), value);
|
|
305
455
|
}
|