@arikajs/view 0.0.3 → 0.0.5
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 +92 -194
- package/dist/Compiler/AST.d.ts +34 -0
- package/dist/Compiler/AST.d.ts.map +1 -0
- package/dist/Compiler/AST.js +12 -0
- package/dist/Compiler/AST.js.map +1 -0
- package/dist/Compiler/CodeGenerator.d.ts +11 -0
- package/dist/Compiler/CodeGenerator.d.ts.map +1 -0
- package/dist/Compiler/CodeGenerator.js +53 -0
- package/dist/Compiler/CodeGenerator.js.map +1 -0
- package/dist/Compiler/DirectiveRegistry.d.ts +10 -0
- package/dist/Compiler/DirectiveRegistry.d.ts.map +1 -0
- package/dist/Compiler/DirectiveRegistry.js +206 -0
- package/dist/Compiler/DirectiveRegistry.js.map +1 -0
- package/dist/Compiler/Lexer.d.ts +28 -0
- package/dist/Compiler/Lexer.d.ts.map +1 -0
- package/dist/Compiler/Lexer.js +209 -0
- package/dist/Compiler/Lexer.js.map +1 -0
- package/dist/Compiler/Parser.d.ts +15 -0
- package/dist/Compiler/Parser.d.ts.map +1 -0
- package/dist/Compiler/Parser.js +188 -0
- package/dist/Compiler/Parser.js.map +1 -0
- package/dist/Compiler.d.ts +4 -3
- package/dist/Compiler.d.ts.map +1 -1
- package/dist/Compiler.js +13 -60
- package/dist/Compiler.js.map +1 -1
- package/dist/Engine.d.ts +47 -4
- package/dist/Engine.d.ts.map +1 -1
- package/dist/Engine.js +203 -39
- package/dist/Engine.js.map +1 -1
- package/dist/Template.js +1 -1
- package/dist/Template.js.map +1 -1
- package/dist/View.d.ts +19 -3
- package/dist/View.d.ts.map +1 -1
- package/dist/View.js +30 -2
- package/dist/View.js.map +1 -1
- package/dist/src/Compiler/AST.d.ts +34 -0
- package/dist/src/Compiler/AST.d.ts.map +1 -0
- package/dist/src/Compiler/AST.js +12 -0
- package/dist/src/Compiler/AST.js.map +1 -0
- package/dist/src/Compiler/CodeGenerator.d.ts +11 -0
- package/dist/src/Compiler/CodeGenerator.d.ts.map +1 -0
- package/dist/src/Compiler/CodeGenerator.js +53 -0
- package/dist/src/Compiler/CodeGenerator.js.map +1 -0
- package/dist/src/Compiler/DirectiveRegistry.d.ts +10 -0
- package/dist/src/Compiler/DirectiveRegistry.d.ts.map +1 -0
- package/dist/src/Compiler/DirectiveRegistry.js +206 -0
- package/dist/src/Compiler/DirectiveRegistry.js.map +1 -0
- package/dist/src/Compiler/Lexer.d.ts +28 -0
- package/dist/src/Compiler/Lexer.d.ts.map +1 -0
- package/dist/src/Compiler/Lexer.js +209 -0
- package/dist/src/Compiler/Lexer.js.map +1 -0
- package/dist/src/Compiler/Parser.d.ts +15 -0
- package/dist/src/Compiler/Parser.d.ts.map +1 -0
- package/dist/src/Compiler/Parser.js +188 -0
- package/dist/src/Compiler/Parser.js.map +1 -0
- package/dist/src/Compiler.d.ts +14 -0
- package/dist/src/Compiler.d.ts.map +1 -0
- package/dist/src/Compiler.js +31 -0
- package/dist/src/Compiler.js.map +1 -0
- package/dist/src/Engine.d.ts +76 -0
- package/dist/src/Engine.d.ts.map +1 -0
- package/dist/src/Engine.js +308 -0
- package/dist/src/Engine.js.map +1 -0
- package/dist/src/Template.d.ts +14 -0
- package/dist/src/Template.d.ts.map +1 -0
- package/dist/src/Template.js +63 -0
- package/dist/src/Template.js.map +1 -0
- package/dist/src/View.d.ts +30 -0
- package/dist/src/View.d.ts.map +1 -0
- package/dist/src/View.js +51 -0
- package/dist/src/View.js.map +1 -0
- package/dist/tests/View.test.d.ts +2 -0
- package/dist/tests/View.test.d.ts.map +1 -0
- package/dist/tests/View.test.js +190 -0
- package/dist/tests/View.test.js.map +1 -0
- package/package.json +45 -43
- package/dist/Directives/For.d.ts +0 -5
- package/dist/Directives/For.d.ts.map +0 -1
- package/dist/Directives/For.js +0 -18
- package/dist/Directives/For.js.map +0 -1
- package/dist/Directives/If.d.ts +0 -6
- package/dist/Directives/If.d.ts.map +0 -1
- package/dist/Directives/If.js +0 -26
- package/dist/Directives/If.js.map +0 -1
- package/dist/Directives/Include.d.ts +0 -5
- package/dist/Directives/Include.d.ts.map +0 -1
- package/dist/Directives/Include.js +0 -15
- package/dist/Directives/Include.js.map +0 -1
- package/dist/Directives/Section.d.ts +0 -5
- package/dist/Directives/Section.d.ts.map +0 -1
- package/dist/Directives/Section.js +0 -28
- package/dist/Directives/Section.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,246 +1,144 @@
|
|
|
1
|
-
|
|
1
|
+
# Arika View v1.0 💎
|
|
2
2
|
|
|
3
|
-
`@arikajs/view` is
|
|
4
|
-
|
|
5
|
-
It allows developers to render dynamic HTML using a clean, expressive template syntax inspired by modern server frameworks — while remaining lightweight, secure, and framework-agnostic.
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { View } from '@arikajs/view';
|
|
9
|
-
|
|
10
|
-
const view = new View({
|
|
11
|
-
viewsPath: './views',
|
|
12
|
-
cachePath: './storage/views',
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const html = await view.render('home', {
|
|
16
|
-
title: 'Welcome to ArikaJS',
|
|
17
|
-
});
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
The View package enables presentation logic in ArikaJS, transforming templates into clean HTML output with safe escaping and high performance.
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
### Status
|
|
25
|
-
|
|
26
|
-
- **Stage**: Experimental / v0.x
|
|
27
|
-
- **Scope (v0.x)**:
|
|
28
|
-
- Template compilation & rendering
|
|
29
|
-
- Layout & section management
|
|
30
|
-
- Basic control structures (`@if`, `@for`)
|
|
31
|
-
- Safe output escaping
|
|
32
|
-
- Template caching
|
|
33
|
-
- **Out of scope (for this package)**:
|
|
34
|
-
- HTTP request/response handling (see `@arikajs/http`)
|
|
35
|
-
- Route matching (see `@arikajs/router`)
|
|
36
|
-
- Authentication logic
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## 🎯 Purpose
|
|
41
|
-
|
|
42
|
-
The View package is the presentation layer of the ArikaJS ecosystem. It is responsible for:
|
|
43
|
-
- Rendering templates into HTML
|
|
44
|
-
- Managing layouts and partials
|
|
45
|
-
- Escaping output safely
|
|
46
|
-
- Supporting control structures
|
|
47
|
-
- Providing a foundation for Web views, Email templates, and Error pages.
|
|
3
|
+
`@arikajs/view` is a production-grade, TypeScript-first template engine designed for the ArikaJS ecosystem. It combines the power of modern JS with a clean, expressive syntax inspired by Laravel Blade, but built natively for the Node.js event loop.
|
|
48
4
|
|
|
49
5
|
---
|
|
50
6
|
|
|
51
|
-
##
|
|
7
|
+
## 🚀 Core Architecture
|
|
52
8
|
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
57
|
-
-
|
|
58
|
-
- Escape output by default
|
|
59
|
-
- Cache compiled templates for performance
|
|
60
|
-
|
|
61
|
-
### ❌ What Arika View Does NOT Do
|
|
62
|
-
- Handle HTTP requests or responses
|
|
63
|
-
- Match routes
|
|
64
|
-
- Manage authentication
|
|
65
|
-
- Execute business logic
|
|
9
|
+
Arika View v1 features a completely rewritten compiler stack:
|
|
10
|
+
- **Lexer**: Intelligent tokenization of `.ark` files.
|
|
11
|
+
- **Parser**: Builds a robust Abstract Syntax Tree (AST) for complex nesting.
|
|
12
|
+
- **Directive Registry**: Modular system for extending template logic.
|
|
13
|
+
- **Code Generator**: Produces highly optimized, async-ready JavaScript.
|
|
66
14
|
|
|
67
15
|
---
|
|
68
16
|
|
|
69
|
-
##
|
|
70
|
-
|
|
71
|
-
```
|
|
72
|
-
Controller
|
|
73
|
-
↓
|
|
74
|
-
View.render()
|
|
75
|
-
↓
|
|
76
|
-
Template Compiler
|
|
77
|
-
↓
|
|
78
|
-
Compiled Template
|
|
79
|
-
↓
|
|
80
|
-
HTML Output
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## Features
|
|
86
|
-
|
|
87
|
-
- **Simple, expressive template syntax**
|
|
88
|
-
- Clean tags for logic and output.
|
|
89
|
-
- **Layout & section support**
|
|
90
|
-
- Powerful inheritance model for UI consistency.
|
|
91
|
-
- **Partial / include support**
|
|
92
|
-
- Modularize your templates into reusable components.
|
|
93
|
-
- **Safe output escaping**
|
|
94
|
-
- Protection against XSS by default.
|
|
95
|
-
- **Custom directives**
|
|
96
|
-
- Extend the engine with your own syntax.
|
|
97
|
-
- **Template caching**
|
|
98
|
-
- High-performance rendering via pre-compiled templates.
|
|
99
|
-
|
|
100
|
-
---
|
|
17
|
+
## ✨ Key Features
|
|
101
18
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
```bash
|
|
105
|
-
npm install @arikajs/view
|
|
106
|
-
# or
|
|
107
|
-
yarn add @arikajs/view
|
|
108
|
-
# or
|
|
109
|
-
pnpm add @arikajs/view
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 🧩 Template Syntax
|
|
115
|
-
|
|
116
|
-
### Variable Output
|
|
19
|
+
### 1️⃣ Pure JavaScript Expressions
|
|
20
|
+
Arika View embraces JavaScript. No need to learn a limited expression language — if it's valid JS, it's valid in your template.
|
|
117
21
|
```html
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
*Escaped by default.*
|
|
121
|
-
|
|
122
|
-
### Raw Output
|
|
123
|
-
```html
|
|
124
|
-
{!! html !!}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### Conditionals
|
|
128
|
-
```html
|
|
129
|
-
@if (user)
|
|
130
|
-
<p>Welcome, {{ user.name }}</p>
|
|
22
|
+
@if (user?.isAdmin && posts.length > 0)
|
|
23
|
+
<p>Welcome back, Admin!</p>
|
|
131
24
|
@endif
|
|
132
25
|
```
|
|
133
26
|
|
|
134
|
-
###
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
27
|
+
### 2️⃣ Type-Safe View Data
|
|
28
|
+
Leverage TypeScript's power in your views.
|
|
29
|
+
```ts
|
|
30
|
+
interface HomeData {
|
|
31
|
+
title: string;
|
|
32
|
+
user: { name: string };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await view.render<HomeData>('home', {
|
|
36
|
+
title: 'ArikaJS',
|
|
37
|
+
user: { name: 'Prakash' }
|
|
38
|
+
});
|
|
139
39
|
```
|
|
140
40
|
|
|
141
|
-
###
|
|
41
|
+
### 3️⃣ Modern Components (`<x-`)
|
|
42
|
+
Stop using clunky syntax. Use modern, HTML-like components.
|
|
142
43
|
```html
|
|
143
|
-
|
|
44
|
+
<x-alert type="danger" :dismissible="true">
|
|
45
|
+
<x-slot name="title">Warning!</x-slot>
|
|
46
|
+
Something went wrong.
|
|
47
|
+
</x-alert>
|
|
144
48
|
```
|
|
145
49
|
|
|
146
|
-
###
|
|
50
|
+
### 4️⃣ Smart Caching & Dev Mode
|
|
51
|
+
- **Hash-based Invalidation**: Templates only recompile when content actually changes.
|
|
52
|
+
- **Dev Mode**: Real-time recompilation and enhanced error stack traces with file/line references.
|
|
53
|
+
- **Production Mode**: Minified output and aggressive in-memory caching.
|
|
147
54
|
|
|
148
|
-
|
|
55
|
+
### 5️⃣ Fragments (HTMX Ready ⚡)
|
|
56
|
+
Render only a specific part of your template — perfect for HTMX or partial reloads.
|
|
149
57
|
```html
|
|
150
|
-
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
</body>
|
|
154
|
-
</html>
|
|
58
|
+
@fragment('sidebar')
|
|
59
|
+
<nav>...</nav>
|
|
60
|
+
@endfragment
|
|
155
61
|
```
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
```html
|
|
159
|
-
@extends('layout')
|
|
160
|
-
|
|
161
|
-
@section('content')
|
|
162
|
-
<h1>Hello World</h1>
|
|
163
|
-
@endsection
|
|
62
|
+
```ts
|
|
63
|
+
await view.renderFragment('dashboard', 'sidebar');
|
|
164
64
|
```
|
|
165
65
|
|
|
166
66
|
---
|
|
167
67
|
|
|
168
|
-
##
|
|
68
|
+
## 🛠 Directives Reference
|
|
69
|
+
|
|
70
|
+
| Directive | Description |
|
|
71
|
+
|-----------|-------------|
|
|
72
|
+
| `@if`, `@elseif`, `@else` | Standard conditional logic. |
|
|
73
|
+
| `@unless` | Inverse of `@if`. |
|
|
74
|
+
| `@for` | Standard JS loop. |
|
|
75
|
+
| `@each(view, data, item, empty)` | Render a view for each item in a collection. |
|
|
76
|
+
| `@switch`, `@case`, `@default` | Switch statement support. |
|
|
77
|
+
| `@break`, `@continue` | Control loop execution. |
|
|
78
|
+
| `@auth`, `@guest` | Conditional rendering based on user session. |
|
|
79
|
+
| `@once` | Ensure a block is only rendered once per request. |
|
|
80
|
+
| `@verbatim` | Stop parsing content inside the block. |
|
|
81
|
+
| `@push`, `@stack`, `@prepend` | Manage assets and scripts across layouts. |
|
|
82
|
+
| `@await(promise)` | Native async support inside templates. |
|
|
169
83
|
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
import { View } from '@arikajs/view';
|
|
84
|
+
---
|
|
173
85
|
|
|
174
|
-
|
|
175
|
-
viewsPath: './views',
|
|
176
|
-
cachePath: './storage/views',
|
|
177
|
-
});
|
|
86
|
+
## 🔌 Advanced Ecosystem
|
|
178
87
|
|
|
179
|
-
|
|
180
|
-
|
|
88
|
+
### View Composers
|
|
89
|
+
Inject data into specific views automatically before they are rendered.
|
|
90
|
+
```ts
|
|
91
|
+
view.composer('dashboard', async (data) => {
|
|
92
|
+
data.notifications = await getNotifications();
|
|
181
93
|
});
|
|
182
94
|
```
|
|
183
95
|
|
|
184
|
-
###
|
|
185
|
-
|
|
96
|
+
### Global Helpers
|
|
97
|
+
Define custom functions accessible in every template.
|
|
186
98
|
```ts
|
|
187
|
-
|
|
188
|
-
user,
|
|
189
|
-
});
|
|
99
|
+
view.helper('formatDate', (date) => new Intl.DateTimeFormat().format(date));
|
|
190
100
|
```
|
|
101
|
+
Usage: `{{ formatDate(user.createdAt) }}`
|
|
191
102
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
## ⚙️ Configuration Options
|
|
195
|
-
|
|
103
|
+
### Custom Directives API
|
|
104
|
+
Extend Arika View with your own powerful directives.
|
|
196
105
|
```ts
|
|
197
|
-
{
|
|
198
|
-
viewsPath: string; // Directory containing templates
|
|
199
|
-
cachePath?: string; // Directory for compiled templates
|
|
200
|
-
extension?: '.html' | '.ark'; // Template file extension
|
|
201
|
-
cache?: boolean; // Enable/disable caching
|
|
202
|
-
}
|
|
106
|
+
view.directive('uppercase', (exp) => `_output += String(${exp}).toUpperCase();`);
|
|
203
107
|
```
|
|
204
108
|
|
|
205
109
|
---
|
|
206
110
|
|
|
207
|
-
##
|
|
208
|
-
|
|
209
|
-
- `src/`
|
|
210
|
-
- `View.ts` – Main entry point
|
|
211
|
-
- `Engine.ts` – Execution context
|
|
212
|
-
- `Compiler.ts` – Template string to JS compiler
|
|
213
|
-
- `Template.ts` – Template resolution and state
|
|
214
|
-
- `Directives/` – Built-in controls
|
|
215
|
-
- `If.ts`, `For.ts`, `Include.ts`, `Section.ts`
|
|
216
|
-
- `index.ts` – Public exports
|
|
217
|
-
- `tests/` – Unit and integration tests
|
|
218
|
-
- `package.json`
|
|
219
|
-
- `tsconfig.json`
|
|
220
|
-
- `README.md`
|
|
221
|
-
- `LICENSE`
|
|
222
|
-
|
|
223
|
-
---
|
|
111
|
+
## 📁 File Structure & Extension
|
|
224
112
|
|
|
225
|
-
|
|
113
|
+
Arika View exclusively uses the `.ark.html` extension for all templates.
|
|
226
114
|
|
|
227
|
-
|
|
228
|
-
|
|
115
|
+
```text
|
|
116
|
+
resources/views/
|
|
117
|
+
├── layouts/
|
|
118
|
+
│ └── app.ark.html
|
|
119
|
+
├── auth/
|
|
120
|
+
│ ├── login.ark.html
|
|
121
|
+
│ └── register.ark.html
|
|
122
|
+
└── welcome.ark.html
|
|
123
|
+
```
|
|
229
124
|
|
|
230
125
|
---
|
|
231
126
|
|
|
232
|
-
##
|
|
127
|
+
## 💻 CLI Integration
|
|
233
128
|
|
|
234
|
-
|
|
129
|
+
Generate views instantly with the Arika CLI:
|
|
130
|
+
```bash
|
|
131
|
+
arika make:view home
|
|
132
|
+
# Generates resources/views/home.ark.html
|
|
133
|
+
```
|
|
235
134
|
|
|
236
135
|
---
|
|
237
136
|
|
|
238
|
-
##
|
|
137
|
+
## 🧠 Philosophy
|
|
239
138
|
|
|
240
|
-
|
|
139
|
+
> "Arika View turns your templates into native Node.js code, making UI rendering as fast as the engine itself."
|
|
241
140
|
|
|
242
141
|
---
|
|
243
142
|
|
|
244
|
-
##
|
|
245
|
-
|
|
246
|
-
> “Presentation is a reflection of logic, not a home for it.”
|
|
143
|
+
## License
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare enum NodeType {
|
|
2
|
+
Root = "Root",
|
|
3
|
+
Text = "Text",
|
|
4
|
+
Expression = "Expression",
|
|
5
|
+
RawExpression = "RawExpression",
|
|
6
|
+
Directive = "Directive"
|
|
7
|
+
}
|
|
8
|
+
export interface Node {
|
|
9
|
+
type: NodeType;
|
|
10
|
+
[key: string]: any;
|
|
11
|
+
}
|
|
12
|
+
export interface RootNode extends Node {
|
|
13
|
+
type: NodeType.Root;
|
|
14
|
+
children: Node[];
|
|
15
|
+
}
|
|
16
|
+
export interface TextNode extends Node {
|
|
17
|
+
type: NodeType.Text;
|
|
18
|
+
content: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ExpressionNode extends Node {
|
|
21
|
+
type: NodeType.Expression;
|
|
22
|
+
content: string;
|
|
23
|
+
}
|
|
24
|
+
export interface RawExpressionNode extends Node {
|
|
25
|
+
type: NodeType.RawExpression;
|
|
26
|
+
content: string;
|
|
27
|
+
}
|
|
28
|
+
export interface DirectiveNode extends Node {
|
|
29
|
+
type: NodeType.Directive;
|
|
30
|
+
name: string;
|
|
31
|
+
expression: string | null;
|
|
32
|
+
children?: Node[];
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=AST.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AST.d.ts","sourceRoot":"","sources":["../../src/Compiler/AST.ts"],"names":[],"mappings":"AAAA,oBAAY,QAAQ;IAChB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,aAAa,kBAAkB;IAC/B,SAAS,cAAc;CAC1B;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,QAAS,SAAQ,IAAI;IAClC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;IACpB,QAAQ,EAAE,IAAI,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,QAAS,SAAQ,IAAI;IAClC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAe,SAAQ,IAAI;IACxC,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI;IAC3C,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAc,SAAQ,IAAI;IACvC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;CACrB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeType = void 0;
|
|
4
|
+
var NodeType;
|
|
5
|
+
(function (NodeType) {
|
|
6
|
+
NodeType["Root"] = "Root";
|
|
7
|
+
NodeType["Text"] = "Text";
|
|
8
|
+
NodeType["Expression"] = "Expression";
|
|
9
|
+
NodeType["RawExpression"] = "RawExpression";
|
|
10
|
+
NodeType["Directive"] = "Directive";
|
|
11
|
+
})(NodeType || (exports.NodeType = NodeType = {}));
|
|
12
|
+
//# sourceMappingURL=AST.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AST.js","sourceRoot":"","sources":["../../src/Compiler/AST.ts"],"names":[],"mappings":";;;AAAA,IAAY,QAMX;AAND,WAAY,QAAQ;IAChB,yBAAa,CAAA;IACb,yBAAa,CAAA;IACb,qCAAyB,CAAA;IACzB,2CAA+B,CAAA;IAC/B,mCAAuB,CAAA;AAC3B,CAAC,EANW,QAAQ,wBAAR,QAAQ,QAMnB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RootNode } from './AST';
|
|
2
|
+
import { DirectiveRegistry } from './DirectiveRegistry';
|
|
3
|
+
export declare class CodeGenerator {
|
|
4
|
+
private registry;
|
|
5
|
+
constructor(registry: DirectiveRegistry);
|
|
6
|
+
generate(root: RootNode): string;
|
|
7
|
+
private generateNodes;
|
|
8
|
+
private generateNode;
|
|
9
|
+
private cleanExpression;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=CodeGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeGenerator.d.ts","sourceRoot":"","sources":["../../src/Compiler/CodeGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAA8E,MAAM,OAAO,CAAC;AAC7G,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAoB;gBAExB,QAAQ,EAAE,iBAAiB;IAIhC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM;IAUvC,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,YAAY;IAiCpB,OAAO,CAAC,eAAe;CAK1B"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CodeGenerator = void 0;
|
|
4
|
+
const AST_1 = require("./AST");
|
|
5
|
+
class CodeGenerator {
|
|
6
|
+
constructor(registry) {
|
|
7
|
+
this.registry = registry;
|
|
8
|
+
}
|
|
9
|
+
generate(root) {
|
|
10
|
+
let jsCode = 'let _output = "";\n';
|
|
11
|
+
jsCode += 'const _escape = (val) => String(val ?? "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/\\\'/g, "'");\n';
|
|
12
|
+
jsCode += this.generateNodes(root.children);
|
|
13
|
+
jsCode += 'return _output;';
|
|
14
|
+
return jsCode;
|
|
15
|
+
}
|
|
16
|
+
generateNodes(nodes) {
|
|
17
|
+
return nodes.map(node => this.generateNode(node)).join('\n');
|
|
18
|
+
}
|
|
19
|
+
generateNode(node) {
|
|
20
|
+
switch (node.type) {
|
|
21
|
+
case AST_1.NodeType.Text:
|
|
22
|
+
const text = node.content
|
|
23
|
+
.replace(/\\/g, '\\\\')
|
|
24
|
+
.replace(/`/g, '\\`')
|
|
25
|
+
.replace(/\${/g, '\\${');
|
|
26
|
+
return `_output += \`${text}\`;`;
|
|
27
|
+
case AST_1.NodeType.Expression:
|
|
28
|
+
return `_output += _escape(${this.cleanExpression(node.content)});`;
|
|
29
|
+
case AST_1.NodeType.RawExpression:
|
|
30
|
+
return `_output += (${this.cleanExpression(node.content)});`;
|
|
31
|
+
case AST_1.NodeType.Directive:
|
|
32
|
+
const dir = node;
|
|
33
|
+
const childrenCode = dir.children ? this.generateNodes(dir.children) : '';
|
|
34
|
+
const result = this.registry.handle(dir.name, dir.expression, childrenCode);
|
|
35
|
+
if (result === null) {
|
|
36
|
+
// Fallback for unknown directives (e.g., CSS @media, @keyframes)
|
|
37
|
+
const originalText = `@${dir.name}${dir.expression ? '(' + dir.expression + ')' : ''}`;
|
|
38
|
+
const sanitized = originalText.replace(/`/g, '\\`').replace(/\${/g, '\\${');
|
|
39
|
+
return `_output += \`${sanitized}\`;\n${childrenCode}`;
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
default:
|
|
43
|
+
return '';
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
cleanExpression(exp) {
|
|
47
|
+
// Strip leading $ from variables to support Laravel-style {{ $var }}
|
|
48
|
+
// This regex finds $ followed by an identifier and replaces it with just the identifier
|
|
49
|
+
return exp.replace(/(^|[^a-zA-Z0-9_])\$([a-zA-Z_][a-zA-Z0-9_]*)/g, '$1$2');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.CodeGenerator = CodeGenerator;
|
|
53
|
+
//# sourceMappingURL=CodeGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CodeGenerator.js","sourceRoot":"","sources":["../../src/Compiler/CodeGenerator.ts"],"names":[],"mappings":";;;AAAA,+BAA6G;AAG7G,MAAa,aAAa;IAGtB,YAAY,QAA2B;QACnC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAEM,QAAQ,CAAC,IAAc;QAC1B,IAAI,MAAM,GAAG,qBAAqB,CAAC;QACnC,MAAM,IAAI,oKAAoK,CAAC;QAE/K,MAAM,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAE5C,MAAM,IAAI,iBAAiB,CAAC;QAC5B,OAAO,MAAM,CAAC;IAClB,CAAC;IAEO,aAAa,CAAC,KAAa;QAC/B,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,CAAC;IAEO,YAAY,CAAC,IAAU;QAC3B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAChB,KAAK,cAAQ,CAAC,IAAI;gBACd,MAAM,IAAI,GAAI,IAAiB,CAAC,OAAO;qBAClC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;qBACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;qBACpB,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAC7B,OAAO,gBAAgB,IAAI,KAAK,CAAC;YAErC,KAAK,cAAQ,CAAC,UAAU;gBACpB,OAAO,sBAAsB,IAAI,CAAC,eAAe,CAAE,IAAuB,CAAC,OAAO,CAAC,IAAI,CAAC;YAE5F,KAAK,cAAQ,CAAC,aAAa;gBACvB,OAAO,eAAe,IAAI,CAAC,eAAe,CAAE,IAA0B,CAAC,OAAO,CAAC,IAAI,CAAC;YAExF,KAAK,cAAQ,CAAC,SAAS;gBACnB,MAAM,GAAG,GAAG,IAAqB,CAAC;gBAClC,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1E,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;gBAE5E,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;oBAClB,iEAAiE;oBACjE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;oBACvF,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBAC5E,OAAO,gBAAgB,SAAS,QAAQ,YAAY,EAAE,CAAC;gBAC3D,CAAC;gBACD,OAAO,MAAM,CAAC;YAElB;gBACI,OAAO,EAAE,CAAC;QAClB,CAAC;IACL,CAAC;IAEO,eAAe,CAAC,GAAW;QAC/B,qEAAqE;QACrE,wFAAwF;QACxF,OAAO,GAAG,CAAC,OAAO,CAAC,8CAA8C,EAAE,MAAM,CAAC,CAAC;IAC/E,CAAC;CACJ;AA3DD,sCA2DC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type DirectiveHandler = (expression: string | null, children?: string) => string;
|
|
2
|
+
export declare class DirectiveRegistry {
|
|
3
|
+
private directives;
|
|
4
|
+
constructor();
|
|
5
|
+
register(name: string, handler: DirectiveHandler): void;
|
|
6
|
+
has(name: string): boolean;
|
|
7
|
+
handle(name: string, expression: string | null, children?: string): string | null;
|
|
8
|
+
private registerDefaultDirectives;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=DirectiveRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DirectiveRegistry.d.ts","sourceRoot":"","sources":["../../src/Compiler/DirectiveRegistry.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,gBAAgB,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAExF,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,UAAU,CAA4C;;IAMvD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,IAAI;IAIvD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAQxF,OAAO,CAAC,yBAAyB;CAyNpC"}
|