@hazeljs/core 0.2.0-beta.1
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/README.md +522 -0
- package/dist/__tests__/container.test.d.ts +2 -0
- package/dist/__tests__/container.test.d.ts.map +1 -0
- package/dist/__tests__/container.test.js +454 -0
- package/dist/__tests__/decorators.test.d.ts +2 -0
- package/dist/__tests__/decorators.test.d.ts.map +1 -0
- package/dist/__tests__/decorators.test.js +693 -0
- package/dist/__tests__/errors/http.error.test.d.ts +2 -0
- package/dist/__tests__/errors/http.error.test.d.ts.map +1 -0
- package/dist/__tests__/errors/http.error.test.js +117 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts +2 -0
- package/dist/__tests__/filters/exception-filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/exception-filter.test.js +135 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts +2 -0
- package/dist/__tests__/filters/http-exception.filter.test.d.ts.map +1 -0
- package/dist/__tests__/filters/http-exception.filter.test.js +119 -0
- package/dist/__tests__/hazel-app.test.d.ts +2 -0
- package/dist/__tests__/hazel-app.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-app.test.js +682 -0
- package/dist/__tests__/hazel-module.test.d.ts +2 -0
- package/dist/__tests__/hazel-module.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-module.test.js +408 -0
- package/dist/__tests__/hazel-response.test.d.ts +2 -0
- package/dist/__tests__/hazel-response.test.d.ts.map +1 -0
- package/dist/__tests__/hazel-response.test.js +138 -0
- package/dist/__tests__/health.test.d.ts +2 -0
- package/dist/__tests__/health.test.d.ts.map +1 -0
- package/dist/__tests__/health.test.js +147 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.js +239 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts +2 -0
- package/dist/__tests__/interceptors/interceptor.test.d.ts.map +1 -0
- package/dist/__tests__/interceptors/interceptor.test.js +166 -0
- package/dist/__tests__/logger.test.d.ts +2 -0
- package/dist/__tests__/logger.test.d.ts.map +1 -0
- package/dist/__tests__/logger.test.js +141 -0
- package/dist/__tests__/middleware/cors.test.d.ts +2 -0
- package/dist/__tests__/middleware/cors.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/cors.test.js +129 -0
- package/dist/__tests__/middleware/csrf.test.d.ts +2 -0
- package/dist/__tests__/middleware/csrf.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/csrf.test.js +247 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware/global-middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/global-middleware.test.js +259 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts +2 -0
- package/dist/__tests__/middleware/rate-limit.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/rate-limit.test.js +264 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts +2 -0
- package/dist/__tests__/middleware/security-headers.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/security-headers.test.js +229 -0
- package/dist/__tests__/middleware/timeout.test.d.ts +2 -0
- package/dist/__tests__/middleware/timeout.test.d.ts.map +1 -0
- package/dist/__tests__/middleware/timeout.test.js +132 -0
- package/dist/__tests__/middleware.test.d.ts +2 -0
- package/dist/__tests__/middleware.test.d.ts.map +1 -0
- package/dist/__tests__/middleware.test.js +180 -0
- package/dist/__tests__/pipes/pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/pipe.test.js +245 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts +2 -0
- package/dist/__tests__/pipes/validation.pipe.test.d.ts.map +1 -0
- package/dist/__tests__/pipes/validation.pipe.test.js +297 -0
- package/dist/__tests__/request-parser.test.d.ts +2 -0
- package/dist/__tests__/request-parser.test.d.ts.map +1 -0
- package/dist/__tests__/request-parser.test.js +182 -0
- package/dist/__tests__/router.test.d.ts +2 -0
- package/dist/__tests__/router.test.d.ts.map +1 -0
- package/dist/__tests__/router.test.js +680 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts +2 -0
- package/dist/__tests__/routing/route-matcher.test.d.ts.map +1 -0
- package/dist/__tests__/routing/route-matcher.test.js +219 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts +2 -0
- package/dist/__tests__/routing/version.decorator.test.d.ts.map +1 -0
- package/dist/__tests__/routing/version.decorator.test.js +298 -0
- package/dist/__tests__/service.test.d.ts +2 -0
- package/dist/__tests__/service.test.d.ts.map +1 -0
- package/dist/__tests__/service.test.js +121 -0
- package/dist/__tests__/shutdown.test.d.ts +2 -0
- package/dist/__tests__/shutdown.test.d.ts.map +1 -0
- package/dist/__tests__/shutdown.test.js +250 -0
- package/dist/__tests__/testing/testing.module.test.d.ts +2 -0
- package/dist/__tests__/testing/testing.module.test.d.ts.map +1 -0
- package/dist/__tests__/testing/testing.module.test.js +370 -0
- package/dist/__tests__/upload/file-upload.test.d.ts +2 -0
- package/dist/__tests__/upload/file-upload.test.d.ts.map +1 -0
- package/dist/__tests__/upload/file-upload.test.js +498 -0
- package/dist/__tests__/utils/sanitize.test.d.ts +2 -0
- package/dist/__tests__/utils/sanitize.test.d.ts.map +1 -0
- package/dist/__tests__/utils/sanitize.test.js +291 -0
- package/dist/__tests__/validator.test.d.ts +2 -0
- package/dist/__tests__/validator.test.d.ts.map +1 -0
- package/dist/__tests__/validator.test.js +300 -0
- package/dist/container.d.ts +80 -0
- package/dist/container.d.ts.map +1 -0
- package/dist/container.js +271 -0
- package/dist/decorators.d.ts +92 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +343 -0
- package/dist/errors/http.error.d.ts +31 -0
- package/dist/errors/http.error.d.ts.map +1 -0
- package/dist/errors/http.error.js +62 -0
- package/dist/filters/exception-filter.d.ts +39 -0
- package/dist/filters/exception-filter.d.ts.map +1 -0
- package/dist/filters/exception-filter.js +38 -0
- package/dist/filters/http-exception.filter.d.ts +9 -0
- package/dist/filters/http-exception.filter.d.ts.map +1 -0
- package/dist/filters/http-exception.filter.js +42 -0
- package/dist/hazel-app.d.ts +78 -0
- package/dist/hazel-app.d.ts.map +1 -0
- package/dist/hazel-app.js +453 -0
- package/dist/hazel-module.d.ts +20 -0
- package/dist/hazel-module.d.ts.map +1 -0
- package/dist/hazel-module.js +109 -0
- package/dist/hazel-response.d.ts +20 -0
- package/dist/hazel-response.d.ts.map +1 -0
- package/dist/hazel-response.js +68 -0
- package/dist/health.d.ts +73 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +174 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +140 -0
- package/dist/interceptors/interceptor.d.ts +22 -0
- package/dist/interceptors/interceptor.d.ts.map +1 -0
- package/dist/interceptors/interceptor.js +46 -0
- package/dist/logger.d.ts +8 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +238 -0
- package/dist/middleware/cors.middleware.d.ts +44 -0
- package/dist/middleware/cors.middleware.d.ts.map +1 -0
- package/dist/middleware/cors.middleware.js +118 -0
- package/dist/middleware/csrf.middleware.d.ts +82 -0
- package/dist/middleware/csrf.middleware.d.ts.map +1 -0
- package/dist/middleware/csrf.middleware.js +183 -0
- package/dist/middleware/global-middleware.d.ts +111 -0
- package/dist/middleware/global-middleware.d.ts.map +1 -0
- package/dist/middleware/global-middleware.js +179 -0
- package/dist/middleware/rate-limit.middleware.d.ts +73 -0
- package/dist/middleware/rate-limit.middleware.d.ts.map +1 -0
- package/dist/middleware/rate-limit.middleware.js +124 -0
- package/dist/middleware/security-headers.middleware.d.ts +76 -0
- package/dist/middleware/security-headers.middleware.d.ts.map +1 -0
- package/dist/middleware/security-headers.middleware.js +123 -0
- package/dist/middleware/timeout.middleware.d.ts +25 -0
- package/dist/middleware/timeout.middleware.d.ts.map +1 -0
- package/dist/middleware/timeout.middleware.js +74 -0
- package/dist/middleware.d.ts +13 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +47 -0
- package/dist/pipes/pipe.d.ts +50 -0
- package/dist/pipes/pipe.d.ts.map +1 -0
- package/dist/pipes/pipe.js +96 -0
- package/dist/pipes/validation.pipe.d.ts +6 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +61 -0
- package/dist/request-context.d.ts +17 -0
- package/dist/request-context.d.ts.map +1 -0
- package/dist/request-context.js +2 -0
- package/dist/request-parser.d.ts +7 -0
- package/dist/request-parser.d.ts.map +1 -0
- package/dist/request-parser.js +60 -0
- package/dist/router.d.ts +33 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +426 -0
- package/dist/routing/route-matcher.d.ts +39 -0
- package/dist/routing/route-matcher.d.ts.map +1 -0
- package/dist/routing/route-matcher.js +93 -0
- package/dist/routing/version.decorator.d.ts +36 -0
- package/dist/routing/version.decorator.d.ts.map +1 -0
- package/dist/routing/version.decorator.js +89 -0
- package/dist/service.d.ts +9 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +39 -0
- package/dist/shutdown.d.ts +32 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +109 -0
- package/dist/testing/testing.module.d.ts +83 -0
- package/dist/testing/testing.module.d.ts.map +1 -0
- package/dist/testing/testing.module.js +164 -0
- package/dist/types.d.ts +76 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/upload/file-upload.d.ts +75 -0
- package/dist/upload/file-upload.d.ts.map +1 -0
- package/dist/upload/file-upload.js +261 -0
- package/dist/utils/sanitize.d.ts +45 -0
- package/dist/utils/sanitize.d.ts.map +1 -0
- package/dist/utils/sanitize.js +165 -0
- package/dist/validator.d.ts +7 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +119 -0
- package/package.json +65 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const sanitize_1 = require("../../utils/sanitize");
|
|
4
|
+
describe('Sanitize Utilities', () => {
|
|
5
|
+
describe('sanitizeHtml', () => {
|
|
6
|
+
it('should remove script tags', () => {
|
|
7
|
+
const input = '<div>Hello <script>alert("xss")</script> World</div>';
|
|
8
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
9
|
+
expect(result).not.toContain('<script>');
|
|
10
|
+
expect(result).toContain('Hello');
|
|
11
|
+
expect(result).toContain('World');
|
|
12
|
+
});
|
|
13
|
+
it('should remove iframe tags', () => {
|
|
14
|
+
const input = '<div>Content <iframe src="evil.com"></iframe></div>';
|
|
15
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
16
|
+
expect(result).not.toContain('<iframe>');
|
|
17
|
+
});
|
|
18
|
+
it('should remove event handlers', () => {
|
|
19
|
+
const input = '<div onclick="alert(\'xss\')">Click me</div>';
|
|
20
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
21
|
+
expect(result).not.toContain('onclick');
|
|
22
|
+
});
|
|
23
|
+
it('should remove javascript: protocol', () => {
|
|
24
|
+
const input = '<a href="javascript:alert(\'xss\')">Link</a>';
|
|
25
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
26
|
+
expect(result).not.toContain('javascript:');
|
|
27
|
+
});
|
|
28
|
+
it('should remove data:text/html', () => {
|
|
29
|
+
const input = '<a href="data:text/html,<script>alert(\'xss\')</script>">Link</a>';
|
|
30
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
31
|
+
expect(result).not.toContain('data:text/html');
|
|
32
|
+
});
|
|
33
|
+
it('should handle non-string input', () => {
|
|
34
|
+
const result = (0, sanitize_1.sanitizeHtml)(123);
|
|
35
|
+
expect(result).toBe('123');
|
|
36
|
+
});
|
|
37
|
+
it('should preserve safe HTML', () => {
|
|
38
|
+
const input = '<div><p>Safe content</p></div>';
|
|
39
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
40
|
+
expect(result).toContain('<div>');
|
|
41
|
+
expect(result).toContain('<p>');
|
|
42
|
+
expect(result).toContain('Safe content');
|
|
43
|
+
});
|
|
44
|
+
it('should remove multiple script tags', () => {
|
|
45
|
+
const input = '<script>bad1</script>Content<script>bad2</script>';
|
|
46
|
+
const result = (0, sanitize_1.sanitizeHtml)(input);
|
|
47
|
+
expect(result).not.toContain('<script>');
|
|
48
|
+
expect(result).toContain('Content');
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('sanitizeString', () => {
|
|
52
|
+
it('should remove control characters', () => {
|
|
53
|
+
const input = 'Hello\x00\x01World';
|
|
54
|
+
const result = (0, sanitize_1.sanitizeString)(input);
|
|
55
|
+
expect(result).toBe('HelloWorld');
|
|
56
|
+
});
|
|
57
|
+
it('should trim whitespace', () => {
|
|
58
|
+
const input = ' Hello World ';
|
|
59
|
+
const result = (0, sanitize_1.sanitizeString)(input);
|
|
60
|
+
expect(result).toBe('Hello World');
|
|
61
|
+
});
|
|
62
|
+
it('should normalize multiple spaces', () => {
|
|
63
|
+
const input = 'Hello World';
|
|
64
|
+
const result = (0, sanitize_1.sanitizeString)(input);
|
|
65
|
+
expect(result).toBe('Hello World');
|
|
66
|
+
});
|
|
67
|
+
it('should handle tabs and newlines', () => {
|
|
68
|
+
const input = 'Hello\t\nWorld';
|
|
69
|
+
const result = (0, sanitize_1.sanitizeString)(input);
|
|
70
|
+
// Tabs and newlines are normalized to single space
|
|
71
|
+
expect(result).toContain('Hello');
|
|
72
|
+
expect(result).toContain('World');
|
|
73
|
+
});
|
|
74
|
+
it('should handle non-string input', () => {
|
|
75
|
+
const result = (0, sanitize_1.sanitizeString)(456);
|
|
76
|
+
expect(result).toBe('456');
|
|
77
|
+
});
|
|
78
|
+
it('should handle empty string', () => {
|
|
79
|
+
const result = (0, sanitize_1.sanitizeString)('');
|
|
80
|
+
expect(result).toBe('');
|
|
81
|
+
});
|
|
82
|
+
it('should remove all control characters', () => {
|
|
83
|
+
const input = '\x00\x01\x02\x03Hello\x7F\x80\x9F';
|
|
84
|
+
const result = (0, sanitize_1.sanitizeString)(input);
|
|
85
|
+
expect(result).toBe('Hello');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('sanitizeUrl', () => {
|
|
89
|
+
it('should allow valid http URL', () => {
|
|
90
|
+
const input = 'http://example.com';
|
|
91
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
92
|
+
expect(result).toBe('http://example.com/');
|
|
93
|
+
});
|
|
94
|
+
it('should allow valid https URL', () => {
|
|
95
|
+
const input = 'https://example.com';
|
|
96
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
97
|
+
expect(result).toBe('https://example.com/');
|
|
98
|
+
});
|
|
99
|
+
it('should reject javascript: protocol', () => {
|
|
100
|
+
const input = 'javascript:alert("xss")';
|
|
101
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
102
|
+
expect(result).toBe('');
|
|
103
|
+
});
|
|
104
|
+
it('should reject data: protocol', () => {
|
|
105
|
+
const input = 'data:text/html,<script>alert("xss")</script>';
|
|
106
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
107
|
+
expect(result).toBe('');
|
|
108
|
+
});
|
|
109
|
+
it('should reject file: protocol', () => {
|
|
110
|
+
const input = 'file:///etc/passwd';
|
|
111
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
112
|
+
expect(result).toBe('');
|
|
113
|
+
});
|
|
114
|
+
it('should handle invalid URL', () => {
|
|
115
|
+
const input = 'not a url';
|
|
116
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
117
|
+
expect(result).toBe('');
|
|
118
|
+
});
|
|
119
|
+
it('should handle non-string input', () => {
|
|
120
|
+
const result = (0, sanitize_1.sanitizeUrl)(123);
|
|
121
|
+
expect(result).toBe('');
|
|
122
|
+
});
|
|
123
|
+
it('should preserve URL with path and query', () => {
|
|
124
|
+
const input = 'https://example.com/path?query=value';
|
|
125
|
+
const result = (0, sanitize_1.sanitizeUrl)(input);
|
|
126
|
+
expect(result).toContain('example.com');
|
|
127
|
+
expect(result).toContain('/path');
|
|
128
|
+
expect(result).toContain('query=value');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('sanitizeEmail', () => {
|
|
132
|
+
it('should accept valid email', () => {
|
|
133
|
+
const input = 'user@example.com';
|
|
134
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
135
|
+
expect(result).toBe('user@example.com');
|
|
136
|
+
});
|
|
137
|
+
it('should convert to lowercase', () => {
|
|
138
|
+
const input = 'User@Example.COM';
|
|
139
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
140
|
+
expect(result).toBe('user@example.com');
|
|
141
|
+
});
|
|
142
|
+
it('should trim whitespace', () => {
|
|
143
|
+
const input = ' user@example.com ';
|
|
144
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
145
|
+
expect(result).toBe('user@example.com');
|
|
146
|
+
});
|
|
147
|
+
it('should reject invalid email', () => {
|
|
148
|
+
const input = 'not-an-email';
|
|
149
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
150
|
+
expect(result).toBe('');
|
|
151
|
+
});
|
|
152
|
+
it('should reject email without @', () => {
|
|
153
|
+
const input = 'userexample.com';
|
|
154
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
155
|
+
expect(result).toBe('');
|
|
156
|
+
});
|
|
157
|
+
it('should reject email without domain', () => {
|
|
158
|
+
const input = 'user@';
|
|
159
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
160
|
+
expect(result).toBe('');
|
|
161
|
+
});
|
|
162
|
+
it('should handle non-string input', () => {
|
|
163
|
+
const result = (0, sanitize_1.sanitizeEmail)(123);
|
|
164
|
+
expect(result).toBe('');
|
|
165
|
+
});
|
|
166
|
+
it('should accept email with subdomain', () => {
|
|
167
|
+
const input = 'user@mail.example.com';
|
|
168
|
+
const result = (0, sanitize_1.sanitizeEmail)(input);
|
|
169
|
+
expect(result).toBe('user@mail.example.com');
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
describe('sanitizeSql', () => {
|
|
173
|
+
it('should escape single quotes', () => {
|
|
174
|
+
const input = "O'Reilly";
|
|
175
|
+
const result = (0, sanitize_1.sanitizeSql)(input);
|
|
176
|
+
expect(result).toBe("O''Reilly");
|
|
177
|
+
});
|
|
178
|
+
it('should remove semicolons', () => {
|
|
179
|
+
const input = 'DROP TABLE users;';
|
|
180
|
+
const result = (0, sanitize_1.sanitizeSql)(input);
|
|
181
|
+
expect(result).not.toContain(';');
|
|
182
|
+
});
|
|
183
|
+
it('should remove SQL comments', () => {
|
|
184
|
+
const input = 'SELECT * FROM users -- comment';
|
|
185
|
+
const result = (0, sanitize_1.sanitizeSql)(input);
|
|
186
|
+
expect(result).not.toContain('--');
|
|
187
|
+
});
|
|
188
|
+
it('should remove block comments', () => {
|
|
189
|
+
const input = 'SELECT * /* comment */ FROM users';
|
|
190
|
+
const result = (0, sanitize_1.sanitizeSql)(input);
|
|
191
|
+
expect(result).not.toContain('/*');
|
|
192
|
+
expect(result).not.toContain('*/');
|
|
193
|
+
});
|
|
194
|
+
it('should handle non-string input', () => {
|
|
195
|
+
const result = (0, sanitize_1.sanitizeSql)(123);
|
|
196
|
+
expect(result).toBe('');
|
|
197
|
+
});
|
|
198
|
+
it('should handle multiple dangerous characters', () => {
|
|
199
|
+
const input = "'; DROP TABLE users; --";
|
|
200
|
+
const result = (0, sanitize_1.sanitizeSql)(input);
|
|
201
|
+
expect(result).toBe("'' DROP TABLE users ");
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
describe('sanitizeObject', () => {
|
|
205
|
+
it('should sanitize string values in object', () => {
|
|
206
|
+
const input = {
|
|
207
|
+
name: ' John ',
|
|
208
|
+
email: 'JOHN@EXAMPLE.COM',
|
|
209
|
+
};
|
|
210
|
+
const result = (0, sanitize_1.sanitizeObject)(input);
|
|
211
|
+
expect(result.name).toBe('John');
|
|
212
|
+
expect(result.email).toBe('JOHN@EXAMPLE.COM');
|
|
213
|
+
});
|
|
214
|
+
it('should handle nested objects', () => {
|
|
215
|
+
const input = {
|
|
216
|
+
user: {
|
|
217
|
+
name: ' Jane ',
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
const result = (0, sanitize_1.sanitizeObject)(input);
|
|
221
|
+
expect(result.user.name).toBe('Jane');
|
|
222
|
+
});
|
|
223
|
+
it('should preserve non-string values', () => {
|
|
224
|
+
const input = {
|
|
225
|
+
name: 'John',
|
|
226
|
+
age: 30,
|
|
227
|
+
active: true,
|
|
228
|
+
};
|
|
229
|
+
const result = (0, sanitize_1.sanitizeObject)(input);
|
|
230
|
+
expect(result.age).toBe(30);
|
|
231
|
+
expect(result.active).toBe(true);
|
|
232
|
+
});
|
|
233
|
+
it('should handle arrays in objects', () => {
|
|
234
|
+
const input = {
|
|
235
|
+
tags: [' tag1 ', ' tag2 '],
|
|
236
|
+
};
|
|
237
|
+
const result = (0, sanitize_1.sanitizeObject)(input);
|
|
238
|
+
expect(result.tags[0]).toBe('tag1');
|
|
239
|
+
expect(result.tags[1]).toBe('tag2');
|
|
240
|
+
});
|
|
241
|
+
it('should handle null values', () => {
|
|
242
|
+
const input = {
|
|
243
|
+
name: 'John',
|
|
244
|
+
email: null,
|
|
245
|
+
};
|
|
246
|
+
const result = (0, sanitize_1.sanitizeObject)(input);
|
|
247
|
+
expect(result.email).toBeNull();
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
describe('escapeHtml', () => {
|
|
251
|
+
it('should escape HTML entities', () => {
|
|
252
|
+
const input = '<div>Hello & "World"</div>';
|
|
253
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
254
|
+
expect(result).toBe('<div>Hello & "World"</div>');
|
|
255
|
+
});
|
|
256
|
+
it('should escape ampersand', () => {
|
|
257
|
+
const input = 'Tom & Jerry';
|
|
258
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
259
|
+
expect(result).toBe('Tom & Jerry');
|
|
260
|
+
});
|
|
261
|
+
it('should escape less than', () => {
|
|
262
|
+
const input = '5 < 10';
|
|
263
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
264
|
+
expect(result).toBe('5 < 10');
|
|
265
|
+
});
|
|
266
|
+
it('should escape greater than', () => {
|
|
267
|
+
const input = '10 > 5';
|
|
268
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
269
|
+
expect(result).toBe('10 > 5');
|
|
270
|
+
});
|
|
271
|
+
it('should escape double quotes', () => {
|
|
272
|
+
const input = 'He said "Hello"';
|
|
273
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
274
|
+
expect(result).toBe('He said "Hello"');
|
|
275
|
+
});
|
|
276
|
+
it('should escape single quotes', () => {
|
|
277
|
+
const input = "It's working";
|
|
278
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
279
|
+
expect(result).toBe('It's working');
|
|
280
|
+
});
|
|
281
|
+
it('should handle non-string input', () => {
|
|
282
|
+
const result = (0, sanitize_1.escapeHtml)(123);
|
|
283
|
+
expect(result).toBe('123');
|
|
284
|
+
});
|
|
285
|
+
it('should escape all special characters', () => {
|
|
286
|
+
const input = `<>&"'`;
|
|
287
|
+
const result = (0, sanitize_1.escapeHtml)(input);
|
|
288
|
+
expect(result).toBe('<>&"'');
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/validator.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const validator_1 = require("../validator");
|
|
4
|
+
describe('Validator', () => {
|
|
5
|
+
describe('required validation', () => {
|
|
6
|
+
it('should validate required fields', () => {
|
|
7
|
+
const schema = {
|
|
8
|
+
name: { type: 'string', required: true },
|
|
9
|
+
};
|
|
10
|
+
const errors = validator_1.Validator.validate({}, schema);
|
|
11
|
+
expect(errors).toHaveLength(1);
|
|
12
|
+
expect(errors[0]).toEqual({
|
|
13
|
+
field: 'name',
|
|
14
|
+
message: 'name is required',
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
it('should reject null values for required fields', () => {
|
|
18
|
+
const schema = {
|
|
19
|
+
email: { type: 'string', required: true },
|
|
20
|
+
};
|
|
21
|
+
const errors = validator_1.Validator.validate({ email: null }, schema);
|
|
22
|
+
expect(errors).toHaveLength(1);
|
|
23
|
+
expect(errors[0].field).toBe('email');
|
|
24
|
+
});
|
|
25
|
+
it('should reject empty strings for required fields', () => {
|
|
26
|
+
const schema = {
|
|
27
|
+
username: { type: 'string', required: true },
|
|
28
|
+
};
|
|
29
|
+
const errors = validator_1.Validator.validate({ username: '' }, schema);
|
|
30
|
+
expect(errors).toHaveLength(1);
|
|
31
|
+
});
|
|
32
|
+
it('should pass when required field is present', () => {
|
|
33
|
+
const schema = {
|
|
34
|
+
name: { type: 'string', required: true },
|
|
35
|
+
};
|
|
36
|
+
const errors = validator_1.Validator.validate({ name: 'John' }, schema);
|
|
37
|
+
expect(errors).toHaveLength(0);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe('string validation', () => {
|
|
41
|
+
it('should validate string type', () => {
|
|
42
|
+
const schema = {
|
|
43
|
+
name: { type: 'string' },
|
|
44
|
+
};
|
|
45
|
+
const errors = validator_1.Validator.validate({ name: 123 }, schema);
|
|
46
|
+
expect(errors).toHaveLength(1);
|
|
47
|
+
expect(errors[0].message).toBe('name must be a string');
|
|
48
|
+
});
|
|
49
|
+
it('should validate minimum length', () => {
|
|
50
|
+
const schema = {
|
|
51
|
+
password: { type: 'string', min: 8 },
|
|
52
|
+
};
|
|
53
|
+
const errors = validator_1.Validator.validate({ password: 'short' }, schema);
|
|
54
|
+
expect(errors).toHaveLength(1);
|
|
55
|
+
expect(errors[0].message).toBe('password must be at least 8 characters');
|
|
56
|
+
});
|
|
57
|
+
it('should validate maximum length', () => {
|
|
58
|
+
const schema = {
|
|
59
|
+
username: { type: 'string', max: 10 },
|
|
60
|
+
};
|
|
61
|
+
const errors = validator_1.Validator.validate({ username: 'verylongusername' }, schema);
|
|
62
|
+
expect(errors).toHaveLength(1);
|
|
63
|
+
expect(errors[0].message).toBe('username must be at most 10 characters');
|
|
64
|
+
});
|
|
65
|
+
it('should validate pattern', () => {
|
|
66
|
+
const schema = {
|
|
67
|
+
email: { type: 'string', pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ },
|
|
68
|
+
};
|
|
69
|
+
const errors = validator_1.Validator.validate({ email: 'invalid-email' }, schema);
|
|
70
|
+
expect(errors).toHaveLength(1);
|
|
71
|
+
expect(errors[0].message).toBe('email has invalid format');
|
|
72
|
+
});
|
|
73
|
+
it('should pass valid string', () => {
|
|
74
|
+
const schema = {
|
|
75
|
+
name: { type: 'string', min: 2, max: 50 },
|
|
76
|
+
};
|
|
77
|
+
const errors = validator_1.Validator.validate({ name: 'John Doe' }, schema);
|
|
78
|
+
expect(errors).toHaveLength(0);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe('number validation', () => {
|
|
82
|
+
it('should validate number type', () => {
|
|
83
|
+
const schema = {
|
|
84
|
+
age: { type: 'number' },
|
|
85
|
+
};
|
|
86
|
+
const errors = validator_1.Validator.validate({ age: '25' }, schema);
|
|
87
|
+
expect(errors).toHaveLength(1);
|
|
88
|
+
expect(errors[0].message).toBe('age must be a number');
|
|
89
|
+
});
|
|
90
|
+
it('should validate minimum value', () => {
|
|
91
|
+
const schema = {
|
|
92
|
+
age: { type: 'number', min: 18 },
|
|
93
|
+
};
|
|
94
|
+
const errors = validator_1.Validator.validate({ age: 16 }, schema);
|
|
95
|
+
expect(errors).toHaveLength(1);
|
|
96
|
+
expect(errors[0].message).toBe('age must be at least 18');
|
|
97
|
+
});
|
|
98
|
+
it('should validate maximum value', () => {
|
|
99
|
+
const schema = {
|
|
100
|
+
percentage: { type: 'number', max: 100 },
|
|
101
|
+
};
|
|
102
|
+
const errors = validator_1.Validator.validate({ percentage: 150 }, schema);
|
|
103
|
+
expect(errors).toHaveLength(1);
|
|
104
|
+
expect(errors[0].message).toBe('percentage must be at most 100');
|
|
105
|
+
});
|
|
106
|
+
it('should pass valid number', () => {
|
|
107
|
+
const schema = {
|
|
108
|
+
score: { type: 'number', min: 0, max: 100 },
|
|
109
|
+
};
|
|
110
|
+
const errors = validator_1.Validator.validate({ score: 85 }, schema);
|
|
111
|
+
expect(errors).toHaveLength(0);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('boolean validation', () => {
|
|
115
|
+
it('should validate boolean type', () => {
|
|
116
|
+
const schema = {
|
|
117
|
+
active: { type: 'boolean' },
|
|
118
|
+
};
|
|
119
|
+
const errors = validator_1.Validator.validate({ active: 'true' }, schema);
|
|
120
|
+
expect(errors).toHaveLength(1);
|
|
121
|
+
expect(errors[0].message).toBe('active must be a boolean');
|
|
122
|
+
});
|
|
123
|
+
it('should pass valid boolean', () => {
|
|
124
|
+
const schema = {
|
|
125
|
+
active: { type: 'boolean' },
|
|
126
|
+
};
|
|
127
|
+
const errors = validator_1.Validator.validate({ active: true }, schema);
|
|
128
|
+
expect(errors).toHaveLength(0);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
describe('object validation', () => {
|
|
132
|
+
it('should validate object type', () => {
|
|
133
|
+
const schema = {
|
|
134
|
+
user: { type: 'object' },
|
|
135
|
+
};
|
|
136
|
+
const errors = validator_1.Validator.validate({ user: 'not an object' }, schema);
|
|
137
|
+
expect(errors).toHaveLength(1);
|
|
138
|
+
expect(errors[0].message).toBe('user must be an object');
|
|
139
|
+
});
|
|
140
|
+
it('should reject arrays as objects', () => {
|
|
141
|
+
const schema = {
|
|
142
|
+
user: { type: 'object' },
|
|
143
|
+
};
|
|
144
|
+
const errors = validator_1.Validator.validate({ user: [] }, schema);
|
|
145
|
+
expect(errors).toHaveLength(1);
|
|
146
|
+
expect(errors[0].message).toBe('user must be an object');
|
|
147
|
+
});
|
|
148
|
+
it('should validate nested properties', () => {
|
|
149
|
+
const schema = {
|
|
150
|
+
user: {
|
|
151
|
+
type: 'object',
|
|
152
|
+
properties: {
|
|
153
|
+
name: { type: 'string', required: true },
|
|
154
|
+
age: { type: 'number', min: 0 },
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
const errors = validator_1.Validator.validate({
|
|
159
|
+
user: {
|
|
160
|
+
age: -5,
|
|
161
|
+
},
|
|
162
|
+
}, schema);
|
|
163
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
164
|
+
expect(errors.some((e) => e.field === 'name')).toBe(true);
|
|
165
|
+
expect(errors.some((e) => e.field === 'age')).toBe(true);
|
|
166
|
+
});
|
|
167
|
+
it('should pass valid nested object', () => {
|
|
168
|
+
const schema = {
|
|
169
|
+
user: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
name: { type: 'string', required: true },
|
|
173
|
+
age: { type: 'number', min: 0 },
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
const errors = validator_1.Validator.validate({
|
|
178
|
+
user: {
|
|
179
|
+
name: 'John',
|
|
180
|
+
age: 25,
|
|
181
|
+
},
|
|
182
|
+
}, schema);
|
|
183
|
+
expect(errors).toHaveLength(0);
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
describe('array validation', () => {
|
|
187
|
+
it('should validate array type', () => {
|
|
188
|
+
const schema = {
|
|
189
|
+
tags: { type: 'array' },
|
|
190
|
+
};
|
|
191
|
+
const errors = validator_1.Validator.validate({ tags: 'not an array' }, schema);
|
|
192
|
+
expect(errors).toHaveLength(1);
|
|
193
|
+
expect(errors[0].message).toBe('tags must be an array');
|
|
194
|
+
});
|
|
195
|
+
it('should validate array items', () => {
|
|
196
|
+
const schema = {
|
|
197
|
+
scores: {
|
|
198
|
+
type: 'array',
|
|
199
|
+
items: { type: 'number', min: 0, max: 100 },
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
const errors = validator_1.Validator.validate({ scores: [50, 150, -10] }, schema);
|
|
203
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
204
|
+
});
|
|
205
|
+
it('should pass valid array', () => {
|
|
206
|
+
const schema = {
|
|
207
|
+
tags: {
|
|
208
|
+
type: 'array',
|
|
209
|
+
items: { type: 'string' },
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
const errors = validator_1.Validator.validate({ tags: ['tag1', 'tag2', 'tag3'] }, schema);
|
|
213
|
+
expect(errors).toHaveLength(0);
|
|
214
|
+
});
|
|
215
|
+
it('should validate array without item schema', () => {
|
|
216
|
+
const schema = {
|
|
217
|
+
items: { type: 'array' },
|
|
218
|
+
};
|
|
219
|
+
const errors = validator_1.Validator.validate({ items: [1, 'two', true] }, schema);
|
|
220
|
+
expect(errors).toHaveLength(0);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
describe('optional fields', () => {
|
|
224
|
+
it('should skip validation for undefined optional fields', () => {
|
|
225
|
+
const schema = {
|
|
226
|
+
name: { type: 'string', required: true },
|
|
227
|
+
age: { type: 'number' },
|
|
228
|
+
};
|
|
229
|
+
const errors = validator_1.Validator.validate({ name: 'John' }, schema);
|
|
230
|
+
expect(errors).toHaveLength(0);
|
|
231
|
+
});
|
|
232
|
+
it('should skip validation for null optional fields', () => {
|
|
233
|
+
const schema = {
|
|
234
|
+
bio: { type: 'string', max: 500 },
|
|
235
|
+
};
|
|
236
|
+
const errors = validator_1.Validator.validate({ bio: null }, schema);
|
|
237
|
+
expect(errors).toHaveLength(0);
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe('complex validation scenarios', () => {
|
|
241
|
+
it('should validate multiple fields with multiple errors', () => {
|
|
242
|
+
const schema = {
|
|
243
|
+
username: { type: 'string', required: true, min: 3, max: 20 },
|
|
244
|
+
email: { type: 'string', required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ },
|
|
245
|
+
age: { type: 'number', min: 18, max: 120 },
|
|
246
|
+
};
|
|
247
|
+
const errors = validator_1.Validator.validate({
|
|
248
|
+
username: 'ab',
|
|
249
|
+
email: 'invalid',
|
|
250
|
+
age: 15,
|
|
251
|
+
}, schema);
|
|
252
|
+
expect(errors.length).toBe(3);
|
|
253
|
+
});
|
|
254
|
+
it('should validate deeply nested objects', () => {
|
|
255
|
+
const schema = {
|
|
256
|
+
profile: {
|
|
257
|
+
type: 'object',
|
|
258
|
+
properties: {
|
|
259
|
+
address: {
|
|
260
|
+
type: 'object',
|
|
261
|
+
properties: {
|
|
262
|
+
street: { type: 'string', required: true },
|
|
263
|
+
city: { type: 'string', required: true },
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
const errors = validator_1.Validator.validate({
|
|
270
|
+
profile: {
|
|
271
|
+
address: {
|
|
272
|
+
street: '123 Main St',
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
}, schema);
|
|
276
|
+
expect(errors.some((e) => e.field === 'city')).toBe(true);
|
|
277
|
+
});
|
|
278
|
+
it('should validate arrays of objects', () => {
|
|
279
|
+
const schema = {
|
|
280
|
+
users: {
|
|
281
|
+
type: 'array',
|
|
282
|
+
items: {
|
|
283
|
+
type: 'object',
|
|
284
|
+
properties: {
|
|
285
|
+
name: { type: 'string', required: true },
|
|
286
|
+
email: { type: 'string', required: true },
|
|
287
|
+
},
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
const errors = validator_1.Validator.validate({
|
|
292
|
+
users: [
|
|
293
|
+
{ name: 'John', email: 'john@example.com' },
|
|
294
|
+
{ name: 'Jane' }, // missing email
|
|
295
|
+
],
|
|
296
|
+
}, schema);
|
|
297
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Type } from './types';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
export declare enum Scope {
|
|
4
|
+
SINGLETON = "singleton",
|
|
5
|
+
TRANSIENT = "transient",
|
|
6
|
+
REQUEST = "request"
|
|
7
|
+
}
|
|
8
|
+
export type InjectionToken<T = unknown> = string | symbol | Type<T>;
|
|
9
|
+
export interface Provider<T = unknown> {
|
|
10
|
+
token: InjectionToken<T>;
|
|
11
|
+
useClass?: Type<T>;
|
|
12
|
+
useValue?: T;
|
|
13
|
+
useFactory?: (...args: unknown[]) => T | Promise<T>;
|
|
14
|
+
scope?: Scope;
|
|
15
|
+
inject?: InjectionToken[];
|
|
16
|
+
}
|
|
17
|
+
export declare class Container {
|
|
18
|
+
private static instance;
|
|
19
|
+
private providers;
|
|
20
|
+
private requestScopedProviders;
|
|
21
|
+
private constructor();
|
|
22
|
+
static getInstance(): Container;
|
|
23
|
+
/**
|
|
24
|
+
* Create a new container instance (for testing)
|
|
25
|
+
*/
|
|
26
|
+
static createTestInstance(): Container;
|
|
27
|
+
/**
|
|
28
|
+
* Register a provider with the container
|
|
29
|
+
*/
|
|
30
|
+
register<T>(token: InjectionToken<T>, provider: T | Provider<T>, scope?: Scope): void;
|
|
31
|
+
/**
|
|
32
|
+
* Register a provider configuration
|
|
33
|
+
*/
|
|
34
|
+
registerProvider<T>(provider: Provider<T>): void;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a dependency from the container
|
|
37
|
+
*/
|
|
38
|
+
resolve<T>(token: InjectionToken<T>, requestId?: string, resolutionStack?: Set<InjectionToken>): T;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve from provider metadata
|
|
41
|
+
*/
|
|
42
|
+
private resolveFromMetadata;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve request-scoped provider
|
|
45
|
+
*/
|
|
46
|
+
private resolveRequestScoped;
|
|
47
|
+
/**
|
|
48
|
+
* Auto-resolve a class without explicit registration
|
|
49
|
+
*/
|
|
50
|
+
private autoResolve;
|
|
51
|
+
/**
|
|
52
|
+
* Create instance of a class with dependency injection
|
|
53
|
+
*/
|
|
54
|
+
private createInstance;
|
|
55
|
+
/**
|
|
56
|
+
* Clear request-scoped providers for a specific request
|
|
57
|
+
*/
|
|
58
|
+
clearRequestScope(requestId: string): void;
|
|
59
|
+
/**
|
|
60
|
+
* Clear all providers
|
|
61
|
+
*/
|
|
62
|
+
clear(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Check if a token is registered
|
|
65
|
+
*/
|
|
66
|
+
has(token: InjectionToken): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Get all registered tokens
|
|
69
|
+
*/
|
|
70
|
+
getTokens(): InjectionToken[];
|
|
71
|
+
/**
|
|
72
|
+
* Helper to get token name for logging
|
|
73
|
+
*/
|
|
74
|
+
private getTokenName;
|
|
75
|
+
/**
|
|
76
|
+
* Type guard to check if value is a Provider
|
|
77
|
+
*/
|
|
78
|
+
private isProvider;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAG1B,oBAAY,KAAK;IACf,SAAS,cAAc;IACvB,SAAS,cAAc;IACvB,OAAO,YAAY;CACpB;AAED,MAAM,MAAM,cAAc,CAAC,CAAC,GAAG,OAAO,IAAI,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAEpE,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO;IACnC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACzB,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,QAAQ,CAAC,EAAE,CAAC,CAAC;IACb,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B;AASD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,SAAS,CAAoD;IACrE,OAAO,CAAC,sBAAsB,CAAwD;IAGtF,OAAO;IAIP,MAAM,CAAC,WAAW,IAAI,SAAS;IAO/B;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,SAAS;IAItC;;OAEG;IACH,QAAQ,CAAC,CAAC,EACR,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EACxB,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,EACzB,KAAK,GAAE,KAAuB,GAC7B,IAAI;IAcP;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI;IAsBhD;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC;IA+BlG;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4D3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAyB5B;;OAEG;IACH,OAAO,CAAC,WAAW;IAqBnB;;OAEG;IACH,OAAO,CAAC,cAAc;IAuCtB;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAO1C;;OAEG;IACH,KAAK,IAAI,IAAI;IAMb;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO;IAInC;;OAEG;IACH,SAAS,IAAI,cAAc,EAAE;IAI7B;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,OAAO,CAAC,UAAU;CAGnB"}
|