@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
package/README.md
CHANGED
|
@@ -1,3 +1,43 @@
|
|
|
1
|
-
#
|
|
1
|
+
# HeshJS
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An independent JavaScript/TypeScript UI framework created by Hesham. Experimental
|
|
4
|
+
Milestone 1 release; APIs and grammar may change.
|
|
5
|
+
|
|
6
|
+
Requires Node.js 22.12 or later.
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
npm create @heshammesalam/heshjs@latest my-app
|
|
10
|
+
cd my-app
|
|
11
|
+
npm install
|
|
12
|
+
npm run dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
For TypeScript, use `npm create @heshammesalam/heshjs@latest my-app -- --ts`.
|
|
16
|
+
|
|
17
|
+
```hesh
|
|
18
|
+
export default view Counter {
|
|
19
|
+
count = 0;
|
|
20
|
+
h1("Count: {count}");
|
|
21
|
+
button("+", { count++; });
|
|
22
|
+
button("-", { count--; });
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For an existing Vite app, install `@heshammesalam/heshjs` and add `hesh()` from `@heshammesalam/heshjs/vite`
|
|
27
|
+
to your Vite plugins. Import a default `.hesh` component, then call
|
|
28
|
+
`mount(Component, document.querySelector('#app'))` from `@heshammesalam/heshjs`.
|
|
29
|
+
|
|
30
|
+
ESM entrypoints: `@heshammesalam/heshjs`, `@heshammesalam/heshjs/reactivity`, `@heshammesalam/heshjs/dom`, `@heshammesalam/heshjs/parser`,
|
|
31
|
+
`@heshammesalam/heshjs/compiler`, `@heshammesalam/heshjs/vite`. JavaScript and declarations are included.
|
|
32
|
+
The root entry contains runtime APIs only; compiler/TypeScript code stays out of
|
|
33
|
+
the browser unless explicitly imported. Vite is an optional peer dependency.
|
|
34
|
+
|
|
35
|
+
State is shallow: replace arrays/objects to notify. Component instances own DOM,
|
|
36
|
+
effects and listener cleanup. Async handlers report errors but are not automatically
|
|
37
|
+
canceled on unmount. Hesh edits reload the page. See `docs/grammar.md` for supported
|
|
38
|
+
syntax. Props, conditional rendering, keyed lists, themes, routing, SSR and full
|
|
39
|
+
type checking inside `.hesh` are not yet implemented. TypeScript helpers and
|
|
40
|
+
consumer APIs support strict type checking.
|
|
41
|
+
|
|
42
|
+
This package is published without granting an open-source license (`UNLICENSED`).
|
|
43
|
+
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Module } from '../parser/index.js';
|
|
2
|
+
export interface CompileOptions {
|
|
3
|
+
filename?: string;
|
|
4
|
+
development?: boolean;
|
|
5
|
+
runtime?: string;
|
|
6
|
+
reactivity?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface Binding {
|
|
9
|
+
view: string;
|
|
10
|
+
start: number;
|
|
11
|
+
end: number;
|
|
12
|
+
dependencies: string[];
|
|
13
|
+
kind: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ViewIR {
|
|
16
|
+
name: string;
|
|
17
|
+
exported: boolean;
|
|
18
|
+
default: boolean;
|
|
19
|
+
instructions: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ModuleIR {
|
|
22
|
+
prelude: string[];
|
|
23
|
+
views: ViewIR[];
|
|
24
|
+
bindings: Binding[];
|
|
25
|
+
}
|
|
26
|
+
export interface Result {
|
|
27
|
+
code: string;
|
|
28
|
+
css: string;
|
|
29
|
+
metadata: Binding[];
|
|
30
|
+
ast: Module;
|
|
31
|
+
ir: ModuleIR;
|
|
32
|
+
}
|
|
33
|
+
export declare function compile(source: string, options?: CompileOptions): Result;
|
|
34
|
+
export declare function createCompiler(): {
|
|
35
|
+
compile(source: string, options?: CompileOptions): Result;
|
|
36
|
+
clear(): void;
|
|
37
|
+
};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { parse, tokenize, HeshError } from '../parser/index.js';
|
|
3
|
+
const printer = ts.createPrinter();
|
|
4
|
+
const f = ts.factory;
|
|
5
|
+
export function compile(source, options = {}) {
|
|
6
|
+
const ast = parse(source, options.filename);
|
|
7
|
+
const metadata = [];
|
|
8
|
+
const fail = (message, offset) => { throw new HeshError(message, source, offset, ast.filename); };
|
|
9
|
+
const names = new Set();
|
|
10
|
+
let defaults = 0;
|
|
11
|
+
const imported = new Set();
|
|
12
|
+
const addImport = (name, offset) => {
|
|
13
|
+
if (name.startsWith('__h'))
|
|
14
|
+
fail('Identifiers beginning __h are reserved', offset);
|
|
15
|
+
if (imported.has(name))
|
|
16
|
+
fail(`Duplicate import binding ${name}`, offset);
|
|
17
|
+
imported.add(name);
|
|
18
|
+
};
|
|
19
|
+
for (const item of ast.imports) {
|
|
20
|
+
const diagnostics = ts.transpileModule(item.source, { fileName: 'imports.js', reportDiagnostics: true, compilerOptions: { allowJs: true, module: ts.ModuleKind.ESNext } }).diagnostics;
|
|
21
|
+
if (diagnostics?.length)
|
|
22
|
+
fail(ts.flattenDiagnosticMessageText(diagnostics[0].messageText, '\n'), item.start);
|
|
23
|
+
const parsed = ts.createSourceFile('imports.js', item.source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
24
|
+
const statement = parsed.statements[0];
|
|
25
|
+
if (!statement || !ts.isImportDeclaration(statement))
|
|
26
|
+
fail('Expected ESM import', item.start);
|
|
27
|
+
const clause = statement.importClause;
|
|
28
|
+
if (clause?.name)
|
|
29
|
+
addImport(clause.name.text, item.start);
|
|
30
|
+
const bindings = clause?.namedBindings;
|
|
31
|
+
if (bindings && ts.isNamedImports(bindings))
|
|
32
|
+
bindings.elements.forEach(e => addImport(e.name.text, item.start));
|
|
33
|
+
else if (bindings)
|
|
34
|
+
addImport(bindings.name.text, item.start);
|
|
35
|
+
}
|
|
36
|
+
for (const view of ast.views) {
|
|
37
|
+
if (!/^[A-Z]/.test(view.name))
|
|
38
|
+
fail('View names must begin with an uppercase letter', view.start);
|
|
39
|
+
if (names.has(view.name) || imported.has(view.name))
|
|
40
|
+
fail(`Duplicate component ${view.name}`, view.start);
|
|
41
|
+
names.add(view.name);
|
|
42
|
+
if (view.default && ++defaults > 1)
|
|
43
|
+
fail('Only one default view is allowed', view.start);
|
|
44
|
+
}
|
|
45
|
+
const prelude = [
|
|
46
|
+
`import { signal as __hSignal } from ${JSON.stringify(options.reactivity ?? '@heshammesalam/heshjs/reactivity')};`,
|
|
47
|
+
`import * as __hDOM from ${JSON.stringify(options.runtime ?? '@heshammesalam/heshjs/dom')};`,
|
|
48
|
+
...ast.imports.map(i => i.source),
|
|
49
|
+
'const __hUpdate = (s, delta, post) => { const value = s.get(); const old = typeof value === "bigint" ? value : +value; const next = typeof old === "bigint" ? old + BigInt(delta) : old + delta; s.set(next); return post ? old : next; };'
|
|
50
|
+
];
|
|
51
|
+
const views = [];
|
|
52
|
+
for (const view of ast.views) {
|
|
53
|
+
const output = [];
|
|
54
|
+
const states = new Set(), constants = new Set();
|
|
55
|
+
for (const node of view.body)
|
|
56
|
+
if (node.kind !== 'element') {
|
|
57
|
+
if (states.has(node.name) || constants.has(node.name) || imported.has(node.name) || names.has(node.name))
|
|
58
|
+
fail(`Duplicate binding ${node.name}`, node.start);
|
|
59
|
+
(node.kind === 'state' ? states : constants).add(node.name);
|
|
60
|
+
}
|
|
61
|
+
let serial = 0;
|
|
62
|
+
const available = new Set();
|
|
63
|
+
const transform = (expression, handler = false, async = false) => {
|
|
64
|
+
const declarations = [...states, ...constants].map(name => `${constants.has(name) ? 'const' : 'let'} ${name} = undefined;`).join('\n');
|
|
65
|
+
const prefix = `${ast.imports.map(i => i.source).join('\n')}\n${[...names].map(n => `function ${n}() {}`).join('\n')}\nfunction __hContext() {\n${declarations}\n${async ? 'async ' : ''}function __hExpression(${handler ? 'event' : ''}) {\n${handler ? '' : 'return ('}`;
|
|
66
|
+
const text = prefix + expression.source + (handler ? '' : ');') + '\n}\n}';
|
|
67
|
+
const filename = '/__hesh_expression__.js';
|
|
68
|
+
const settings = { allowJs: true, checkJs: true, target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext, noEmit: true };
|
|
69
|
+
const host = ts.createCompilerHost(settings);
|
|
70
|
+
const original = host.getSourceFile.bind(host);
|
|
71
|
+
host.getSourceFile = (name, languageVersion, onError, shouldCreate) => name === filename ? ts.createSourceFile(name, text, languageVersion, true, ts.ScriptKind.JS) : original(name, languageVersion, onError, shouldCreate);
|
|
72
|
+
const program = ts.createProgram([filename], settings, host);
|
|
73
|
+
const file = program.getSourceFile(filename);
|
|
74
|
+
const diagnostics = program.getSyntacticDiagnostics(file);
|
|
75
|
+
if (diagnostics.length) {
|
|
76
|
+
const d = diagnostics[0];
|
|
77
|
+
fail(ts.flattenDiagnosticMessageText(d.messageText, '\n'), expression.start + Math.max(0, (d.start ?? prefix.length) - prefix.length));
|
|
78
|
+
}
|
|
79
|
+
const checker = program.getTypeChecker();
|
|
80
|
+
const context = file.statements.find(n => ts.isFunctionDeclaration(n) && n.name?.text === '__hContext');
|
|
81
|
+
const symbols = new Map();
|
|
82
|
+
for (const stmt of context.body.statements)
|
|
83
|
+
if (ts.isVariableStatement(stmt)) {
|
|
84
|
+
const name = stmt.declarationList.declarations[0].name;
|
|
85
|
+
symbols.set(checker.getSymbolAtLocation(name), name.text);
|
|
86
|
+
}
|
|
87
|
+
const fn = context.body.statements.at(-1);
|
|
88
|
+
const dependencies = new Set();
|
|
89
|
+
const stateName = (node) => {
|
|
90
|
+
if (!ts.isIdentifier(node))
|
|
91
|
+
return;
|
|
92
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
93
|
+
const name = symbol ? symbols.get(symbol) : undefined;
|
|
94
|
+
if (name && !handler && !available.has(name))
|
|
95
|
+
fail(`Binding ${name} is used before initialization`, expression.start);
|
|
96
|
+
return name;
|
|
97
|
+
};
|
|
98
|
+
const read = (name) => f.createCallExpression(f.createPropertyAccessExpression(f.createIdentifier(name), 'get'), undefined, []);
|
|
99
|
+
const write = (name, value) => f.createCallExpression(f.createPropertyAccessExpression(f.createIdentifier(name), 'set'), undefined, [value]);
|
|
100
|
+
const result = ts.transform(fn.body, [context => {
|
|
101
|
+
const visit = node => {
|
|
102
|
+
if (ts.isIdentifier(node) && node.text.startsWith('__h'))
|
|
103
|
+
fail('Identifiers beginning __h are reserved', expression.start + Math.max(0, node.getStart(file) - prefix.length));
|
|
104
|
+
if ((ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && [ts.SyntaxKind.PlusPlusToken, ts.SyntaxKind.MinusMinusToken].includes(node.operator)) {
|
|
105
|
+
const name = stateName(node.operand);
|
|
106
|
+
if (name) {
|
|
107
|
+
dependencies.add(name);
|
|
108
|
+
if (constants.has(name))
|
|
109
|
+
fail(`Cannot assign constant ${name}`, expression.start);
|
|
110
|
+
const delta = node.operator === ts.SyntaxKind.PlusPlusToken ? f.createNumericLiteral(1) : f.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, f.createNumericLiteral(1));
|
|
111
|
+
return f.createCallExpression(f.createIdentifier('__hUpdate'), undefined, [f.createIdentifier(name), delta, node.kind === ts.SyntaxKind.PostfixUnaryExpression ? f.createTrue() : f.createFalse()]);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment) {
|
|
115
|
+
if (ts.isArrayLiteralExpression(node.left) || ts.isObjectLiteralExpression(node.left)) {
|
|
116
|
+
const checkTarget = (target) => {
|
|
117
|
+
const name = stateName(target);
|
|
118
|
+
if (name)
|
|
119
|
+
fail('Destructuring assignments to component bindings are not supported', expression.start);
|
|
120
|
+
ts.forEachChild(target, checkTarget);
|
|
121
|
+
};
|
|
122
|
+
checkTarget(node.left);
|
|
123
|
+
}
|
|
124
|
+
const name = stateName(node.left);
|
|
125
|
+
if (name) {
|
|
126
|
+
dependencies.add(name);
|
|
127
|
+
if (constants.has(name))
|
|
128
|
+
fail(`Cannot assign constant ${name}`, expression.start);
|
|
129
|
+
const right = ts.visitNode(node.right, visit);
|
|
130
|
+
if (node.operatorToken.kind === ts.SyntaxKind.EqualsToken)
|
|
131
|
+
return write(name, right);
|
|
132
|
+
const operators = {
|
|
133
|
+
[ts.SyntaxKind.PlusEqualsToken]: ts.SyntaxKind.PlusToken, [ts.SyntaxKind.MinusEqualsToken]: ts.SyntaxKind.MinusToken,
|
|
134
|
+
[ts.SyntaxKind.AsteriskEqualsToken]: ts.SyntaxKind.AsteriskToken, [ts.SyntaxKind.SlashEqualsToken]: ts.SyntaxKind.SlashToken,
|
|
135
|
+
[ts.SyntaxKind.PercentEqualsToken]: ts.SyntaxKind.PercentToken, [ts.SyntaxKind.AsteriskAsteriskEqualsToken]: ts.SyntaxKind.AsteriskAsteriskToken,
|
|
136
|
+
[ts.SyntaxKind.AmpersandEqualsToken]: ts.SyntaxKind.AmpersandToken, [ts.SyntaxKind.BarEqualsToken]: ts.SyntaxKind.BarToken,
|
|
137
|
+
[ts.SyntaxKind.CaretEqualsToken]: ts.SyntaxKind.CaretToken, [ts.SyntaxKind.LessThanLessThanEqualsToken]: ts.SyntaxKind.LessThanLessThanToken,
|
|
138
|
+
[ts.SyntaxKind.GreaterThanGreaterThanEqualsToken]: ts.SyntaxKind.GreaterThanGreaterThanToken, [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken
|
|
139
|
+
};
|
|
140
|
+
const op = operators[node.operatorToken.kind];
|
|
141
|
+
if (!op)
|
|
142
|
+
fail('Logical assignment to state is not supported yet', expression.start);
|
|
143
|
+
return write(name, f.createBinaryExpression(read(name), op, right));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (ts.isShorthandPropertyAssignment(node)) {
|
|
147
|
+
const symbol = checker.getShorthandAssignmentValueSymbol(node);
|
|
148
|
+
const name = symbol && symbols.get(symbol);
|
|
149
|
+
if (name && !handler && !available.has(name))
|
|
150
|
+
fail(`Binding ${name} is used before initialization`, expression.start);
|
|
151
|
+
if (name && states.has(name)) {
|
|
152
|
+
dependencies.add(name);
|
|
153
|
+
return f.createPropertyAssignment(node.name.text, read(name));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (ts.isIdentifier(node)) {
|
|
157
|
+
const name = stateName(node);
|
|
158
|
+
if (name && !handler && !available.has(name))
|
|
159
|
+
fail(`Binding ${name} is used before initialization`, expression.start);
|
|
160
|
+
if (name && states.has(name)) {
|
|
161
|
+
dependencies.add(name);
|
|
162
|
+
return read(name);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if ((ts.isForOfStatement(node) || ts.isForInStatement(node)) && stateName(node.initializer))
|
|
166
|
+
fail('Use a local loop variable, then assign state in the loop body', expression.start);
|
|
167
|
+
return ts.visitEachChild(node, visit, context);
|
|
168
|
+
};
|
|
169
|
+
return node => ts.visitNode(node, visit);
|
|
170
|
+
}]);
|
|
171
|
+
// Report unresolved names while leaving module resolution and imported types to Vite/tsc.
|
|
172
|
+
for (const d of program.getSemanticDiagnostics(file))
|
|
173
|
+
if ((d.code < 2000 || [2304, 2552, 2588].includes(d.code)) && (d.start ?? 0) >= prefix.length && (d.start ?? 0) < prefix.length + expression.source.length) {
|
|
174
|
+
fail(ts.flattenDiagnosticMessageText(d.messageText, '\n'), expression.start + d.start - prefix.length);
|
|
175
|
+
}
|
|
176
|
+
const body = result.transformed[0];
|
|
177
|
+
metadata.push({ view: view.name, start: expression.start, end: expression.end, dependencies: [...dependencies].sort(), kind: handler ? 'event' : 'expression' });
|
|
178
|
+
let rendered;
|
|
179
|
+
if (handler)
|
|
180
|
+
rendered = printer.printNode(ts.EmitHint.Unspecified, body, file);
|
|
181
|
+
else
|
|
182
|
+
rendered = printer.printNode(ts.EmitHint.Expression, body.statements[0].expression, file);
|
|
183
|
+
result.dispose();
|
|
184
|
+
return rendered;
|
|
185
|
+
};
|
|
186
|
+
const value = (expr) => {
|
|
187
|
+
if (!expr.source.startsWith('"'))
|
|
188
|
+
return transform(expr);
|
|
189
|
+
const tokens = tokenize(expr.source);
|
|
190
|
+
if (tokens.length !== 1 || tokens[0].kind !== ts.SyntaxKind.StringLiteral)
|
|
191
|
+
return transform(expr);
|
|
192
|
+
const raw = expr.source.slice(1, -1);
|
|
193
|
+
const parts = [];
|
|
194
|
+
let literal = '', i = 0;
|
|
195
|
+
const emit = () => { if (literal) {
|
|
196
|
+
parts.push(JSON.stringify(literal));
|
|
197
|
+
literal = '';
|
|
198
|
+
} };
|
|
199
|
+
while (i < raw.length) {
|
|
200
|
+
if (raw[i] === '\\') {
|
|
201
|
+
const next = raw[++i];
|
|
202
|
+
const escapes = { n: '\n', r: '\r', t: '\t', b: '\b', f: '\f', v: '\v', '0': '\0' };
|
|
203
|
+
if (next === 'u' || next === 'x')
|
|
204
|
+
fail('Use single quotes for Unicode/hex escapes in literal strings', expr.start + i);
|
|
205
|
+
literal += escapes[next ?? ''] ?? next ?? '';
|
|
206
|
+
i++;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (raw[i] !== '{') {
|
|
210
|
+
literal += raw[i++];
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
emit();
|
|
214
|
+
const start = ++i;
|
|
215
|
+
const nested = tokenize(raw.slice(start));
|
|
216
|
+
let depth = 1, end = -1;
|
|
217
|
+
for (const token of nested) {
|
|
218
|
+
if (token.text === '{')
|
|
219
|
+
depth++;
|
|
220
|
+
if (token.text === '}' && --depth === 0) {
|
|
221
|
+
end = start + token.start;
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (end < 0)
|
|
226
|
+
fail('Unterminated text interpolation', expr.start + start);
|
|
227
|
+
parts.push(`String(${transform({ source: raw.slice(start, end), start: expr.start + 1 + start, end: expr.start + 1 + end })} ?? "")`);
|
|
228
|
+
i = end + 1;
|
|
229
|
+
}
|
|
230
|
+
emit();
|
|
231
|
+
return parts.length ? parts.join(' + ') : '""';
|
|
232
|
+
};
|
|
233
|
+
const emit = (node, parent) => {
|
|
234
|
+
if (/^[A-Z]/.test(node.name)) {
|
|
235
|
+
if (!names.has(node.name) && !imported.has(node.name))
|
|
236
|
+
fail(`Unknown component ${node.name}`, node.start);
|
|
237
|
+
if (node.value || node.handler || node.children.length)
|
|
238
|
+
fail('Component props, event blocks and slots are not supported in Milestone 1', node.start);
|
|
239
|
+
output.push(`__hDOM.component(${parent}, ${node.name});`);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const id = `__hNode${serial++}`;
|
|
243
|
+
output.push(`const ${id} = __hDOM.element(${parent}, ${JSON.stringify(node.name)});`);
|
|
244
|
+
if (node.value) {
|
|
245
|
+
if (node.name === 'input') {
|
|
246
|
+
if (!states.has(node.value.source.trim()) || !available.has(node.value.source.trim()))
|
|
247
|
+
fail('input requires an initialized state identifier', node.value.start);
|
|
248
|
+
output.push(`__hDOM.input(${id}, ${node.value.source});`);
|
|
249
|
+
}
|
|
250
|
+
else if (node.name === 'image' || node.name === 'img')
|
|
251
|
+
output.push(`__hDOM.attribute(${id}, "src", () => ${value(node.value)});`);
|
|
252
|
+
else
|
|
253
|
+
output.push(`__hDOM.text(${id}, () => ${value(node.value)});`);
|
|
254
|
+
}
|
|
255
|
+
if (node.handler)
|
|
256
|
+
output.push(`__hDOM.listen(${id}, "click", ${node.async ? 'async ' : ''}(event) => ${transform(node.handler, true, node.async)});`);
|
|
257
|
+
node.children.forEach(child => emit(child, id));
|
|
258
|
+
};
|
|
259
|
+
for (const node of view.body) {
|
|
260
|
+
if (node.kind === 'element')
|
|
261
|
+
emit(node, '__hParent');
|
|
262
|
+
else {
|
|
263
|
+
output.push(`const ${node.name} = ${node.kind === 'state' ? '__hSignal(' : ''}${transform(node.value)}${node.kind === 'state' ? ')' : ''};`);
|
|
264
|
+
available.add(node.name);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
views.push({ name: view.name, exported: view.exported, default: view.default, instructions: output });
|
|
268
|
+
}
|
|
269
|
+
const ir = { prelude, views, bindings: options.development === false ? [] : metadata };
|
|
270
|
+
const output = [...ir.prelude, ...ir.views.flatMap(view => [
|
|
271
|
+
`${view.exported ? 'export ' : ''}${view.default ? 'default ' : ''}function ${view.name}(__hParent) {`,
|
|
272
|
+
...view.instructions.map(instruction => instruction.split('\n').map(line => ` ${line}`).join('\n')),
|
|
273
|
+
'}'
|
|
274
|
+
])];
|
|
275
|
+
if (options.development !== false)
|
|
276
|
+
output.push(`export const __hesh = ${JSON.stringify(metadata)};`);
|
|
277
|
+
return { code: output.join('\n'), css: '', metadata: options.development === false ? [] : metadata, ast, ir };
|
|
278
|
+
}
|
|
279
|
+
export function createCompiler() {
|
|
280
|
+
const cache = new Map();
|
|
281
|
+
return {
|
|
282
|
+
compile(source, options = {}) {
|
|
283
|
+
const key = JSON.stringify([source, options]);
|
|
284
|
+
let result = cache.get(key);
|
|
285
|
+
if (!result) {
|
|
286
|
+
result = compile(source, options);
|
|
287
|
+
cache.set(key, result);
|
|
288
|
+
}
|
|
289
|
+
return result;
|
|
290
|
+
},
|
|
291
|
+
clear() { cache.clear(); }
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compiler/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAA8C,MAAM,oBAAoB,CAAC;AAO5G,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC;AACnC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;AAErB,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,UAA0B,EAAE;IAClE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,CAAC,OAAe,EAAE,MAAc,EAAS,EAAE,GAAG,MAAM,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACzH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,MAAc,EAAQ,EAAE;QACvD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;YAAE,IAAI,CAAC,wCAAwC,EAAE,MAAM,CAAC,CAAC;QACnF,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,4BAA4B,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;QACzE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACrB,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC;QACvL,IAAI,WAAW,EAAE,MAAM;YAAE,IAAI,CAAC,EAAE,CAAC,4BAA4B,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9G,MAAM,MAAM,GAAG,EAAE,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC9G,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvC,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,SAAS,CAAC;YAAE,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAI,SAAkC,CAAC,YAAY,CAAC;QAChE,IAAI,MAAM,EAAE,IAAI;YAAE,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,MAAM,EAAE,aAAa,CAAC;QACvC,IAAI,QAAQ,IAAI,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC;YAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;aAC3G,IAAI,QAAQ;YAAE,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,gDAAgD,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAClG,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,IAAI,CAAC,uBAAuB,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1G,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,QAAQ,GAAG,CAAC;YAAE,IAAI,CAAC,kCAAkC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3F,CAAC;IACD,MAAM,OAAO,GAAG;QACd,uCAAuC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,UAAU,IAAI,kCAAkC,CAAC,GAAG;QAClH,2BAA2B,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,IAAI,2BAA2B,CAAC,GAAG;QAC5F,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;QACjC,4OAA4O;KAC7O,CAAC;IACF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,EAAE,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QAChE,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI;YAAE,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC1D,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,qBAAqB,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC7J,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9D,CAAC;QACD,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;QACpC,MAAM,SAAS,GAAG,CAAC,UAAsB,EAAE,OAAO,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK,EAAU,EAAE;YACnF,MAAM,YAAY,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,eAAe,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvI,MAAM,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,8BAA8B,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,0BAA0B,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC;YAC5Q,MAAM,IAAI,GAAG,MAAM,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;YAC3E,MAAM,QAAQ,GAAG,yBAAyB,CAAC;YAC3C,MAAM,QAAQ,GAAuB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;YAClJ,MAAM,IAAI,GAAG,EAAE,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,IAAI,CAAC,aAAa,GAAG,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;YAC7N,MAAM,OAAO,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAE,CAAC;YAC9C,MAAM,WAAW,GAAG,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC;YAC1D,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;gBACvB,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAE,CAAC;gBAC1B,IAAI,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACzI,CAAC;YACD,MAAM,OAAO,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,YAAY,CAA2B,CAAC;YAClI,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqB,CAAC;YAC7C,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,IAAK,CAAC,UAAU;gBAAE,IAAI,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC,CAAE,CAAC,IAAqB,CAAC;oBACzE,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC7D,CAAC;YACD,MAAM,EAAE,GAAG,OAAO,CAAC,IAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAA2B,CAAC;YACrE,MAAM,YAAY,GAAG,IAAI,GAAG,EAAU,CAAC;YACvC,MAAM,SAAS,GAAG,CAAC,IAAa,EAAsB,EAAE;gBACtD,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC;oBAAE,OAAO;gBACnC,MAAM,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBACjD,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACtD,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,WAAW,IAAI,gCAAgC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;gBACtH,OAAO,IAAI,CAAC;YACd,CAAC,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;YACxI,MAAM,KAAK,GAAG,CAAC,IAAY,EAAE,KAAoB,EAAE,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YACpK,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,IAAK,EAAE,CAAC,OAAO,CAAC,EAAE;oBAC/C,MAAM,KAAK,GAAe,IAAI,CAAC,EAAE;wBAC/B,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;4BAAE,IAAI,CAAC,wCAAwC,EAAE,UAAU,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;wBAC9K,IAAI,CAAC,EAAE,CAAC,uBAAuB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;4BACpK,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;4BACrC,IAAI,IAAI,EAAE,CAAC;gCACT,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gCACvB,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;oCAAE,IAAI,CAAC,0BAA0B,IAAI,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;gCAClF,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,2BAA2B,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;gCAC7K,OAAO,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;4BACtM,CAAC;wBACH,CAAC;wBACD,IAAI,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC;4BACvJ,IAAI,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,yBAAyB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gCACtF,MAAM,WAAW,GAAG,CAAC,MAAe,EAAQ,EAAE;oCAC5C,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;oCAC/B,IAAI,IAAI;wCAAE,IAAI,CAAC,mEAAmE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;oCACtG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;gCACvC,CAAC,CAAC;gCACF,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BACzB,CAAC;4BACD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;4BAClC,IAAI,IAAI,EAAE,CAAC;gCACT,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gCACvB,IAAI,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;oCAAE,IAAI,CAAC,0BAA0B,IAAI,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;gCAClF,MAAM,KAAK,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAkB,CAAC;gCAC/D,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,WAAW;oCAAE,OAAO,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gCACrF,MAAM,SAAS,GAAsD;oCACnE,CAAC,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU;oCACpH,CAAC,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU;oCAC5H,CAAC,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,2BAA2B,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,qBAAqB;oCAChJ,CAAC,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ;oCAC1H,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,2BAA2B,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,qBAAqB;oCAC5I,CAAC,EAAE,CAAC,UAAU,CAAC,iCAAiC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,2BAA2B,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,4CAA4C,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,sCAAsC;iCACjN,CAAC;gCACF,MAAM,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gCAC9C,IAAI,CAAC,EAAE;oCAAE,IAAI,CAAC,kDAAkD,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;gCACpF,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,sBAAsB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAG,EAAE,KAAK,CAAC,CAAC,CAAC;4BACvE,CAAC;wBACH,CAAC;wBACD,IAAI,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,iCAAiC,CAAC,IAAI,CAAC,CAAC;4BAC/D,MAAM,IAAI,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;4BAC3C,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;gCAAE,IAAI,CAAC,WAAW,IAAI,gCAAgC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;4BACtH,IAAI,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gCAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gCAAC,OAAO,CAAC,CAAC,wBAAwB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;4BAAC,CAAC;wBAC1H,CAAC;wBACD,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;4BAC1B,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;4BAC7B,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;gCAAE,IAAI,CAAC,WAAW,IAAI,gCAAgC,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;4BACtH,IAAI,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gCAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gCAAC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC;4BAAC,CAAC;wBAC9E,CAAC;wBACD,IAAI,CAAC,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC;4BAAE,IAAI,CAAC,+DAA+D,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;wBACrL,OAAO,EAAE,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;oBACjD,CAAC,CAAC;oBACF,OAAO,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAa,CAAC;gBACvD,CAAC,CAAC,CAAC,CAAC;YACJ,0FAA0F;YAC1F,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,sBAAsB,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;oBACjN,IAAI,CAAC,EAAE,CAAC,4BAA4B,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,KAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC1G,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAa,CAAC;YAC/C,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;YACjK,IAAI,QAAgB,CAAC;YACrB,IAAI,OAAO;gBAAE,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;;gBAC1E,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAwB,CAAC,UAAW,EAAE,IAAI,CAAC,CAAC;YACxH,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,QAAQ,CAAC;QAClB,CAAC,CAAC;QACF,MAAM,KAAK,GAAG,CAAC,IAAgB,EAAU,EAAE;YACzC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;YACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,CAAE,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,CAAC,aAAa;gBAAE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;YACnG,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,IAAI,OAAO,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,IAAI,GAAG,GAAG,EAAE,GAAG,IAAI,OAAO,EAAE,CAAC;gBAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;YAAC,CAAC,CAAC,CAAC,CAAC;YAC3F,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;gBACtB,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;oBACpB,MAAM,IAAI,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;oBACtB,MAAM,OAAO,GAA2B,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;oBAC5G,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG;wBAAE,IAAI,CAAC,8DAA8D,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;oBACvH,OAAO,IAAI,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;oBAAC,CAAC,EAAE,CAAC;oBAAC,SAAS;gBAC9D,CAAC;gBACD,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAAC,OAAO,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;oBAAC,SAAS;gBAAC,CAAC;gBACtD,IAAI,EAAE,CAAC;gBAAC,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC;gBAC1B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;gBAAC,IAAI,KAAK,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;gBACnE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAAC,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG;wBAAE,KAAK,EAAE,CAAC;oBAAC,IAAI,KAAK,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC;wBAAC,GAAG,GAAG,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;wBAAC,MAAM;oBAAC,CAAC;gBAAC,CAAC;gBAC/I,IAAI,GAAG,GAAG,CAAC;oBAAE,IAAI,CAAC,iCAAiC,EAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;gBACzE,KAAK,CAAC,IAAI,CAAC,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBACtI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC;YACd,CAAC;YACD,IAAI,EAAE,CAAC;YAAC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,CAAC,IAAa,EAAE,MAAc,EAAQ,EAAE;YACnD,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;oBAAE,IAAI,CAAC,qBAAqB,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1G,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM;oBAAE,IAAI,CAAC,0EAA0E,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBACrJ,MAAM,CAAC,IAAI,CAAC,oBAAoB,MAAM,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;gBAAC,OAAO;YACpE,CAAC;YACD,MAAM,EAAE,GAAG,UAAU,MAAM,EAAE,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,qBAAqB,MAAM,KAAK,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAC1B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;wBAAE,IAAI,CAAC,gDAAgD,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;oBAChK,MAAM,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;gBAC5D,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;oBAAE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,kBAAkB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;;oBAC/H,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACtE,CAAC;YACD,IAAI,IAAI,CAAC,OAAO;gBAAE,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,cAAc,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,cAAc,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACtJ,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC7B,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS;gBAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;iBAChD,CAAC;gBAAC,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;gBAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAC,CAAC;QAClL,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;IACxG,CAAC;IACD,MAAM,EAAE,GAAa,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACjG,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACzD,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,IAAI,CAAC,IAAI,eAAe;YACtG,GAAG,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpG,GAAG;SACJ,CAAC,CAAC,CAAC;IACJ,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK;QAAE,MAAM,CAAC,IAAI,CAAC,yBAAyB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrG,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;AAChH,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,OAAO;QACL,OAAO,CAAC,MAAc,EAAE,UAA0B,EAAE;YAClD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;YAC9C,IAAI,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;gBAAC,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAAC,CAAC;YAC3E,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,KAAK,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;KAC3B,CAAC;AACJ,CAAC","sourcesContent":["import ts from 'typescript';\nimport { parse, tokenize, HeshError, type Expression, type Element, type Module } from '../parser/index.js';\n\nexport interface CompileOptions { filename?: string; development?: boolean; runtime?: string; reactivity?: string }\nexport interface Binding { view: string; start: number; end: number; dependencies: string[]; kind: string }\nexport interface ViewIR { name: string; exported: boolean; default: boolean; instructions: string[] }\nexport interface ModuleIR { prelude: string[]; views: ViewIR[]; bindings: Binding[] }\nexport interface Result { code: string; css: string; metadata: Binding[]; ast: Module; ir: ModuleIR }\nconst printer = ts.createPrinter();\nconst f = ts.factory;\n\nexport function compile(source: string, options: CompileOptions = {}): Result {\n const ast = parse(source, options.filename);\n const metadata: Binding[] = [];\n const fail = (message: string, offset: number): never => { throw new HeshError(message, source, offset, ast.filename); };\n const names = new Set<string>();\n let defaults = 0;\n const imported = new Set<string>();\n const addImport = (name: string, offset: number): void => {\n if (name.startsWith('__h')) fail('Identifiers beginning __h are reserved', offset);\n if (imported.has(name)) fail(`Duplicate import binding ${name}`, offset);\n imported.add(name);\n };\n for (const item of ast.imports) {\n const diagnostics = ts.transpileModule(item.source, { fileName: 'imports.js', reportDiagnostics: true, compilerOptions: { allowJs: true, module: ts.ModuleKind.ESNext } }).diagnostics;\n if (diagnostics?.length) fail(ts.flattenDiagnosticMessageText(diagnostics[0]!.messageText, '\\n'), item.start);\n const parsed = ts.createSourceFile('imports.js', item.source, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);\n const statement = parsed.statements[0];\n if (!statement || !ts.isImportDeclaration(statement)) fail('Expected ESM import', item.start);\n const clause = (statement as ts.ImportDeclaration).importClause;\n if (clause?.name) addImport(clause.name.text, item.start);\n const bindings = clause?.namedBindings;\n if (bindings && ts.isNamedImports(bindings)) bindings.elements.forEach(e => addImport(e.name.text, item.start));\n else if (bindings) addImport(bindings.name.text, item.start);\n }\n for (const view of ast.views) {\n if (!/^[A-Z]/.test(view.name)) fail('View names must begin with an uppercase letter', view.start);\n if (names.has(view.name) || imported.has(view.name)) fail(`Duplicate component ${view.name}`, view.start);\n names.add(view.name);\n if (view.default && ++defaults > 1) fail('Only one default view is allowed', view.start);\n }\n const prelude = [\n `import { signal as __hSignal } from ${JSON.stringify(options.reactivity ?? '@heshammesalam/heshjs/reactivity')};`,\n `import * as __hDOM from ${JSON.stringify(options.runtime ?? '@heshammesalam/heshjs/dom')};`,\n ...ast.imports.map(i => i.source),\n 'const __hUpdate = (s, delta, post) => { const value = s.get(); const old = typeof value === \"bigint\" ? value : +value; const next = typeof old === \"bigint\" ? old + BigInt(delta) : old + delta; s.set(next); return post ? old : next; };'\n ];\n const views: ViewIR[] = [];\n for (const view of ast.views) {\n const output: string[] = [];\n const states = new Set<string>(), constants = new Set<string>();\n for (const node of view.body) if (node.kind !== 'element') {\n if (states.has(node.name) || constants.has(node.name) || imported.has(node.name) || names.has(node.name)) fail(`Duplicate binding ${node.name}`, node.start);\n (node.kind === 'state' ? states : constants).add(node.name);\n }\n let serial = 0;\n const available = new Set<string>();\n const transform = (expression: Expression, handler = false, async = false): string => {\n const declarations = [...states, ...constants].map(name => `${constants.has(name) ? 'const' : 'let'} ${name} = undefined;`).join('\\n');\n const prefix = `${ast.imports.map(i => i.source).join('\\n')}\\n${[...names].map(n => `function ${n}() {}`).join('\\n')}\\nfunction __hContext() {\\n${declarations}\\n${async ? 'async ' : ''}function __hExpression(${handler ? 'event' : ''}) {\\n${handler ? '' : 'return ('}`;\n const text = prefix + expression.source + (handler ? '' : ');') + '\\n}\\n}';\n const filename = '/__hesh_expression__.js';\n const settings: ts.CompilerOptions = { allowJs: true, checkJs: true, target: ts.ScriptTarget.ESNext, module: ts.ModuleKind.ESNext, noEmit: true };\n const host = ts.createCompilerHost(settings);\n const original = host.getSourceFile.bind(host);\n host.getSourceFile = (name, languageVersion, onError, shouldCreate) => name === filename ? ts.createSourceFile(name, text, languageVersion, true, ts.ScriptKind.JS) : original(name, languageVersion, onError, shouldCreate);\n const program = ts.createProgram([filename], settings, host);\n const file = program.getSourceFile(filename)!;\n const diagnostics = program.getSyntacticDiagnostics(file);\n if (diagnostics.length) {\n const d = diagnostics[0]!;\n fail(ts.flattenDiagnosticMessageText(d.messageText, '\\n'), expression.start + Math.max(0, (d.start ?? prefix.length) - prefix.length));\n }\n const checker = program.getTypeChecker();\n const context = file.statements.find(n => ts.isFunctionDeclaration(n) && n.name?.text === '__hContext') as ts.FunctionDeclaration;\n const symbols = new Map<ts.Symbol, string>();\n for (const stmt of context.body!.statements) if (ts.isVariableStatement(stmt)) {\n const name = stmt.declarationList.declarations[0]!.name as ts.Identifier;\n symbols.set(checker.getSymbolAtLocation(name)!, name.text);\n }\n const fn = context.body!.statements.at(-1) as ts.FunctionDeclaration;\n const dependencies = new Set<string>();\n const stateName = (node: ts.Node): string | undefined => {\n if (!ts.isIdentifier(node)) return;\n const symbol = checker.getSymbolAtLocation(node);\n const name = symbol ? symbols.get(symbol) : undefined;\n if (name && !handler && !available.has(name)) fail(`Binding ${name} is used before initialization`, expression.start);\n return name;\n };\n const read = (name: string) => f.createCallExpression(f.createPropertyAccessExpression(f.createIdentifier(name), 'get'), undefined, []);\n const write = (name: string, value: ts.Expression) => f.createCallExpression(f.createPropertyAccessExpression(f.createIdentifier(name), 'set'), undefined, [value]);\n const result = ts.transform(fn.body!, [context => {\n const visit: ts.Visitor = node => {\n if (ts.isIdentifier(node) && node.text.startsWith('__h')) fail('Identifiers beginning __h are reserved', expression.start + Math.max(0, node.getStart(file) - prefix.length));\n if ((ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && [ts.SyntaxKind.PlusPlusToken, ts.SyntaxKind.MinusMinusToken].includes(node.operator)) {\n const name = stateName(node.operand);\n if (name) {\n dependencies.add(name);\n if (constants.has(name)) fail(`Cannot assign constant ${name}`, expression.start);\n const delta = node.operator === ts.SyntaxKind.PlusPlusToken ? f.createNumericLiteral(1) : f.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, f.createNumericLiteral(1));\n return f.createCallExpression(f.createIdentifier('__hUpdate'), undefined, [f.createIdentifier(name), delta, node.kind === ts.SyntaxKind.PostfixUnaryExpression ? f.createTrue() : f.createFalse()]);\n }\n }\n if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment) {\n if (ts.isArrayLiteralExpression(node.left) || ts.isObjectLiteralExpression(node.left)) {\n const checkTarget = (target: ts.Node): void => {\n const name = stateName(target);\n if (name) fail('Destructuring assignments to component bindings are not supported', expression.start);\n ts.forEachChild(target, checkTarget);\n };\n checkTarget(node.left);\n }\n const name = stateName(node.left);\n if (name) {\n dependencies.add(name);\n if (constants.has(name)) fail(`Cannot assign constant ${name}`, expression.start);\n const right = ts.visitNode(node.right, visit) as ts.Expression;\n if (node.operatorToken.kind === ts.SyntaxKind.EqualsToken) return write(name, right);\n const operators: Partial<Record<ts.SyntaxKind, ts.BinaryOperator>> = {\n [ts.SyntaxKind.PlusEqualsToken]: ts.SyntaxKind.PlusToken, [ts.SyntaxKind.MinusEqualsToken]: ts.SyntaxKind.MinusToken,\n [ts.SyntaxKind.AsteriskEqualsToken]: ts.SyntaxKind.AsteriskToken, [ts.SyntaxKind.SlashEqualsToken]: ts.SyntaxKind.SlashToken,\n [ts.SyntaxKind.PercentEqualsToken]: ts.SyntaxKind.PercentToken, [ts.SyntaxKind.AsteriskAsteriskEqualsToken]: ts.SyntaxKind.AsteriskAsteriskToken,\n [ts.SyntaxKind.AmpersandEqualsToken]: ts.SyntaxKind.AmpersandToken, [ts.SyntaxKind.BarEqualsToken]: ts.SyntaxKind.BarToken,\n [ts.SyntaxKind.CaretEqualsToken]: ts.SyntaxKind.CaretToken, [ts.SyntaxKind.LessThanLessThanEqualsToken]: ts.SyntaxKind.LessThanLessThanToken,\n [ts.SyntaxKind.GreaterThanGreaterThanEqualsToken]: ts.SyntaxKind.GreaterThanGreaterThanToken, [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken\n };\n const op = operators[node.operatorToken.kind];\n if (!op) fail('Logical assignment to state is not supported yet', expression.start);\n return write(name, f.createBinaryExpression(read(name), op!, right));\n }\n }\n if (ts.isShorthandPropertyAssignment(node)) {\n const symbol = checker.getShorthandAssignmentValueSymbol(node);\n const name = symbol && symbols.get(symbol);\n if (name && !handler && !available.has(name)) fail(`Binding ${name} is used before initialization`, expression.start);\n if (name && states.has(name)) { dependencies.add(name); return f.createPropertyAssignment(node.name.text, read(name)); }\n }\n if (ts.isIdentifier(node)) {\n const name = stateName(node);\n if (name && !handler && !available.has(name)) fail(`Binding ${name} is used before initialization`, expression.start);\n if (name && states.has(name)) { dependencies.add(name); return read(name); }\n }\n if ((ts.isForOfStatement(node) || ts.isForInStatement(node)) && stateName(node.initializer)) fail('Use a local loop variable, then assign state in the loop body', expression.start);\n return ts.visitEachChild(node, visit, context);\n };\n return node => ts.visitNode(node, visit) as ts.Block;\n }]);\n // Report unresolved names while leaving module resolution and imported types to Vite/tsc.\n for (const d of program.getSemanticDiagnostics(file)) if ((d.code < 2000 || [2304, 2552, 2588].includes(d.code)) && (d.start ?? 0) >= prefix.length && (d.start ?? 0) < prefix.length + expression.source.length) {\n fail(ts.flattenDiagnosticMessageText(d.messageText, '\\n'), expression.start + d.start! - prefix.length);\n }\n const body = result.transformed[0] as ts.Block;\n metadata.push({ view: view.name, start: expression.start, end: expression.end, dependencies: [...dependencies].sort(), kind: handler ? 'event' : 'expression' });\n let rendered: string;\n if (handler) rendered = printer.printNode(ts.EmitHint.Unspecified, body, file);\n else rendered = printer.printNode(ts.EmitHint.Expression, (body.statements[0] as ts.ReturnStatement).expression!, file);\n result.dispose();\n return rendered;\n };\n const value = (expr: Expression): string => {\n if (!expr.source.startsWith('\"')) return transform(expr);\n const tokens = tokenize(expr.source);\n if (tokens.length !== 1 || tokens[0]!.kind !== ts.SyntaxKind.StringLiteral) return transform(expr);\n const raw = expr.source.slice(1, -1);\n const parts: string[] = [];\n let literal = '', i = 0;\n const emit = () => { if (literal) { parts.push(JSON.stringify(literal)); literal = ''; } };\n while (i < raw.length) {\n if (raw[i] === '\\\\') {\n const next = raw[++i];\n const escapes: Record<string, string> = { n: '\\n', r: '\\r', t: '\\t', b: '\\b', f: '\\f', v: '\\v', '0': '\\0' };\n if (next === 'u' || next === 'x') fail('Use single quotes for Unicode/hex escapes in literal strings', expr.start + i);\n literal += escapes[next ?? ''] ?? next ?? ''; i++; continue;\n }\n if (raw[i] !== '{') { literal += raw[i++]; continue; }\n emit(); const start = ++i;\n const nested = tokenize(raw.slice(start)); let depth = 1, end = -1;\n for (const token of nested) { if (token.text === '{') depth++; if (token.text === '}' && --depth === 0) { end = start + token.start; break; } }\n if (end < 0) fail('Unterminated text interpolation', expr.start + start);\n parts.push(`String(${transform({ source: raw.slice(start, end), start: expr.start + 1 + start, end: expr.start + 1 + end })} ?? \"\")`);\n i = end + 1;\n }\n emit(); return parts.length ? parts.join(' + ') : '\"\"';\n };\n const emit = (node: Element, parent: string): void => {\n if (/^[A-Z]/.test(node.name)) {\n if (!names.has(node.name) && !imported.has(node.name)) fail(`Unknown component ${node.name}`, node.start);\n if (node.value || node.handler || node.children.length) fail('Component props, event blocks and slots are not supported in Milestone 1', node.start);\n output.push(`__hDOM.component(${parent}, ${node.name});`); return;\n }\n const id = `__hNode${serial++}`;\n output.push(`const ${id} = __hDOM.element(${parent}, ${JSON.stringify(node.name)});`);\n if (node.value) {\n if (node.name === 'input') {\n if (!states.has(node.value.source.trim()) || !available.has(node.value.source.trim())) fail('input requires an initialized state identifier', node.value.start);\n output.push(`__hDOM.input(${id}, ${node.value.source});`);\n } else if (node.name === 'image' || node.name === 'img') output.push(`__hDOM.attribute(${id}, \"src\", () => ${value(node.value)});`);\n else output.push(`__hDOM.text(${id}, () => ${value(node.value)});`);\n }\n if (node.handler) output.push(`__hDOM.listen(${id}, \"click\", ${node.async ? 'async ' : ''}(event) => ${transform(node.handler, true, node.async)});`);\n node.children.forEach(child => emit(child, id));\n };\n for (const node of view.body) {\n if (node.kind === 'element') emit(node, '__hParent');\n else { output.push(`const ${node.name} = ${node.kind === 'state' ? '__hSignal(' : ''}${transform(node.value)}${node.kind === 'state' ? ')' : ''};`); available.add(node.name); }\n }\n views.push({ name: view.name, exported: view.exported, default: view.default, instructions: output });\n }\n const ir: ModuleIR = { prelude, views, bindings: options.development === false ? [] : metadata };\n const output = [...ir.prelude, ...ir.views.flatMap(view => [\n `${view.exported ? 'export ' : ''}${view.default ? 'default ' : ''}function ${view.name}(__hParent) {`,\n ...view.instructions.map(instruction => instruction.split('\\n').map(line => ` ${line}`).join('\\n')),\n '}'\n ])];\n if (options.development !== false) output.push(`export const __hesh = ${JSON.stringify(metadata)};`);\n return { code: output.join('\\n'), css: '', metadata: options.development === false ? [] : metadata, ast, ir };\n}\n\nexport function createCompiler() {\n const cache = new Map<string, Result>();\n return {\n compile(source: string, options: CompileOptions = {}) {\n const key = JSON.stringify([source, options]);\n let result = cache.get(key);\n if (!result) { result = compile(source, options); cache.set(key, result); }\n return result;\n },\n clear() { cache.clear(); }\n };\n}\n\r\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type Signal, type Disposer } from '../reactivity/index.js';
|
|
2
|
+
export type Component = (parent: Node) => void;
|
|
3
|
+
export interface MountOptions {
|
|
4
|
+
onError?: (error: unknown) => void;
|
|
5
|
+
}
|
|
6
|
+
export declare function mount(component: Component, parent: Node, options?: MountOptions): Disposer;
|
|
7
|
+
export declare function element(parent: Node, name: string): HTMLElement;
|
|
8
|
+
export declare function text(parent: Node, read: () => unknown): void;
|
|
9
|
+
export declare function attribute(node: HTMLElement, name: string, read: () => unknown): void;
|
|
10
|
+
export declare function listen(node: HTMLElement, name: string, handler: (event: Event) => unknown): void;
|
|
11
|
+
export declare function input(node: HTMLInputElement, state: Signal<unknown>): void;
|
|
12
|
+
export declare function component(parent: Node, view: Component): void;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { effect, onCleanup, scope, batch } from '../reactivity/index.js';
|
|
2
|
+
let errorHandler = error => console.error(error);
|
|
3
|
+
const aliases = { text: 'span', card: 'div', row: 'div', stack: 'div', grid: 'div', image: 'img', link: 'a' };
|
|
4
|
+
export function mount(component, parent, options = {}) {
|
|
5
|
+
const previous = errorHandler;
|
|
6
|
+
errorHandler = options.onError ?? previous;
|
|
7
|
+
try {
|
|
8
|
+
return scope(() => component(parent)).dispose;
|
|
9
|
+
}
|
|
10
|
+
finally {
|
|
11
|
+
errorHandler = previous;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function element(parent, name) {
|
|
15
|
+
const node = parent.ownerDocument.createElement(aliases[name] ?? name);
|
|
16
|
+
parent.appendChild(node);
|
|
17
|
+
onCleanup(() => node.remove());
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
export function text(parent, read) {
|
|
21
|
+
const node = parent.ownerDocument.createTextNode('');
|
|
22
|
+
parent.appendChild(node);
|
|
23
|
+
onCleanup(() => node.remove());
|
|
24
|
+
effect(() => { node.data = String(read() ?? ''); });
|
|
25
|
+
}
|
|
26
|
+
function safeURL(value) {
|
|
27
|
+
// Parse like a browser, including embedded ASCII tabs/newlines.
|
|
28
|
+
const normalized = value.replace(/[\u0000-\u0020]/g, '');
|
|
29
|
+
const scheme = /^([a-z][a-z\d+.-]*):/i.exec(normalized)?.[1]?.toLowerCase();
|
|
30
|
+
if (scheme && !['http', 'https', 'mailto', 'tel'].includes(scheme)) {
|
|
31
|
+
throw new Error(`Unsafe URL scheme: ${scheme}`);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
export function attribute(node, name, read) {
|
|
36
|
+
if (/^on/i.test(name) || ['innerhtml', 'outerhtml', 'srcdoc'].includes(name.toLowerCase()))
|
|
37
|
+
throw new Error(`Unsafe attribute: ${name}`);
|
|
38
|
+
effect(() => {
|
|
39
|
+
const value = read();
|
|
40
|
+
if (value == null || value === false)
|
|
41
|
+
node.removeAttribute(name);
|
|
42
|
+
else {
|
|
43
|
+
const rendered = value === true ? '' : String(value);
|
|
44
|
+
node.setAttribute(name, ['href', 'src', 'action', 'formaction', 'poster', 'xlink:href'].includes(name.toLowerCase()) ? safeURL(rendered) : rendered);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
export function listen(node, name, handler) {
|
|
49
|
+
const report = errorHandler;
|
|
50
|
+
const listener = (event) => {
|
|
51
|
+
try {
|
|
52
|
+
Promise.resolve(batch(() => handler(event))).catch(report);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
report(error);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
node.addEventListener(name, listener);
|
|
59
|
+
onCleanup(() => node.removeEventListener(name, listener));
|
|
60
|
+
}
|
|
61
|
+
export function input(node, state) {
|
|
62
|
+
effect(() => { const value = String(state.get() ?? ''); if (node.value !== value)
|
|
63
|
+
node.value = value; });
|
|
64
|
+
listen(node, 'input', () => state.set(node.value));
|
|
65
|
+
}
|
|
66
|
+
export function component(parent, view) {
|
|
67
|
+
scope(() => view(parent));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dom/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { effect, onCleanup, scope, batch, type Signal, type Disposer } from '../reactivity/index.js';\nexport type Component = (parent: Node) => void;\nexport interface MountOptions { onError?: (error: unknown) => void }\nlet errorHandler: (error: unknown) => void = error => console.error(error);\nconst aliases: Record<string, string> = { text: 'span', card: 'div', row: 'div', stack: 'div', grid: 'div', image: 'img', link: 'a' };\n\nexport function mount(component: Component, parent: Node, options: MountOptions = {}): Disposer {\n const previous = errorHandler;\n errorHandler = options.onError ?? previous;\n try { return scope(() => component(parent)).dispose; }\n finally { errorHandler = previous; }\n}\n\nexport function element(parent: Node, name: string): HTMLElement {\n const node = parent.ownerDocument!.createElement(aliases[name] ?? name);\n parent.appendChild(node);\n onCleanup(() => node.remove());\n return node;\n}\n\nexport function text(parent: Node, read: () => unknown): void {\n const node = parent.ownerDocument!.createTextNode('');\n parent.appendChild(node);\n onCleanup(() => node.remove());\n effect(() => { node.data = String(read() ?? ''); });\n}\n\nfunction safeURL(value: string): string {\n // Parse like a browser, including embedded ASCII tabs/newlines.\n const normalized = value.replace(/[\\u0000-\\u0020]/g, '');\n const scheme = /^([a-z][a-z\\d+.-]*):/i.exec(normalized)?.[1]?.toLowerCase();\n if (scheme && !['http', 'https', 'mailto', 'tel'].includes(scheme)) {\n throw new Error(`Unsafe URL scheme: ${scheme}`);\n }\n return value;\n}\n\nexport function attribute(node: HTMLElement, name: string, read: () => unknown): void {\n if (/^on/i.test(name) || ['innerhtml', 'outerhtml', 'srcdoc'].includes(name.toLowerCase())) throw new Error(`Unsafe attribute: ${name}`);\n effect(() => {\n const value = read();\n if (value == null || value === false) node.removeAttribute(name);\n else {\n const rendered = value === true ? '' : String(value);\n node.setAttribute(name, ['href', 'src', 'action', 'formaction', 'poster', 'xlink:href'].includes(name.toLowerCase()) ? safeURL(rendered) : rendered);\n }\n });\n}\n\nexport function listen(node: HTMLElement, name: string, handler: (event: Event) => unknown): void {\n const report = errorHandler;\n const listener = (event: Event) => {\n try { Promise.resolve(batch(() => handler(event))).catch(report); }\n catch (error) { report(error); }\n };\n node.addEventListener(name, listener);\n onCleanup(() => node.removeEventListener(name, listener));\n}\n\nexport function input(node: HTMLInputElement, state: Signal<unknown>): void {\n effect(() => { const value = String(state.get() ?? ''); if (node.value !== value) node.value = value; });\n listen(node, 'input', () => state.set(node.value));\n}\n\nexport function component(parent: Node, view: Component): void {\n scope(() => view(parent));\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { signal, effect, derived, batch, scope, onCleanup, untrack } from '../reactivity/index.js';
|
|
2
|
+
export type { Signal, Disposer } from '../reactivity/index.js';
|
|
3
|
+
export { mount, element, text, attribute, listen, input, component } from '../dom/index.js';
|
|
4
|
+
export type { Component, MountOptions } from '../dom/index.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/heshjs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEnG,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["export { signal, effect, derived, batch, scope, onCleanup, untrack } from '../reactivity/index.js';\nexport type { Signal, Disposer } from '../reactivity/index.js';\nexport { mount, element, text, attribute, listen, input, component } from '../dom/index.js';\nexport type { Component, MountOptions } from '../dom/index.js';\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
export interface Location {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Expression extends Location {
|
|
7
|
+
source: string;
|
|
8
|
+
}
|
|
9
|
+
export interface State extends Location {
|
|
10
|
+
kind: 'state' | 'const';
|
|
11
|
+
name: string;
|
|
12
|
+
value: Expression;
|
|
13
|
+
}
|
|
14
|
+
export interface Element extends Location {
|
|
15
|
+
kind: 'element';
|
|
16
|
+
name: string;
|
|
17
|
+
value?: Expression;
|
|
18
|
+
handler?: Expression;
|
|
19
|
+
async: boolean;
|
|
20
|
+
children: Element[];
|
|
21
|
+
}
|
|
22
|
+
export interface View extends Location {
|
|
23
|
+
name: string;
|
|
24
|
+
exported: boolean;
|
|
25
|
+
default: boolean;
|
|
26
|
+
body: (State | Element)[];
|
|
27
|
+
}
|
|
28
|
+
export interface Module {
|
|
29
|
+
source: string;
|
|
30
|
+
filename: string;
|
|
31
|
+
imports: Expression[];
|
|
32
|
+
views: View[];
|
|
33
|
+
}
|
|
34
|
+
export declare class HeshError extends Error {
|
|
35
|
+
readonly source: string;
|
|
36
|
+
readonly offset: number;
|
|
37
|
+
readonly filename: string;
|
|
38
|
+
readonly line: number;
|
|
39
|
+
readonly column: number;
|
|
40
|
+
constructor(message: string, source: string, offset: number, filename?: string);
|
|
41
|
+
}
|
|
42
|
+
export interface Token extends Location {
|
|
43
|
+
text: string;
|
|
44
|
+
kind: ts.SyntaxKind;
|
|
45
|
+
}
|
|
46
|
+
export declare function tokenize(source: string, filename?: string): Token[];
|
|
47
|
+
export declare function parse(source: string, filename?: string): Module;
|