@heshammesalam/heshjs 0.0.0-stage → 0.1.0
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 +42 -2
- package/dist/compiler/index.d.ts +37 -0
- package/dist/compiler/index.js +294 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/dom/index.d.ts +12 -0
- package/dist/dom/index.js +69 -0
- package/dist/dom/index.js.map +1 -0
- package/dist/heshjs/index.d.ts +4 -0
- package/dist/heshjs/index.js +3 -0
- package/dist/heshjs/index.js.map +1 -0
- package/dist/parser/index.d.ts +47 -0
- package/dist/parser/index.js +218 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/reactivity/index.d.ts +15 -0
- package/dist/reactivity/index.js +162 -0
- package/dist/reactivity/index.js.map +1 -0
- package/dist/vite/index.d.ts +2 -0
- package/dist/vite/index.js +21 -0
- package/dist/vite/index.js.map +1 -0
- package/docs/grammar.md +65 -0
- package/package.json +24 -4
- package/src/compiler/index.ts +231 -0
- package/src/dom/index.ts +67 -0
- package/src/heshjs/index.ts +4 -0
- package/src/parser/index.ts +149 -0
- package/src/reactivity/index.ts +115 -0
- package/src/vite/index.ts +17 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
export class HeshError extends Error {
|
|
3
|
+
source;
|
|
4
|
+
offset;
|
|
5
|
+
filename;
|
|
6
|
+
line;
|
|
7
|
+
column;
|
|
8
|
+
constructor(message, source, offset, filename = 'component.hesh') {
|
|
9
|
+
const lines = source.slice(0, offset).split('\n');
|
|
10
|
+
const line = lines.length, column = lines.at(-1).length + 1;
|
|
11
|
+
super(`${filename}:${line}:${column}: ${message}`);
|
|
12
|
+
this.source = source;
|
|
13
|
+
this.offset = offset;
|
|
14
|
+
this.filename = filename;
|
|
15
|
+
this.name = 'HeshError';
|
|
16
|
+
this.line = line;
|
|
17
|
+
this.column = column;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function tokenize(source, filename = 'component.hesh') {
|
|
21
|
+
const tokens = [];
|
|
22
|
+
const keywords = new Set('break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield let static await async'.split(' '));
|
|
23
|
+
let at = 0;
|
|
24
|
+
const fail = (message, offset) => { throw new HeshError(message, source, offset, filename); };
|
|
25
|
+
while (at < source.length) {
|
|
26
|
+
const start = at;
|
|
27
|
+
const ch = source[at];
|
|
28
|
+
if (/\s/.test(ch)) {
|
|
29
|
+
at++;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (source.startsWith('//', at)) {
|
|
33
|
+
while (at < source.length && source[at] !== '\n')
|
|
34
|
+
at++;
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
if (source.startsWith('/*', at)) {
|
|
38
|
+
const end = source.indexOf('*/', at + 2);
|
|
39
|
+
if (end < 0)
|
|
40
|
+
fail('Unterminated comment', at);
|
|
41
|
+
at = end + 2;
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
let kind = ts.SyntaxKind.Unknown;
|
|
45
|
+
if (ch === '"' || ch === "'" || ch === '`') {
|
|
46
|
+
const quote = ch;
|
|
47
|
+
at++;
|
|
48
|
+
let closed = false;
|
|
49
|
+
while (at < source.length) {
|
|
50
|
+
const current = source[at++];
|
|
51
|
+
if (current === '\\') {
|
|
52
|
+
at++;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (quote === '`' && current === '$' && source[at] === '{')
|
|
56
|
+
fail('Template substitutions belong in imported JS/TS helpers in Milestone 1', at - 1);
|
|
57
|
+
if (current === quote) {
|
|
58
|
+
closed = true;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
if (quote !== '`' && (current === '\n' || current === '\r'))
|
|
62
|
+
fail('Unterminated string', start);
|
|
63
|
+
}
|
|
64
|
+
if (!closed)
|
|
65
|
+
fail('Unterminated string', start);
|
|
66
|
+
kind = quote === '`' ? ts.SyntaxKind.NoSubstitutionTemplateLiteral : ts.SyntaxKind.StringLiteral;
|
|
67
|
+
}
|
|
68
|
+
else if (/[$_\p{ID_Start}]/u.test(ch)) {
|
|
69
|
+
at++;
|
|
70
|
+
while (at < source.length && /[$\u200c\u200d\p{ID_Continue}]/u.test(source[at]))
|
|
71
|
+
at++;
|
|
72
|
+
kind = keywords.has(source.slice(start, at)) ? ts.SyntaxKind.Unknown : ts.SyntaxKind.Identifier;
|
|
73
|
+
}
|
|
74
|
+
else if (/\d/.test(ch)) {
|
|
75
|
+
at++;
|
|
76
|
+
while (at < source.length && /[\w.]/.test(source[at]))
|
|
77
|
+
at++;
|
|
78
|
+
kind = ts.SyntaxKind.NumericLiteral;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const operator = ['>>>=', '===', '!==', '**=', '&&=', '||=', '??=', '>>>', '<<=', '>>=', '=>', '==', '!=', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=', '%=', '**', '&&', '||', '??', '?.', '<<', '>>', '&=', '|=', '^=', '...'].find(op => source.startsWith(op, at));
|
|
82
|
+
at += operator?.length ?? 1;
|
|
83
|
+
}
|
|
84
|
+
tokens.push({ kind, text: source.slice(start, at), start, end: at });
|
|
85
|
+
}
|
|
86
|
+
return tokens;
|
|
87
|
+
}
|
|
88
|
+
export function parse(source, filename = 'component.hesh') {
|
|
89
|
+
const tokens = tokenize(source, filename);
|
|
90
|
+
let at = 0;
|
|
91
|
+
const peek = () => tokens[at]?.text;
|
|
92
|
+
const fail = (message, offset = tokens[at]?.start ?? source.length) => { throw new HeshError(message, source, offset, filename); };
|
|
93
|
+
const take = (text) => {
|
|
94
|
+
const token = tokens[at];
|
|
95
|
+
if (!token || (text !== undefined && token.text !== text))
|
|
96
|
+
fail(`Expected ${text ?? 'token'}, received ${peek() ?? 'end of file'}`);
|
|
97
|
+
at++;
|
|
98
|
+
return token;
|
|
99
|
+
};
|
|
100
|
+
const identifier = () => {
|
|
101
|
+
const token = take();
|
|
102
|
+
if (token.kind !== ts.SyntaxKind.Identifier)
|
|
103
|
+
fail('Expected identifier', token.start);
|
|
104
|
+
if (token.text.startsWith('__h'))
|
|
105
|
+
fail('Identifiers beginning __h are reserved', token.start);
|
|
106
|
+
return token;
|
|
107
|
+
};
|
|
108
|
+
const expression = (ends) => {
|
|
109
|
+
const start = tokens[at]?.start ?? source.length;
|
|
110
|
+
const stack = [];
|
|
111
|
+
const pairs = { '(': ')', '[': ']', '{': '}' };
|
|
112
|
+
while (tokens[at]) {
|
|
113
|
+
const token = tokens[at];
|
|
114
|
+
if (!stack.length && ends.includes(token.text))
|
|
115
|
+
break;
|
|
116
|
+
if (pairs[token.text])
|
|
117
|
+
stack.push(pairs[token.text]);
|
|
118
|
+
else if ([')', ']', '}'].includes(token.text)) {
|
|
119
|
+
if (stack.pop() !== token.text)
|
|
120
|
+
fail('Unbalanced expression', token.start);
|
|
121
|
+
}
|
|
122
|
+
at++;
|
|
123
|
+
}
|
|
124
|
+
if (stack.length)
|
|
125
|
+
fail('Unterminated expression', start);
|
|
126
|
+
const end = tokens[at]?.start ?? source.length;
|
|
127
|
+
if (!source.slice(start, end).trim())
|
|
128
|
+
fail('Expected expression', start);
|
|
129
|
+
return { source: source.slice(start, end).trimEnd(), start, end };
|
|
130
|
+
};
|
|
131
|
+
const element = () => {
|
|
132
|
+
const name = identifier();
|
|
133
|
+
take('(');
|
|
134
|
+
let value, handler, async = false;
|
|
135
|
+
if (peek() !== ')')
|
|
136
|
+
value = expression([',', ')']);
|
|
137
|
+
if (peek() === ',') {
|
|
138
|
+
take(',');
|
|
139
|
+
if (peek() === 'async') {
|
|
140
|
+
take();
|
|
141
|
+
async = true;
|
|
142
|
+
}
|
|
143
|
+
const start = take('{').end;
|
|
144
|
+
let depth = 1;
|
|
145
|
+
while (tokens[at] && depth) {
|
|
146
|
+
if (peek() === '{')
|
|
147
|
+
depth++;
|
|
148
|
+
if (peek() === '}')
|
|
149
|
+
depth--;
|
|
150
|
+
if (depth)
|
|
151
|
+
at++;
|
|
152
|
+
}
|
|
153
|
+
if (!tokens[at])
|
|
154
|
+
fail('Unterminated event block', start);
|
|
155
|
+
const end = take('}').start;
|
|
156
|
+
handler = { source: source.slice(start, end), start, end };
|
|
157
|
+
}
|
|
158
|
+
take(')');
|
|
159
|
+
const children = [];
|
|
160
|
+
if (peek() === '{') {
|
|
161
|
+
take();
|
|
162
|
+
while (peek() && peek() !== '}')
|
|
163
|
+
children.push(element());
|
|
164
|
+
take('}');
|
|
165
|
+
if (peek() === ';')
|
|
166
|
+
take();
|
|
167
|
+
}
|
|
168
|
+
else
|
|
169
|
+
take(';');
|
|
170
|
+
return { kind: 'element', name: name.text, start: name.start, end: tokens[at - 1].end, value, handler, async, children };
|
|
171
|
+
};
|
|
172
|
+
const module = { source, filename, imports: [], views: [] };
|
|
173
|
+
while (tokens[at]) {
|
|
174
|
+
if (peek() === 'import') {
|
|
175
|
+
if (module.views.length)
|
|
176
|
+
fail('Imports must precede views');
|
|
177
|
+
const start = take().start;
|
|
178
|
+
while (peek() && peek() !== ';')
|
|
179
|
+
take();
|
|
180
|
+
const end = take(';').end;
|
|
181
|
+
module.imports.push({ source: source.slice(start, end), start, end });
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
let exported = false, isDefault = false;
|
|
185
|
+
if (peek() === 'export') {
|
|
186
|
+
take();
|
|
187
|
+
exported = true;
|
|
188
|
+
}
|
|
189
|
+
if (peek() === 'default') {
|
|
190
|
+
take();
|
|
191
|
+
isDefault = true;
|
|
192
|
+
if (!exported)
|
|
193
|
+
fail('default requires export');
|
|
194
|
+
}
|
|
195
|
+
const start = take('view').start;
|
|
196
|
+
const name = identifier().text;
|
|
197
|
+
take('{');
|
|
198
|
+
const body = [];
|
|
199
|
+
while (peek() && peek() !== '}') {
|
|
200
|
+
if (peek() === 'const' || tokens[at + 1]?.text === '=') {
|
|
201
|
+
const kind = peek() === 'const' ? (take(), 'const') : 'state';
|
|
202
|
+
const name = identifier();
|
|
203
|
+
take('=');
|
|
204
|
+
const value = expression([';']);
|
|
205
|
+
const end = take(';').end;
|
|
206
|
+
body.push({ kind, name: name.text, value, start: name.start, end });
|
|
207
|
+
}
|
|
208
|
+
else
|
|
209
|
+
body.push(element());
|
|
210
|
+
}
|
|
211
|
+
const end = take('}').end;
|
|
212
|
+
module.views.push({ name, body, start, end, exported, default: isDefault });
|
|
213
|
+
}
|
|
214
|
+
if (!module.views.length)
|
|
215
|
+
fail('Expected at least one view');
|
|
216
|
+
return module;
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"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","sourcesContent":["import ts from 'typescript';\nexport interface Location { start: number; end: number }\nexport interface Expression extends Location { source: string }\nexport interface State extends Location { kind: 'state' | 'const'; name: string; value: Expression }\nexport interface Element extends Location { kind: 'element'; name: string; value?: Expression; handler?: Expression; async: boolean; children: Element[] }\nexport interface View extends Location { name: string; exported: boolean; default: boolean; body: (State | Element)[] }\nexport interface Module { source: string; filename: string; imports: Expression[]; views: View[] }\nexport class HeshError extends Error {\n readonly line: number;\n readonly column: number;\n constructor(message: string, readonly source: string, readonly offset: number, readonly filename = 'component.hesh') {\n const lines = source.slice(0, offset).split('\\n');\n const line = lines.length, column = lines.at(-1)!.length + 1;\n super(`${filename}:${line}:${column}: ${message}`);\n this.name = 'HeshError'; this.line = line; this.column = column;\n }\n}\nexport interface Token extends Location { text: string; kind: ts.SyntaxKind }\nexport function tokenize(source: string, filename = 'component.hesh'): Token[] {\n const tokens: Token[] = [];\n const keywords = new Set('break case catch class const continue debugger default delete do else enum export extends false finally for function if import in instanceof new null return super switch this throw true try typeof var void while with yield let static await async'.split(' '));\n let at = 0;\n const fail = (message: string, offset: number): never => { throw new HeshError(message, source, offset, filename); };\n while (at < source.length) {\n const start = at;\n const ch = source[at]!;\n if (/\\s/.test(ch)) { at++; continue; }\n if (source.startsWith('//', at)) { while (at < source.length && source[at] !== '\\n') at++; continue; }\n if (source.startsWith('/*', at)) {\n const end = source.indexOf('*/', at + 2);\n if (end < 0) fail('Unterminated comment', at);\n at = end + 2; continue;\n }\n let kind = ts.SyntaxKind.Unknown;\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n const quote = ch;\n at++; let closed = false;\n while (at < source.length) {\n const current = source[at++]!;\n if (current === '\\\\') { at++; continue; }\n if (quote === '`' && current === '$' && source[at] === '{') fail('Template substitutions belong in imported JS/TS helpers in Milestone 1', at - 1);\n if (current === quote) { closed = true; break; }\n if (quote !== '`' && (current === '\\n' || current === '\\r')) fail('Unterminated string', start);\n }\n if (!closed) fail('Unterminated string', start);\n kind = quote === '`' ? ts.SyntaxKind.NoSubstitutionTemplateLiteral : ts.SyntaxKind.StringLiteral;\n } else if (/[$_\\p{ID_Start}]/u.test(ch)) {\n at++;\n while (at < source.length && /[$\\u200c\\u200d\\p{ID_Continue}]/u.test(source[at]!)) at++;\n kind = keywords.has(source.slice(start, at)) ? ts.SyntaxKind.Unknown : ts.SyntaxKind.Identifier;\n } else if (/\\d/.test(ch)) {\n at++;\n while (at < source.length && /[\\w.]/.test(source[at]!)) at++;\n kind = ts.SyntaxKind.NumericLiteral;\n } else {\n const operator = ['>>>=', '===', '!==', '**=', '&&=', '||=', '??=', '>>>', '<<=', '>>=', '=>', '==', '!=', '<=', '>=', '++', '--', '+=', '-=', '*=', '/=', '%=', '**', '&&', '||', '??', '?.', '<<', '>>', '&=', '|=', '^=', '...'].find(op => source.startsWith(op, at));\n at += operator?.length ?? 1;\n }\n tokens.push({ kind, text: source.slice(start, at), start, end: at });\n }\n return tokens;\n}\n\nexport function parse(source: string, filename = 'component.hesh'): Module {\n const tokens = tokenize(source, filename);\n let at = 0;\n const peek = () => tokens[at]?.text;\n const fail = (message: string, offset = tokens[at]?.start ?? source.length): never => { throw new HeshError(message, source, offset, filename); };\n const take = (text?: string): Token => {\n const token = tokens[at];\n if (!token || (text !== undefined && token.text !== text)) fail(`Expected ${text ?? 'token'}, received ${peek() ?? 'end of file'}`);\n at++; return token!;\n };\n const identifier = () => {\n const token = take();\n if (token.kind !== ts.SyntaxKind.Identifier) fail('Expected identifier', token.start);\n if (token.text.startsWith('__h')) fail('Identifiers beginning __h are reserved', token.start);\n return token;\n };\n const expression = (ends: string[]): Expression => {\n const start = tokens[at]?.start ?? source.length;\n const stack: string[] = [];\n const pairs: Record<string, string> = { '(': ')', '[': ']', '{': '}' };\n while (tokens[at]) {\n const token = tokens[at]!;\n if (!stack.length && ends.includes(token.text)) break;\n if (pairs[token.text]) stack.push(pairs[token.text]!);\n else if ([')', ']', '}'].includes(token.text)) {\n if (stack.pop() !== token.text) fail('Unbalanced expression', token.start);\n }\n at++;\n }\n if (stack.length) fail('Unterminated expression', start);\n const end = tokens[at]?.start ?? source.length;\n if (!source.slice(start, end).trim()) fail('Expected expression', start);\n return { source: source.slice(start, end).trimEnd(), start, end };\n };\n const element = (): Element => {\n const name = identifier(); take('(');\n let value: Expression | undefined, handler: Expression | undefined, async = false;\n if (peek() !== ')') value = expression([',', ')']);\n if (peek() === ',') {\n take(',');\n if (peek() === 'async') { take(); async = true; }\n const start = take('{').end;\n let depth = 1;\n while (tokens[at] && depth) {\n if (peek() === '{') depth++;\n if (peek() === '}') depth--;\n if (depth) at++;\n }\n if (!tokens[at]) fail('Unterminated event block', start);\n const end = take('}').start;\n handler = { source: source.slice(start, end), start, end };\n }\n take(')');\n const children: Element[] = [];\n if (peek() === '{') { take(); while (peek() && peek() !== '}') children.push(element()); take('}'); if (peek() === ';') take(); }\n else take(';');\n return { kind: 'element', name: name.text, start: name.start, end: tokens[at - 1]!.end, value, handler, async, children };\n };\n const module: Module = { source, filename, imports: [], views: [] };\n while (tokens[at]) {\n if (peek() === 'import') {\n if (module.views.length) fail('Imports must precede views');\n const start = take().start;\n while (peek() && peek() !== ';') take();\n const end = take(';').end;\n module.imports.push({ source: source.slice(start, end), start, end }); continue;\n }\n let exported = false, isDefault = false;\n if (peek() === 'export') { take(); exported = true; }\n if (peek() === 'default') { take(); isDefault = true; if (!exported) fail('default requires export'); }\n const start = take('view').start;\n const name = identifier().text; take('{');\n const body: (State | Element)[] = [];\n while (peek() && peek() !== '}') {\n if (peek() === 'const' || tokens[at + 1]?.text === '=') {\n const kind = peek() === 'const' ? (take(), 'const' as const) : 'state' as const;\n const name = identifier(); take('='); const value = expression([';']); const end = take(';').end;\n body.push({ kind, name: name.text, value, start: name.start, end });\n } else body.push(element());\n }\n const end = take('}').end;\n module.views.push({ name, body, start, end, exported, default: isDefault });\n }\n if (!module.views.length) fail('Expected at least one view');\n return module;\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Disposer = () => void;
|
|
2
|
+
export interface Signal<T> {
|
|
3
|
+
get(): T;
|
|
4
|
+
set(value: T): T;
|
|
5
|
+
}
|
|
6
|
+
export declare function signal<T>(initial: T): Signal<T>;
|
|
7
|
+
export declare function onCleanup(fn: Disposer): void;
|
|
8
|
+
export declare function scope<T>(fn: () => T): {
|
|
9
|
+
value: T;
|
|
10
|
+
dispose: Disposer;
|
|
11
|
+
};
|
|
12
|
+
export declare function effect(fn: () => void, computed?: boolean): Disposer;
|
|
13
|
+
export declare function derived<T>(fn: () => T): Pick<Signal<T>, 'get'>;
|
|
14
|
+
export declare function batch<T>(fn: () => T): T;
|
|
15
|
+
export declare function untrack<T>(fn: () => T): T;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
let active;
|
|
2
|
+
let owner;
|
|
3
|
+
let depth = 0;
|
|
4
|
+
let flushing = false;
|
|
5
|
+
const queue = new Set();
|
|
6
|
+
function flush() {
|
|
7
|
+
if (depth || flushing)
|
|
8
|
+
return;
|
|
9
|
+
flushing = true;
|
|
10
|
+
let steps = 0;
|
|
11
|
+
try {
|
|
12
|
+
while (queue.size) {
|
|
13
|
+
if (++steps > 1000)
|
|
14
|
+
throw new Error('HeshJS reactive update limit exceeded');
|
|
15
|
+
const next = [...queue].find(o => o.computed) ?? queue.values().next().value;
|
|
16
|
+
queue.delete(next);
|
|
17
|
+
if (!next.disposed)
|
|
18
|
+
next.run();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
queue.clear();
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
flushing = false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function signal(initial) {
|
|
30
|
+
let value = initial;
|
|
31
|
+
const subscribers = new Set();
|
|
32
|
+
return {
|
|
33
|
+
get() { if (active) {
|
|
34
|
+
subscribers.add(active);
|
|
35
|
+
active.deps.add(subscribers);
|
|
36
|
+
} return value; },
|
|
37
|
+
set(next) {
|
|
38
|
+
if (!Object.is(value, next)) {
|
|
39
|
+
value = next;
|
|
40
|
+
for (const observer of subscribers)
|
|
41
|
+
queue.add(observer);
|
|
42
|
+
flush();
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function onCleanup(fn) {
|
|
49
|
+
if (!owner)
|
|
50
|
+
throw new Error('onCleanup requires a reactive scope');
|
|
51
|
+
if (owner.disposed)
|
|
52
|
+
fn();
|
|
53
|
+
else
|
|
54
|
+
owner.cleanups.add(fn);
|
|
55
|
+
}
|
|
56
|
+
export function scope(fn) {
|
|
57
|
+
const parent = owner;
|
|
58
|
+
const current = { cleanups: new Set(), disposed: false };
|
|
59
|
+
const dispose = () => {
|
|
60
|
+
if (current.disposed)
|
|
61
|
+
return;
|
|
62
|
+
current.disposed = true;
|
|
63
|
+
parent?.cleanups.delete(dispose);
|
|
64
|
+
const errors = [];
|
|
65
|
+
for (const cleanup of [...current.cleanups].reverse()) {
|
|
66
|
+
try {
|
|
67
|
+
cleanup();
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
errors.push(error);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
current.cleanups.clear();
|
|
74
|
+
if (errors.length)
|
|
75
|
+
throw new AggregateError(errors, 'HeshJS cleanup failed');
|
|
76
|
+
};
|
|
77
|
+
parent?.cleanups.add(dispose);
|
|
78
|
+
owner = current;
|
|
79
|
+
try {
|
|
80
|
+
return { value: fn(), dispose };
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
dispose();
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
owner = parent;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
export function effect(fn, computed = false) {
|
|
91
|
+
const owningScope = owner;
|
|
92
|
+
let runScope;
|
|
93
|
+
const observer = {
|
|
94
|
+
deps: new Set(), disposed: false, computed,
|
|
95
|
+
run() {
|
|
96
|
+
for (const dep of observer.deps)
|
|
97
|
+
dep.delete(observer);
|
|
98
|
+
observer.deps.clear();
|
|
99
|
+
runScope?.dispose();
|
|
100
|
+
const previous = active;
|
|
101
|
+
const previousOwner = owner;
|
|
102
|
+
active = observer;
|
|
103
|
+
owner = owningScope;
|
|
104
|
+
depth++;
|
|
105
|
+
try {
|
|
106
|
+
runScope = scope(fn);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
active = previous;
|
|
110
|
+
owner = previousOwner;
|
|
111
|
+
depth--;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const dispose = () => {
|
|
116
|
+
if (observer.disposed)
|
|
117
|
+
return;
|
|
118
|
+
observer.disposed = true;
|
|
119
|
+
owningScope?.cleanups.delete(dispose);
|
|
120
|
+
queue.delete(observer);
|
|
121
|
+
for (const dep of observer.deps)
|
|
122
|
+
dep.delete(observer);
|
|
123
|
+
observer.deps.clear();
|
|
124
|
+
runScope?.dispose();
|
|
125
|
+
};
|
|
126
|
+
owningScope?.cleanups.add(dispose);
|
|
127
|
+
try {
|
|
128
|
+
observer.run();
|
|
129
|
+
flush();
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
dispose();
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
return dispose;
|
|
136
|
+
}
|
|
137
|
+
export function derived(fn) {
|
|
138
|
+
const value = signal(undefined);
|
|
139
|
+
effect(() => value.set(fn()), true);
|
|
140
|
+
return { get: value.get };
|
|
141
|
+
}
|
|
142
|
+
export function batch(fn) {
|
|
143
|
+
depth++;
|
|
144
|
+
try {
|
|
145
|
+
return fn();
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
depth--;
|
|
149
|
+
flush();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function untrack(fn) {
|
|
153
|
+
const previous = active;
|
|
154
|
+
active = undefined;
|
|
155
|
+
try {
|
|
156
|
+
return fn();
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
active = previous;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reactivity/index.ts"],"names":[],"mappings":"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","sourcesContent":["export type Disposer = () => void;\nexport interface Signal<T> { get(): T; set(value: T): T }\ninterface Observer { run(): void; deps: Set<Set<Observer>>; disposed: boolean; computed: boolean }\ninterface Owner { cleanups: Set<Disposer>; disposed: boolean }\nlet active: Observer | undefined;\nlet owner: Owner | undefined;\nlet depth = 0;\nlet flushing = false;\nconst queue = new Set<Observer>();\n\nfunction flush(): void {\n if (depth || flushing) return;\n flushing = true;\n let steps = 0;\n try {\n while (queue.size) {\n if (++steps > 1000) throw new Error('HeshJS reactive update limit exceeded');\n const next = [...queue].find(o => o.computed) ?? queue.values().next().value!;\n queue.delete(next);\n if (!next.disposed) next.run();\n }\n } catch (error) { queue.clear(); throw error; }\n finally { flushing = false; }\n}\n\nexport function signal<T>(initial: T): Signal<T> {\n let value = initial;\n const subscribers = new Set<Observer>();\n return {\n get() { if (active) { subscribers.add(active); active.deps.add(subscribers); } return value; },\n set(next) {\n if (!Object.is(value, next)) {\n value = next;\n for (const observer of subscribers) queue.add(observer);\n flush();\n }\n return value;\n }\n };\n}\n\nexport function onCleanup(fn: Disposer): void {\n if (!owner) throw new Error('onCleanup requires a reactive scope');\n if (owner.disposed) fn(); else owner.cleanups.add(fn);\n}\n\nexport function scope<T>(fn: () => T): { value: T; dispose: Disposer } {\n const parent = owner;\n const current: Owner = { cleanups: new Set(), disposed: false };\n const dispose = () => {\n if (current.disposed) return;\n current.disposed = true;\n parent?.cleanups.delete(dispose);\n const errors: unknown[] = [];\n for (const cleanup of [...current.cleanups].reverse()) {\n try { cleanup(); } catch (error) { errors.push(error); }\n }\n current.cleanups.clear();\n if (errors.length) throw new AggregateError(errors, 'HeshJS cleanup failed');\n };\n parent?.cleanups.add(dispose);\n owner = current;\n try { return { value: fn(), dispose }; }\n catch (error) { dispose(); throw error; }\n finally { owner = parent; }\n}\n\nexport function effect(fn: () => void, computed = false): Disposer {\n const owningScope = owner;\n let runScope: { dispose: Disposer } | undefined;\n const observer: Observer = {\n deps: new Set(), disposed: false, computed,\n run() {\n for (const dep of observer.deps) dep.delete(observer);\n observer.deps.clear();\n runScope?.dispose();\n const previous = active;\n const previousOwner = owner;\n active = observer;\n owner = owningScope;\n depth++;\n try { runScope = scope(fn); }\n finally { active = previous; owner = previousOwner; depth--; }\n }\n };\n const dispose = () => {\n if (observer.disposed) return;\n observer.disposed = true;\n owningScope?.cleanups.delete(dispose);\n queue.delete(observer);\n for (const dep of observer.deps) dep.delete(observer);\n observer.deps.clear();\n runScope?.dispose();\n };\n owningScope?.cleanups.add(dispose);\n try { observer.run(); flush(); } catch (error) { dispose(); throw error; }\n return dispose;\n}\n\nexport function derived<T>(fn: () => T): Pick<Signal<T>, 'get'> {\n const value = signal<T>(undefined as T);\n effect(() => value.set(fn()), true);\n return { get: value.get };\n}\n\nexport function batch<T>(fn: () => T): T {\n depth++;\n try { return fn(); } finally { depth--; flush(); }\n}\n\nexport function untrack<T>(fn: () => T): T {\n const previous = active;\n active = undefined;\n try { return fn(); } finally { active = previous; }\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { compile } from '../compiler/index.js';
|
|
2
|
+
export function hesh() {
|
|
3
|
+
let production = false;
|
|
4
|
+
return {
|
|
5
|
+
name: 'heshjs', enforce: 'pre',
|
|
6
|
+
configResolved(config) { production = config.command === 'build'; },
|
|
7
|
+
transform(source, id) {
|
|
8
|
+
if (!id.endsWith('.hesh'))
|
|
9
|
+
return;
|
|
10
|
+
const result = compile(source, { filename: id, development: !production });
|
|
11
|
+
return { code: result.code, map: null };
|
|
12
|
+
},
|
|
13
|
+
handleHotUpdate(context) {
|
|
14
|
+
if (context.file.endsWith('.hesh')) {
|
|
15
|
+
context.server.ws.send({ type: 'full-reload' });
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vite/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,MAAM,UAAU,IAAI;IAClB,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,OAAO;QACL,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK;QAC9B,cAAc,CAAC,MAAM,IAAI,UAAU,GAAG,MAAM,CAAC,OAAO,KAAK,OAAO,CAAC,CAAC,CAAC;QACnE,SAAS,CAAC,MAAM,EAAE,EAAE;YAClB,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,OAAO;YAClC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,WAAW,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;YAC3E,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QACD,eAAe,CAAC,OAAO;YACrB,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;gBAAC,OAAO,EAAE,CAAC;YAAC,CAAC;QACrG,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { Plugin } from 'vite';\nimport { compile } from '../compiler/index.js';\nexport function hesh(): Plugin {\n let production = false;\n return {\n name: 'heshjs', enforce: 'pre',\n configResolved(config) { production = config.command === 'build'; },\n transform(source, id) {\n if (!id.endsWith('.hesh')) return;\n const result = compile(source, { filename: id, development: !production });\n return { code: result.code, map: null };\n },\n handleHotUpdate(context) {\n if (context.file.endsWith('.hesh')) { context.server.ws.send({ type: 'full-reload' }); return []; }\n }\n };\n}\n"]}
|
package/docs/grammar.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Milestone 1 language (v0.1)
|
|
2
|
+
|
|
3
|
+
The grammar is deliberately smaller than the product roadmap. Source is UTF-8.
|
|
4
|
+
Whitespace and JavaScript comments separate tokens. Identifiers follow JavaScript
|
|
5
|
+
identifier rules. Strings and numbers follow JavaScript lexical rules.
|
|
6
|
+
|
|
7
|
+
```ebnf
|
|
8
|
+
module = { importDecl | view } ;
|
|
9
|
+
view = [ "export" ], [ "default" ], "view", Identifier, "{", { statement }, "}" ;
|
|
10
|
+
statement = state | constant | element ;
|
|
11
|
+
state = Identifier, "=", expression, ";" ;
|
|
12
|
+
constant = "const", Identifier, "=", expression, ";" ;
|
|
13
|
+
element = Identifier, "(", [ expression, [ ",", [ "async" ], handler ] ], ")",
|
|
14
|
+
( ";" | "{", { element }, "}", [ ";" ] ) ;
|
|
15
|
+
handler = "{", { javascriptStatement }, "}" ;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`importDecl` is an ESM import. Expressions and event bodies are parsed with
|
|
19
|
+
TypeScript's JavaScript parser, never evaluated by the compiler. Type annotations
|
|
20
|
+
inside `.hesh` are rejected; use `.ts` modules for typed logic. Imports must precede
|
|
21
|
+
views. Each file may export multiple named views and at most one default view.
|
|
22
|
+
|
|
23
|
+
`count = 0;` declares component-local state; a second declaration is an error.
|
|
24
|
+
State is a shallow signal: assignment and `++`, `--`, compound assignments trigger
|
|
25
|
+
updates. `items.push(x)` and `object.field = x` do **not** notify; assign a new array
|
|
26
|
+
or object instead. Constants are immutable bindings, not deeply frozen objects.
|
|
27
|
+
Initializers execute once per mount in declaration order. There is no derived
|
|
28
|
+
declaration yet. State references in text expressions become tracked reads.
|
|
29
|
+
|
|
30
|
+
`button("+", { count++; });` has an explicit click block inside its argument list.
|
|
31
|
+
A block after `)` contains children, eliminating event/child ambiguity. Event code
|
|
32
|
+
is ordinary JavaScript, with `event` available, lexical local variables, functions,
|
|
33
|
+
and optional `async`. Synchronous and asynchronous errors go to mount's `onError`
|
|
34
|
+
callback (default: `console.error`). Cleanup removes listeners. Async continuations
|
|
35
|
+
are not canceled on unmount; applications must cancel their own async work.
|
|
36
|
+
|
|
37
|
+
Double-quoted strings can interpolate `{expression}`; `"Count: {count}"` becomes
|
|
38
|
+
a sequence of text parts. Braces inside strings use `\{` and `\}`. Interpolation
|
|
39
|
+
expressions may contain nested braces, strings and comments. Single quotes and
|
|
40
|
+
backtick literals use standard JavaScript semantics, without Hesh interpolation.
|
|
41
|
+
The initial lexical envelope does not support backtick `${...}` substitutions or
|
|
42
|
+
regular-expression literals; move these into imported JS/TS
|
|
43
|
+
helpers. Double-quoted Hesh strings support ordinary single-character escapes;
|
|
44
|
+
use single quotes for Unicode/hex escape sequences. Destructuring assignment and
|
|
45
|
+
logical compound assignment to component bindings are rejected. For `for…of` or
|
|
46
|
+
`for…in`, declare a local iteration variable and assign state inside the body.
|
|
47
|
+
|
|
48
|
+
Lowercase names identify native HTML elements. `text` maps to `span`, `card`,
|
|
49
|
+
`row`, `stack`, `grid` to `div`, `image` to `img`, and `link` to `a`. Use a native
|
|
50
|
+
element name for anything else; custom elements use `element("x-widget")` only in
|
|
51
|
+
the public DOM API, not yet in `.hesh`. Unknown uppercase references are errors;
|
|
52
|
+
uppercase view calls mount a locally declared or imported component, with no props
|
|
53
|
+
in this milestone. Views have no parameter syntax yet. Children of a component
|
|
54
|
+
call and click blocks on components are rejected rather than silently discarded.
|
|
55
|
+
|
|
56
|
+
`input(name);` binds a writable state identifier bidirectionally using `input`
|
|
57
|
+
events and its string value. `image(url);` binds a safe `src`. Other values become
|
|
58
|
+
text via `String(value ?? "")`, never HTML. Generic attributes are available in the
|
|
59
|
+
DOM API; declarative attribute syntax is deferred. Event closures may shadow state
|
|
60
|
+
identifiers; lexical resolution preserves those local bindings. Globals and imports
|
|
61
|
+
retain ordinary JavaScript behavior. Unknown unbound names are compile errors.
|
|
62
|
+
|
|
63
|
+
No conditionals, keyed lists, styles, props, TypeScript syntax, slots, or top-level
|
|
64
|
+
JavaScript statements are accepted by this grammar. Future syntax requires a
|
|
65
|
+
versioned grammar change and tests. Unsupported input produces source diagnostics.
|
package/package.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heshammesalam/heshjs",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An experimental independent reactive UI framework with brace-based .hesh components",
|
|
5
|
+
"author": "Hesham",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/heshjs/index.js",
|
|
9
|
+
"types": "./dist/heshjs/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": { "types": "./dist/heshjs/index.d.ts", "import": "./dist/heshjs/index.js" },
|
|
12
|
+
"./reactivity": { "types": "./dist/reactivity/index.d.ts", "import": "./dist/reactivity/index.js" },
|
|
13
|
+
"./dom": { "types": "./dist/dom/index.d.ts", "import": "./dist/dom/index.js" },
|
|
14
|
+
"./parser": { "types": "./dist/parser/index.d.ts", "import": "./dist/parser/index.js" },
|
|
15
|
+
"./compiler": { "types": "./dist/compiler/index.d.ts", "import": "./dist/compiler/index.js" },
|
|
16
|
+
"./vite": { "types": "./dist/vite/index.d.ts", "import": "./dist/vite/index.js" },
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": ["dist", "src", "docs", "README.md"],
|
|
20
|
+
"engines": { "node": ">=22.12.0" },
|
|
21
|
+
"dependencies": { "typescript": "~5.9.3" },
|
|
22
|
+
"peerDependencies": { "vite": "^7.2.2" },
|
|
23
|
+
"peerDependenciesMeta": { "vite": { "optional": true } },
|
|
24
|
+
"publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" }
|
|
25
|
+
}
|
|
26
|
+
|