@jqhtml/core 2.2.222

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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -0
  3. package/dist/component-registry.d.ts +64 -0
  4. package/dist/component-registry.d.ts.map +1 -0
  5. package/dist/component.d.ts +336 -0
  6. package/dist/component.d.ts.map +1 -0
  7. package/dist/debug-entry.d.ts +36 -0
  8. package/dist/debug-entry.d.ts.map +1 -0
  9. package/dist/debug-overlay.d.ts +61 -0
  10. package/dist/debug-overlay.d.ts.map +1 -0
  11. package/dist/debug.d.ts +19 -0
  12. package/dist/debug.d.ts.map +1 -0
  13. package/dist/index.cjs +4384 -0
  14. package/dist/index.cjs.map +1 -0
  15. package/dist/index.d.ts +91 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +4347 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/instruction-processor.d.ts +31 -0
  20. package/dist/instruction-processor.d.ts.map +1 -0
  21. package/dist/jqhtml-core.esm.js +4352 -0
  22. package/dist/jqhtml-core.esm.js.map +1 -0
  23. package/dist/jqhtml-debug.esm.js +575 -0
  24. package/dist/jqhtml-debug.esm.js.map +1 -0
  25. package/dist/jquery-plugin.d.ts +30 -0
  26. package/dist/jquery-plugin.d.ts.map +1 -0
  27. package/dist/lifecycle-manager.d.ts +34 -0
  28. package/dist/lifecycle-manager.d.ts.map +1 -0
  29. package/dist/load-coordinator.d.ts +79 -0
  30. package/dist/load-coordinator.d.ts.map +1 -0
  31. package/dist/local-storage.d.ts +147 -0
  32. package/dist/local-storage.d.ts.map +1 -0
  33. package/dist/template-renderer.d.ts +17 -0
  34. package/dist/template-renderer.d.ts.map +1 -0
  35. package/laravel-bridge/README.md +242 -0
  36. package/laravel-bridge/autoload.php +51 -0
  37. package/laravel-bridge/composer.json +34 -0
  38. package/laravel-bridge/config/jqhtml.php +82 -0
  39. package/laravel-bridge/examples/node-integration.js +201 -0
  40. package/laravel-bridge/src/JqhtmlErrorFormatter.php +187 -0
  41. package/laravel-bridge/src/JqhtmlException.php +173 -0
  42. package/laravel-bridge/src/JqhtmlExceptionRenderer.php +93 -0
  43. package/laravel-bridge/src/JqhtmlServiceProvider.php +72 -0
  44. package/laravel-bridge/src/Middleware/JqhtmlErrorMiddleware.php +90 -0
  45. package/laravel-bridge/tests/ExceptionFormattingTest.php +219 -0
  46. package/package.json +74 -0
@@ -0,0 +1,72 @@
1
+ <?php
2
+
3
+ namespace Jqhtml\LaravelBridge;
4
+
5
+ use Illuminate\Support\ServiceProvider;
6
+ use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
7
+
8
+ class JqhtmlServiceProvider extends ServiceProvider
9
+ {
10
+ /**
11
+ * Register any application services.
12
+ */
13
+ public function register()
14
+ {
15
+ // Register the error formatter as a singleton
16
+ $this->app->singleton(JqhtmlErrorFormatter::class, function ($app) {
17
+ return new JqhtmlErrorFormatter(
18
+ $app['config']->get('jqhtml.source_maps_path', storage_path('jqhtml-sourcemaps')),
19
+ $app['config']->get('jqhtml.show_source_context', true)
20
+ );
21
+ });
22
+
23
+ // Register the exception renderer
24
+ $this->app->singleton(JqhtmlExceptionRenderer::class, function ($app) {
25
+ return new JqhtmlExceptionRenderer(
26
+ $app->make(JqhtmlErrorFormatter::class)
27
+ );
28
+ });
29
+ }
30
+
31
+ /**
32
+ * Bootstrap any application services.
33
+ */
34
+ public function boot()
35
+ {
36
+ // Publish configuration
37
+ $this->publishes([
38
+ __DIR__ . '/../config/jqhtml.php' => config_path('jqhtml.php'),
39
+ ], 'jqhtml-config');
40
+
41
+ // Extend Laravel's exception handler
42
+ $this->extendExceptionHandler();
43
+ }
44
+
45
+ /**
46
+ * Extend Laravel's exception handler to handle JQHTML exceptions
47
+ */
48
+ protected function extendExceptionHandler()
49
+ {
50
+ $this->app->extend(ExceptionHandler::class, function ($handler, $app) {
51
+ // Hook into the exception rendering process
52
+ $handler->reportable(function (JqhtmlException $e) {
53
+ // Custom reporting logic if needed
54
+ });
55
+
56
+ $handler->renderable(function (JqhtmlException $e, $request) use ($app) {
57
+ if ($request->expectsJson()) {
58
+ return response()->json(
59
+ $app->make(JqhtmlErrorFormatter::class)->formatForJson($e),
60
+ 500
61
+ );
62
+ }
63
+
64
+ // For web requests, let Laravel's default HTML handler display it
65
+ // with our enhanced error information
66
+ return null;
67
+ });
68
+
69
+ return $handler;
70
+ });
71
+ }
72
+ }
@@ -0,0 +1,90 @@
1
+ <?php
2
+
3
+ namespace Jqhtml\LaravelBridge\Middleware;
4
+
5
+ use Closure;
6
+ use Illuminate\Http\Request;
7
+ use Jqhtml\LaravelBridge\JqhtmlErrorFormatter;
8
+ use Jqhtml\LaravelBridge\JqhtmlException;
9
+ use Throwable;
10
+
11
+ class JqhtmlErrorMiddleware
12
+ {
13
+ protected $formatter;
14
+
15
+ public function __construct(JqhtmlErrorFormatter $formatter)
16
+ {
17
+ $this->formatter = $formatter;
18
+ }
19
+
20
+ /**
21
+ * Handle an incoming request.
22
+ *
23
+ * @param \Illuminate\Http\Request $request
24
+ * @param \Closure $next
25
+ * @return mixed
26
+ */
27
+ public function handle(Request $request, Closure $next)
28
+ {
29
+ try {
30
+ return $next($request);
31
+ } catch (Throwable $exception) {
32
+ // Check if this might be a JQHTML error
33
+ if ($this->isJqhtmlError($exception)) {
34
+ // Wrap it in our exception type for better handling
35
+ $wrapped = $this->formatter->wrapException($exception);
36
+
37
+ if ($wrapped instanceof JqhtmlException) {
38
+ // Add request context
39
+ $wrapped->setCompiledFile(
40
+ $this->getCompiledFileFromRequest($request)
41
+ );
42
+
43
+ throw $wrapped;
44
+ }
45
+ }
46
+
47
+ // Not a JQHTML error, rethrow as-is
48
+ throw $exception;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Check if an exception appears to be JQHTML-related
54
+ */
55
+ protected function isJqhtmlError(Throwable $exception): bool
56
+ {
57
+ $message = $exception->getMessage();
58
+
59
+ return strpos($message, 'JQHTML') !== false ||
60
+ strpos($message, 'jqhtml') !== false ||
61
+ strpos($message, 'at line') !== false && strpos($message, 'column') !== false ||
62
+ strpos($message, 'Unclosed component') !== false ||
63
+ strpos($message, 'Mismatched tags') !== false;
64
+ }
65
+
66
+ /**
67
+ * Try to determine the compiled file from the request
68
+ */
69
+ protected function getCompiledFileFromRequest(Request $request): ?string
70
+ {
71
+ // Check if the request has a reference to a compiled template
72
+ $route = $request->route();
73
+
74
+ if ($route && method_exists($route, 'getAction')) {
75
+ $action = $route->getAction();
76
+
77
+ // Look for JQHTML template reference in route action
78
+ if (isset($action['jqhtml_template'])) {
79
+ return $action['jqhtml_template'];
80
+ }
81
+ }
82
+
83
+ // Check request attributes
84
+ if ($request->has('_jqhtml_compiled')) {
85
+ return $request->get('_jqhtml_compiled');
86
+ }
87
+
88
+ return null;
89
+ }
90
+ }
@@ -0,0 +1,219 @@
1
+ <?php
2
+
3
+ namespace Jqhtml\LaravelBridge\Tests;
4
+
5
+ use PHPUnit\Framework\TestCase;
6
+ use Jqhtml\LaravelBridge\JqhtmlException;
7
+ use Jqhtml\LaravelBridge\JqhtmlErrorFormatter;
8
+
9
+ class ExceptionFormattingTest extends TestCase
10
+ {
11
+ protected $formatter;
12
+
13
+ protected function setUp(): void
14
+ {
15
+ parent::setUp();
16
+ $this->formatter = new JqhtmlErrorFormatter();
17
+ }
18
+
19
+ public function testBasicExceptionCreation()
20
+ {
21
+ $exception = new JqhtmlException(
22
+ 'Unclosed component definition',
23
+ 'templates/test.jqhtml',
24
+ 10,
25
+ 15
26
+ );
27
+
28
+ $this->assertEquals('Unclosed component definition', $exception->getMessage());
29
+ $this->assertEquals('templates/test.jqhtml', $exception->getTemplateFile());
30
+ $this->assertEquals(10, $exception->getTemplateLine());
31
+ $this->assertEquals(15, $exception->getTemplateColumn());
32
+ }
33
+
34
+ public function testExceptionWithSuggestion()
35
+ {
36
+ $exception = new JqhtmlException(
37
+ 'Unclosed component definition',
38
+ 'templates/test.jqhtml',
39
+ 10,
40
+ 15,
41
+ null,
42
+ 'Did you forget </Define:ComponentName>?'
43
+ );
44
+
45
+ $this->assertEquals('Did you forget </Define:ComponentName>?', $exception->getSuggestion());
46
+
47
+ $formatted = $exception->getFormattedMessage();
48
+ $this->assertStringContainsString('Did you forget', $formatted);
49
+ }
50
+
51
+ public function testExceptionFromJsError()
52
+ {
53
+ $jsError = [
54
+ 'message' => 'Syntax error: unexpected token',
55
+ 'filename' => 'app.jqhtml',
56
+ 'line' => 42,
57
+ 'column' => 8,
58
+ 'suggestion' => 'Check for missing closing tags',
59
+ 'severity' => 'error'
60
+ ];
61
+
62
+ $exception = JqhtmlException::createFromJsError($jsError);
63
+
64
+ $this->assertEquals('Syntax error: unexpected token', $exception->getMessage());
65
+ $this->assertEquals('app.jqhtml', $exception->getTemplateFile());
66
+ $this->assertEquals(42, $exception->getTemplateLine());
67
+ $this->assertEquals(8, $exception->getTemplateColumn());
68
+ $this->assertEquals('Check for missing closing tags', $exception->getSuggestion());
69
+ }
70
+
71
+ public function testExceptionFromJsonString()
72
+ {
73
+ $json = json_encode([
74
+ 'message' => 'Parse error',
75
+ 'templateFile' => 'template.jqhtml',
76
+ 'line' => 5,
77
+ 'column' => 10
78
+ ]);
79
+
80
+ $exception = JqhtmlException::createFromJsError($json);
81
+
82
+ $this->assertEquals('Parse error', $exception->getMessage());
83
+ $this->assertEquals('template.jqhtml', $exception->getTemplateFile());
84
+ $this->assertEquals(5, $exception->getTemplateLine());
85
+ $this->assertEquals(10, $exception->getTemplateColumn());
86
+ }
87
+
88
+ public function testFormatterBasicFormat()
89
+ {
90
+ $exception = new JqhtmlException(
91
+ 'Test error',
92
+ 'test.jqhtml',
93
+ 20,
94
+ 5
95
+ );
96
+
97
+ $formatted = $this->formatter->format($exception);
98
+
99
+ $this->assertArrayHasKey('message', $formatted);
100
+ $this->assertArrayHasKey('file', $formatted);
101
+ $this->assertArrayHasKey('line', $formatted);
102
+ $this->assertArrayHasKey('column', $formatted);
103
+ $this->assertArrayHasKey('error_type', $formatted);
104
+
105
+ $this->assertEquals('Test error', $formatted['message']);
106
+ $this->assertEquals('test.jqhtml', $formatted['file']);
107
+ $this->assertEquals(20, $formatted['line']);
108
+ $this->assertEquals(5, $formatted['column']);
109
+ }
110
+
111
+ public function testFormatterWithSourceContext()
112
+ {
113
+ $sourceCode = "line 1\nline 2\nline 3 with error\nline 4\nline 5";
114
+
115
+ $exception = new JqhtmlException(
116
+ 'Error on line 3',
117
+ 'test.jqhtml',
118
+ 3,
119
+ 10,
120
+ $sourceCode
121
+ );
122
+
123
+ $formatter = new JqhtmlErrorFormatter(null, true);
124
+ $formatted = $formatter->format($exception);
125
+
126
+ $this->assertArrayHasKey('source_context', $formatted);
127
+
128
+ $context = $formatted['source_context'];
129
+ $this->assertIsArray($context);
130
+
131
+ // Find the error line in context
132
+ $errorLine = null;
133
+ foreach ($context as $line) {
134
+ if ($line['is_error_line']) {
135
+ $errorLine = $line;
136
+ break;
137
+ }
138
+ }
139
+
140
+ $this->assertNotNull($errorLine);
141
+ $this->assertEquals(3, $errorLine['line_number']);
142
+ $this->assertEquals('line 3 with error', $errorLine['content']);
143
+ $this->assertEquals(10, $errorLine['error_column']);
144
+ }
145
+
146
+ public function testFormatterJsonFormat()
147
+ {
148
+ $exception = new JqhtmlException('JSON test error');
149
+
150
+ $json = $this->formatter->formatForJson($exception);
151
+
152
+ $this->assertArrayHasKey('error', $json);
153
+ $this->assertArrayHasKey('type', $json);
154
+ $this->assertArrayHasKey('message', $json);
155
+ $this->assertArrayHasKey('details', $json);
156
+
157
+ $this->assertTrue($json['error']);
158
+ $this->assertEquals('jqhtml_error', $json['type']);
159
+ $this->assertEquals('JSON test error', $json['message']);
160
+ }
161
+
162
+ public function testWrapGenericException()
163
+ {
164
+ $genericException = new \Exception(
165
+ 'JQHTMLParseError: Unclosed tag at line 10, column 5'
166
+ );
167
+
168
+ $wrapped = $this->formatter->wrapException($genericException);
169
+
170
+ $this->assertInstanceOf(JqhtmlException::class, $wrapped);
171
+ $this->assertEquals(10, $wrapped->getTemplateLine());
172
+ $this->assertEquals(5, $wrapped->getTemplateColumn());
173
+ }
174
+
175
+ public function testWrapExceptionWithFilename()
176
+ {
177
+ $genericException = new \Exception(
178
+ 'Error at component.jqhtml:15:20 - syntax error'
179
+ );
180
+
181
+ $wrapped = $this->formatter->wrapException($genericException);
182
+
183
+ $this->assertInstanceOf(JqhtmlException::class, $wrapped);
184
+ $this->assertEquals('component.jqhtml', $wrapped->getTemplateFile());
185
+ $this->assertEquals(15, $wrapped->getTemplateLine());
186
+ $this->assertEquals(20, $wrapped->getTemplateColumn());
187
+ }
188
+
189
+ public function testCodeSnippetGeneration()
190
+ {
191
+ $source = implode("\n", [
192
+ 'line 1',
193
+ 'line 2',
194
+ 'line 3',
195
+ 'error is here', // line 4
196
+ 'line 5',
197
+ 'line 6',
198
+ 'line 7'
199
+ ]);
200
+
201
+ $exception = new JqhtmlException(
202
+ 'Error message',
203
+ 'test.jqhtml',
204
+ 4,
205
+ 8,
206
+ $source
207
+ );
208
+
209
+ $formatted = $exception->getFormattedMessage();
210
+
211
+ // Should show context lines
212
+ $this->assertStringContainsString('line 3', $formatted);
213
+ $this->assertStringContainsString('error is here', $formatted);
214
+ $this->assertStringContainsString('line 5', $formatted);
215
+
216
+ // Should have error pointer
217
+ $this->assertStringContainsString('^', $formatted);
218
+ }
219
+ }
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@jqhtml/core",
3
+ "version": "2.2.222",
4
+ "description": "Core runtime library for JQHTML",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.cjs",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./debug": {
15
+ "import": "./dist/jqhtml-debug.esm.js",
16
+ "types": "./dist/debug.d.ts"
17
+ },
18
+ "./bundle": {
19
+ "import": "./dist/jqhtml-core.esm.js"
20
+ }
21
+ },
22
+ "scripts": {
23
+ "build": "rollup -c",
24
+ "build:tsc": "tsc",
25
+ "watch": "rollup -c -w",
26
+ "test": "jest",
27
+ "clean": "rm -rf dist"
28
+ },
29
+ "peerDependencies": {
30
+ "jquery": "^3.7.0"
31
+ },
32
+ "browser": true,
33
+ "publishConfig": {
34
+ "access": "public"
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "laravel-bridge",
39
+ "README.md",
40
+ "LICENSE"
41
+ ],
42
+ "keywords": [
43
+ "jquery",
44
+ "components",
45
+ "framework",
46
+ "jqhtml",
47
+ "templating"
48
+ ],
49
+ "author": "JQHTML Team",
50
+ "license": "MIT",
51
+ "repository": {
52
+ "type": "git",
53
+ "url": "https://github.com/jqhtml/jqhtml.git",
54
+ "directory": "packages/core"
55
+ },
56
+ "dependencies": {
57
+ "@rollup/plugin-node-resolve": "^16.0.1",
58
+ "@rollup/plugin-replace": "^6.0.2",
59
+ "@rollup/plugin-terser": "^0.4.4",
60
+ "@rollup/plugin-typescript": "^12.1.4",
61
+ "@types/jest": "^29.5.14",
62
+ "@types/jquery": "^3.5.32",
63
+ "esbuild": "^0.25.9",
64
+ "jest": "^29.5.0",
65
+ "jsdom": "^26.1.0",
66
+ "playwright": "^1.53.2",
67
+ "rollup": "^4.49.0",
68
+ "rollup-plugin-dts": "^6.2.3",
69
+ "ts-jest": "^29.1.0",
70
+ "tslib": "^2.8.1",
71
+ "typescript": "^5.9.2"
72
+ },
73
+ "devDependencies": null
74
+ }