jsgui3-server 0.0.138 → 0.0.140

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 (57) hide show
  1. package/AGENTS.md +87 -0
  2. package/README.md +12 -0
  3. package/docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md +19 -0
  4. package/docs/advanced-usage-examples.md +1360 -0
  5. package/docs/agent-development-guide.md +386 -0
  6. package/docs/api-reference.md +916 -0
  7. package/docs/broken-functionality-tracker.md +285 -0
  8. package/docs/bundling-system-deep-dive.md +525 -0
  9. package/docs/cli-reference.md +393 -0
  10. package/docs/comprehensive-documentation.md +1403 -0
  11. package/docs/configuration-reference.md +808 -0
  12. package/docs/controls-development.md +859 -0
  13. package/docs/documentation-review/CURRENT_REVIEW.md +95 -0
  14. package/docs/function-publishers-json-apis.md +847 -0
  15. package/docs/getting-started-with-json.md +518 -0
  16. package/docs/minification-compression-sourcemaps-status.md +482 -0
  17. package/docs/minification-compression-sourcemaps-test-results.md +205 -0
  18. package/docs/publishers-guide.md +313 -0
  19. package/docs/resources-guide.md +615 -0
  20. package/docs/serve-helpers.md +406 -0
  21. package/docs/simple-server-api-design.md +13 -0
  22. package/docs/system-architecture.md +275 -0
  23. package/docs/troubleshooting.md +698 -0
  24. package/examples/json/README.md +115 -0
  25. package/examples/json/basic-api/README.md +345 -0
  26. package/examples/json/basic-api/server.js +199 -0
  27. package/examples/json/simple-api/README.md +125 -0
  28. package/examples/json/simple-api/diagnostic-report.json +73 -0
  29. package/examples/json/simple-api/diagnostic-test.js +433 -0
  30. package/examples/json/simple-api/server-debug.md +58 -0
  31. package/examples/json/simple-api/server.js +91 -0
  32. package/examples/json/simple-api/test.js +215 -0
  33. package/http/responders/static/Static_Route_HTTP_Responder.js +1 -2
  34. package/package.json +19 -8
  35. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +65 -12
  36. package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +6 -1
  37. package/publishers/http-function-publisher.js +59 -38
  38. package/publishers/http-webpage-publisher.js +48 -1
  39. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +38 -146
  40. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +54 -5
  41. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +36 -4
  42. package/serve-factory.js +36 -9
  43. package/server.js +10 -4
  44. package/test-report.json +0 -0
  45. package/tests/README.md +250 -0
  46. package/tests/assigners.test.js +316 -0
  47. package/tests/bundlers.test.js +329 -0
  48. package/tests/configuration-validation.test.js +530 -0
  49. package/tests/content-analysis.test.js +641 -0
  50. package/tests/end-to-end.test.js +496 -0
  51. package/tests/error-handling.test.js +746 -0
  52. package/tests/performance.test.js +653 -0
  53. package/tests/publishers.test.js +395 -0
  54. package/tests/temp_invalid.js +7 -0
  55. package/tests/temp_invalid_utf8.js +1 -0
  56. package/tests/temp_malformed.js +10 -0
  57. package/tests/test-runner.js +261 -0
@@ -0,0 +1,395 @@
1
+ const assert = require('assert');
2
+ const { describe, it, beforeEach, afterEach } = require('mocha');
3
+
4
+ // Import publisher classes
5
+ const HTTP_Webpage_Publisher = require('../publishers/http-webpage-publisher');
6
+
7
+ describe('Publisher Component Isolation Tests', function() {
8
+ this.timeout(15000); // Increase timeout for publisher operations
9
+
10
+ let mockControl;
11
+ let mockWebpage;
12
+
13
+ beforeEach(function() {
14
+ // Create mock control class
15
+ mockControl = class MockControl {
16
+ constructor(spec) {
17
+ this.context = spec.context;
18
+ this.head = {
19
+ add: function(element) {
20
+ // Mock add method
21
+ }
22
+ };
23
+ this.body = {
24
+ add: function(element) {
25
+ // Mock add method
26
+ }
27
+ };
28
+ }
29
+
30
+ active() {
31
+ // Mock activation
32
+ }
33
+
34
+ all_html_render() {
35
+ return Promise.resolve(`<!DOCTYPE html>
36
+ <html>
37
+ <head><title>Test Page</title></head>
38
+ <body>
39
+ <div id="control-root">
40
+ <h1>Test Control</h1>
41
+ <p>This is a test control for publisher testing.</p>
42
+ </div>
43
+ <script src="/js/js.js"></script>
44
+ </body>
45
+ </html>`);
46
+ }
47
+ };
48
+
49
+ // Create mock webpage
50
+ mockWebpage = {
51
+ content: mockControl
52
+ };
53
+ });
54
+
55
+ describe('HTTP_Webpage_Publisher', function() {
56
+ it('should initialize with default configuration', function() {
57
+ const publisher = new HTTP_Webpage_Publisher({
58
+ webpage: mockWebpage
59
+ });
60
+
61
+ assert(publisher.webpage === mockWebpage, 'Should store webpage reference');
62
+ assert(publisher.bundler_config, 'Should initialize bundler config');
63
+ assert(publisher.static_routes_responses_webpage_bundle_preparer,
64
+ 'Should create bundle preparer');
65
+ });
66
+
67
+ it('should accept and validate bundler configuration', function() {
68
+ const validConfig = {
69
+ webpage: mockWebpage,
70
+ bundler: {
71
+ compression: {
72
+ enabled: true,
73
+ algorithms: ['gzip', 'br'],
74
+ threshold: 1024
75
+ },
76
+ minify: {
77
+ enabled: true,
78
+ level: 'normal'
79
+ },
80
+ sourcemaps: {
81
+ enabled: true,
82
+ format: 'inline'
83
+ }
84
+ }
85
+ };
86
+
87
+ const publisher = new HTTP_Webpage_Publisher(validConfig);
88
+ assert.deepStrictEqual(publisher.bundler_config, validConfig.bundler,
89
+ 'Should store valid bundler configuration');
90
+ });
91
+
92
+ it('should validate compression configuration - boolean enabled', function() {
93
+ assert.throws(() => {
94
+ new HTTP_Webpage_Publisher({
95
+ webpage: mockWebpage,
96
+ bundler: {
97
+ compression: {
98
+ enabled: 'invalid' // Should be boolean
99
+ }
100
+ }
101
+ });
102
+ }, /bundler\.compression\.enabled must be a boolean/);
103
+ });
104
+
105
+ it('should validate compression configuration - array algorithms', function() {
106
+ assert.throws(() => {
107
+ new HTTP_Webpage_Publisher({
108
+ webpage: mockWebpage,
109
+ bundler: {
110
+ compression: {
111
+ algorithms: 'invalid' // Should be array
112
+ }
113
+ }
114
+ });
115
+ }, /bundler\.compression\.algorithms must be an array/);
116
+ });
117
+
118
+ it('should validate compression configuration - valid algorithms', function() {
119
+ assert.throws(() => {
120
+ new HTTP_Webpage_Publisher({
121
+ webpage: mockWebpage,
122
+ bundler: {
123
+ compression: {
124
+ algorithms: ['gzip', 'invalid_algorithm']
125
+ }
126
+ }
127
+ });
128
+ }, /Invalid compression algorithm: invalid_algorithm/);
129
+ });
130
+
131
+ it('should validate compression configuration - threshold number', function() {
132
+ assert.throws(() => {
133
+ new HTTP_Webpage_Publisher({
134
+ webpage: mockWebpage,
135
+ bundler: {
136
+ compression: {
137
+ threshold: 'invalid' // Should be number
138
+ }
139
+ }
140
+ });
141
+ }, /bundler\.compression\.threshold must be a non-negative number/);
142
+ });
143
+
144
+ it('should validate compression configuration - negative threshold', function() {
145
+ assert.throws(() => {
146
+ new HTTP_Webpage_Publisher({
147
+ webpage: mockWebpage,
148
+ bundler: {
149
+ compression: {
150
+ threshold: -1 // Should be non-negative
151
+ }
152
+ }
153
+ });
154
+ }, /bundler\.compression\.threshold must be a non-negative number/);
155
+ });
156
+
157
+ it('should accept valid compression algorithms', function() {
158
+ const publisher = new HTTP_Webpage_Publisher({
159
+ webpage: mockWebpage,
160
+ bundler: {
161
+ compression: {
162
+ algorithms: ['gzip', 'br']
163
+ }
164
+ }
165
+ });
166
+
167
+ assert.deepStrictEqual(publisher.bundler_config.compression.algorithms, ['gzip', 'br']);
168
+ });
169
+
170
+ it('should initialize bundle preparer with configuration', function() {
171
+ const config = {
172
+ webpage: mockWebpage,
173
+ bundler: {
174
+ compression: {
175
+ enabled: true,
176
+ algorithms: ['gzip']
177
+ }
178
+ }
179
+ };
180
+
181
+ const publisher = new HTTP_Webpage_Publisher(config);
182
+
183
+ // Verify preparer was created with config
184
+ assert(publisher.static_routes_responses_webpage_bundle_preparer,
185
+ 'Should create bundle preparer');
186
+ assert.deepStrictEqual(
187
+ publisher.static_routes_responses_webpage_bundle_preparer.bundler_config,
188
+ config.bundler,
189
+ 'Preparer should receive bundler config'
190
+ );
191
+ });
192
+
193
+ it('should handle missing bundler configuration gracefully', function() {
194
+ const publisher = new HTTP_Webpage_Publisher({
195
+ webpage: mockWebpage
196
+ // No bundler config
197
+ });
198
+
199
+ assert.deepStrictEqual(publisher.bundler_config, {},
200
+ 'Should default to empty bundler config');
201
+ });
202
+
203
+ it('should handle missing compression configuration gracefully', function() {
204
+ const publisher = new HTTP_Webpage_Publisher({
205
+ webpage: mockWebpage,
206
+ bundler: {
207
+ // Empty bundler config
208
+ }
209
+ });
210
+
211
+ assert.deepStrictEqual(publisher.bundler_config, {});
212
+ });
213
+
214
+ it('should handle partial bundler configuration', function() {
215
+ const partialConfig = {
216
+ webpage: mockWebpage,
217
+ bundler: {
218
+ compression: {
219
+ enabled: true
220
+ // Missing other compression options
221
+ }
222
+ // Missing minify and sourcemaps
223
+ }
224
+ };
225
+
226
+ const publisher = new HTTP_Webpage_Publisher(partialConfig);
227
+
228
+ assert.strictEqual(publisher.bundler_config.compression.enabled, true);
229
+ assert(!publisher.bundler_config.minify, 'Should not have minify config');
230
+ assert(!publisher.bundler_config.sourcemaps, 'Should not have sourcemaps config');
231
+ });
232
+
233
+ it('should handle handle_http method', function() {
234
+ const publisher = new HTTP_Webpage_Publisher({
235
+ webpage: mockWebpage
236
+ });
237
+
238
+ // Mock request and response
239
+ const mockReq = {
240
+ url: '/test',
241
+ headers: {}
242
+ };
243
+
244
+ let responseWritten = false;
245
+ let statusCode = null;
246
+ let headers = {};
247
+
248
+ const mockRes = {
249
+ writeHead: function(code, h) {
250
+ statusCode = code;
251
+ headers = h;
252
+ },
253
+ end: function() {
254
+ responseWritten = true;
255
+ }
256
+ };
257
+
258
+ publisher.handle_http(mockReq, mockRes);
259
+
260
+ // Note: This test may need adjustment based on actual handle_http implementation
261
+ // For now, just verify it doesn't crash
262
+ assert(responseWritten || statusCode, 'Should handle HTTP request');
263
+ });
264
+
265
+ it('should pass configuration to bundle preparer correctly', function() {
266
+ const complexConfig = {
267
+ webpage: mockWebpage,
268
+ bundler: {
269
+ minify: {
270
+ enabled: true,
271
+ level: 'aggressive',
272
+ options: {
273
+ drop_console: true
274
+ }
275
+ },
276
+ sourcemaps: {
277
+ enabled: true,
278
+ format: 'inline',
279
+ includeInProduction: false
280
+ },
281
+ compression: {
282
+ enabled: true,
283
+ algorithms: ['br'],
284
+ brotli: { quality: 6 },
285
+ threshold: 2048
286
+ }
287
+ }
288
+ };
289
+
290
+ const publisher = new HTTP_Webpage_Publisher(complexConfig);
291
+
292
+ // Verify complex configuration is passed through
293
+ assert.deepStrictEqual(publisher.bundler_config, complexConfig.bundler);
294
+ assert.strictEqual(publisher.static_routes_responses_webpage_bundle_preparer.bundler_config,
295
+ complexConfig.bundler);
296
+ });
297
+
298
+ it('should handle configuration inheritance and defaults', function() {
299
+ // Test that defaults are applied when partial config is provided
300
+ const partialConfig = {
301
+ webpage: mockWebpage,
302
+ bundler: {
303
+ compression: {
304
+ // Only specify some options
305
+ enabled: true
306
+ }
307
+ }
308
+ };
309
+
310
+ const publisher = new HTTP_Webpage_Publisher(partialConfig);
311
+
312
+ // Should have the specified option
313
+ assert.strictEqual(publisher.bundler_config.compression.enabled, true);
314
+
315
+ // Should not have unspecified options (they will be undefined)
316
+ assert(!publisher.bundler_config.compression.algorithms,
317
+ 'Should not set default algorithms when not specified');
318
+ });
319
+ });
320
+
321
+ describe('Configuration Validation Edge Cases', function() {
322
+ it('should handle null/undefined webpage', function() {
323
+ // This might be allowed or not depending on implementation
324
+ const publisher = new HTTP_Webpage_Publisher({
325
+ // No webpage
326
+ });
327
+
328
+ assert(!publisher.webpage, 'Should handle missing webpage');
329
+ });
330
+
331
+ it('should handle empty bundler config object', function() {
332
+ const publisher = new HTTP_Webpage_Publisher({
333
+ webpage: mockWebpage,
334
+ bundler: {}
335
+ });
336
+
337
+ assert.deepStrictEqual(publisher.bundler_config, {});
338
+ });
339
+
340
+ it('should handle deeply nested configuration', function() {
341
+ const deepConfig = {
342
+ webpage: mockWebpage,
343
+ bundler: {
344
+ minify: {
345
+ options: {
346
+ compress: {
347
+ drop_console: true,
348
+ drop_debugger: true
349
+ }
350
+ }
351
+ }
352
+ }
353
+ };
354
+
355
+ const publisher = new HTTP_Webpage_Publisher(deepConfig);
356
+
357
+ assert.strictEqual(
358
+ publisher.bundler_config.minify.options.compress.drop_console,
359
+ true
360
+ );
361
+ assert.strictEqual(
362
+ publisher.bundler_config.minify.options.compress.drop_debugger,
363
+ true
364
+ );
365
+ });
366
+ });
367
+
368
+ describe('Integration with Static_Routes_Responses_Webpage_Bundle_Preparer', function() {
369
+ it('should create preparer with correct configuration', function() {
370
+ const config = {
371
+ webpage: mockWebpage,
372
+ bundler: {
373
+ compression: {
374
+ enabled: true,
375
+ algorithms: ['gzip']
376
+ }
377
+ }
378
+ };
379
+
380
+ const publisher = new HTTP_Webpage_Publisher(config);
381
+
382
+ const preparer = publisher.static_routes_responses_webpage_bundle_preparer;
383
+
384
+ // Verify preparer has the config
385
+ assert.strictEqual(preparer.bundler_config, config.bundler);
386
+
387
+ // Verify preparer creates compressed response buffers assigner with config
388
+ assert(preparer.compressed_response_buffers_assigner);
389
+ assert.strictEqual(
390
+ preparer.compressed_response_buffers_assigner.compression_config,
391
+ config.bundler.compression
392
+ );
393
+ });
394
+ });
395
+ });
@@ -0,0 +1,7 @@
1
+
2
+ function invalidFunction() {
3
+ // Missing closing brace and syntax error
4
+ console.log('invalid syntax'
5
+ return "this will never execute";
6
+ }
7
+
@@ -0,0 +1 @@
1
+ ���
@@ -0,0 +1,10 @@
1
+
2
+ const css = `
3
+ .test-class {
4
+ color: red;
5
+ /* Missing closing brace
6
+ background: blue
7
+ `;
8
+
9
+ console.log('test');
10
+
@@ -0,0 +1,261 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Comprehensive Test Runner for JSGUI3 Minification, Compression, and Sourcemaps
5
+ *
6
+ * This test runner executes all test suites and provides detailed reporting
7
+ * for the minification, compression, and sourcemap features.
8
+ */
9
+
10
+ const { spawn } = require('child_process');
11
+ const path = require('path');
12
+ const fs = require('fs').promises;
13
+
14
+ class TestRunner {
15
+ constructor() {
16
+ this.testResults = {
17
+ total: 0,
18
+ passed: 0,
19
+ failed: 0,
20
+ skipped: 0,
21
+ duration: 0,
22
+ suites: []
23
+ };
24
+
25
+ this.testFiles = [
26
+ 'bundlers.test.js',
27
+ 'assigners.test.js',
28
+ 'publishers.test.js',
29
+ 'configuration-validation.test.js',
30
+ 'end-to-end.test.js',
31
+ 'content-analysis.test.js',
32
+ 'performance.test.js',
33
+ 'error-handling.test.js'
34
+ ];
35
+ }
36
+
37
+ async runAllTests() {
38
+ console.log('šŸš€ Starting JSGUI3 Minification, Compression & Sourcemaps Test Suite\n');
39
+ console.log('=' .repeat(80));
40
+
41
+ const startTime = Date.now();
42
+
43
+ for (const testFile of this.testFiles) {
44
+ await this.runTestFile(testFile);
45
+ }
46
+
47
+ this.testResults.duration = Date.now() - startTime;
48
+
49
+ this.printSummary();
50
+ this.generateReport();
51
+
52
+ return this.testResults.failed === 0;
53
+ }
54
+
55
+ async runTestFile(testFile) {
56
+ const testPath = path.join(__dirname, testFile);
57
+
58
+ try {
59
+ await fs.access(testPath);
60
+ } catch (error) {
61
+ console.log(`āš ļø Skipping ${testFile} - file not found`);
62
+ this.testResults.suites.push({
63
+ name: testFile,
64
+ status: 'skipped',
65
+ error: 'File not found'
66
+ });
67
+ this.testResults.skipped++;
68
+ return;
69
+ }
70
+
71
+ console.log(`\nšŸ“‹ Running ${testFile}...`);
72
+
73
+ return new Promise((resolve) => {
74
+ const mocha = spawn('node', ['node_modules/mocha/bin/mocha.js', testPath, '--timeout', '30000', '--reporter', 'spec'], {
75
+ stdio: 'inherit',
76
+ cwd: process.cwd(),
77
+ env: { ...process.env, JSGUI_DEBUG: '0' }
78
+ });
79
+
80
+ let output = '';
81
+ let errorOutput = '';
82
+
83
+ mocha.stdout?.on('data', (data) => {
84
+ output += data.toString();
85
+ });
86
+
87
+ mocha.stderr?.on('data', (data) => {
88
+ errorOutput += data.toString();
89
+ });
90
+
91
+ mocha.on('close', (code) => {
92
+ const suiteResult = {
93
+ name: testFile,
94
+ status: code === 0 ? 'passed' : 'failed',
95
+ exitCode: code,
96
+ output: output,
97
+ errorOutput: errorOutput
98
+ };
99
+
100
+ this.testResults.suites.push(suiteResult);
101
+
102
+ if (code === 0) {
103
+ console.log(`āœ… ${testFile} passed`);
104
+ this.testResults.passed++;
105
+ } else {
106
+ console.log(`āŒ ${testFile} failed (exit code: ${code})`);
107
+ this.testResults.failed++;
108
+ }
109
+
110
+ this.testResults.total++;
111
+ resolve();
112
+ });
113
+
114
+ mocha.on('error', (error) => {
115
+ console.log(`āŒ ${testFile} error: ${error.message}`);
116
+ this.testResults.suites.push({
117
+ name: testFile,
118
+ status: 'error',
119
+ error: error.message
120
+ });
121
+ this.testResults.failed++;
122
+ this.testResults.total++;
123
+ resolve();
124
+ });
125
+ });
126
+ }
127
+
128
+ printSummary() {
129
+ console.log('\n' + '='.repeat(80));
130
+ console.log('šŸ“Š TEST SUMMARY');
131
+ console.log('='.repeat(80));
132
+
133
+ console.log(`Total Test Suites: ${this.testResults.total}`);
134
+ console.log(`āœ… Passed: ${this.testResults.passed}`);
135
+ console.log(`āŒ Failed: ${this.testResults.failed}`);
136
+ console.log(`āš ļø Skipped: ${this.testResults.skipped}`);
137
+ console.log(`ā±ļø Duration: ${(this.testResults.duration / 1000).toFixed(2)}s`);
138
+
139
+ const successRate = this.testResults.total > 0 ?
140
+ ((this.testResults.passed / this.testResults.total) * 100).toFixed(1) : 0;
141
+ console.log(`šŸ“ˆ Success Rate: ${successRate}%`);
142
+
143
+ if (this.testResults.failed > 0) {
144
+ console.log('\nāŒ Failed Test Suites:');
145
+ this.testResults.suites
146
+ .filter(suite => suite.status === 'failed' || suite.status === 'error')
147
+ .forEach(suite => {
148
+ console.log(` - ${suite.name}: ${suite.error || 'Exit code ' + suite.exitCode}`);
149
+ });
150
+ }
151
+
152
+ console.log('\n' + '='.repeat(80));
153
+
154
+ if (this.testResults.failed === 0) {
155
+ console.log('šŸŽ‰ All tests passed! The minification, compression, and sourcemap features are working correctly.');
156
+ } else {
157
+ console.log('āš ļø Some tests failed. Please review the implementation and fix the issues.');
158
+ }
159
+ }
160
+
161
+ async generateReport() {
162
+ const reportPath = path.join(__dirname, '..', 'test-report.json');
163
+
164
+ const report = {
165
+ timestamp: new Date().toISOString(),
166
+ summary: {
167
+ total: this.testResults.total,
168
+ passed: this.testResults.passed,
169
+ failed: this.testResults.failed,
170
+ skipped: this.testResults.skipped,
171
+ duration: this.testResults.duration,
172
+ successRate: this.testResults.total > 0 ?
173
+ ((this.testResults.passed / this.testResults.total) * 100).toFixed(1) : 0
174
+ },
175
+ suites: this.testResults.suites.map(suite => ({
176
+ name: suite.name,
177
+ status: suite.status,
178
+ exitCode: suite.exitCode,
179
+ error: suite.error
180
+ })),
181
+ environment: {
182
+ nodeVersion: process.version,
183
+ platform: process.platform,
184
+ arch: process.arch,
185
+ cwd: process.cwd()
186
+ }
187
+ };
188
+
189
+ try {
190
+ await fs.writeFile(reportPath, JSON.stringify(report, null, 2));
191
+ console.log(`šŸ“„ Detailed report saved to: ${reportPath}`);
192
+ } catch (error) {
193
+ console.log(`āš ļø Failed to save report: ${error.message}`);
194
+ }
195
+ }
196
+
197
+ async runSpecificTest(testName) {
198
+ if (!this.testFiles.includes(testName)) {
199
+ console.log(`āŒ Test file '${testName}' not found. Available tests:`);
200
+ this.testFiles.forEach(file => console.log(` - ${file}`));
201
+ return false;
202
+ }
203
+
204
+ console.log(`šŸŽÆ Running specific test: ${testName}\n`);
205
+ console.log('='.repeat(80));
206
+
207
+ const startTime = Date.now();
208
+ await this.runTestFile(testName);
209
+ this.testResults.duration = Date.now() - startTime;
210
+
211
+ this.printSummary();
212
+ this.generateReport();
213
+
214
+ return this.testResults.failed === 0;
215
+ }
216
+
217
+ async runWithOptions(options) {
218
+ if (options.debug) {
219
+ process.env.JSGUI_DEBUG = '1';
220
+ console.log('šŸ› Debug mode enabled');
221
+ }
222
+
223
+ if (options.verbose) {
224
+ console.log('šŸ“ Verbose output enabled');
225
+ }
226
+
227
+ if (options.specific) {
228
+ return await this.runSpecificTest(options.specific);
229
+ } else {
230
+ return await this.runAllTests();
231
+ }
232
+ }
233
+ }
234
+
235
+ // CLI Interface
236
+ async function main() {
237
+ const args = process.argv.slice(2);
238
+ const options = {
239
+ debug: args.includes('--debug'),
240
+ verbose: args.includes('--verbose'),
241
+ specific: args.find(arg => arg.startsWith('--test='))?.split('=')[1]
242
+ };
243
+
244
+ const runner = new TestRunner();
245
+
246
+ try {
247
+ const success = await runner.runWithOptions(options);
248
+ process.exit(success ? 0 : 1);
249
+ } catch (error) {
250
+ console.error('šŸ’„ Test runner failed:', error);
251
+ process.exit(1);
252
+ }
253
+ }
254
+
255
+ // Export for programmatic use
256
+ module.exports = TestRunner;
257
+
258
+ // Run if called directly
259
+ if (require.main === module) {
260
+ main();
261
+ }