@vesk/compiler 0.0.1
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 +23 -0
- package/dist/acorn-ts-plugin/index.d.ts +482 -0
- package/dist/acorn-ts-plugin/index.d.ts.map +1 -0
- package/dist/acorn-ts-plugin/index.js +5028 -0
- package/dist/actions.d.ts +22 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +167 -0
- package/dist/api-routes.d.ts +30 -0
- package/dist/api-routes.d.ts.map +1 -0
- package/dist/api-routes.js +350 -0
- package/dist/client-codegen.d.ts +19 -0
- package/dist/client-codegen.d.ts.map +1 -0
- package/dist/client-codegen.js +1523 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +210 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/ir-generator.d.ts +10 -0
- package/dist/ir-generator.d.ts.map +1 -0
- package/dist/ir-generator.js +1062 -0
- package/dist/ir.d.ts +160 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +219 -0
- package/dist/middleware.d.ts +15 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +183 -0
- package/dist/package.json +15 -0
- package/dist/parser.d.ts +38 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +242 -0
- package/dist/router.d.ts +31 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +451 -0
- package/dist/scan.d.ts +106 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +438 -0
- package/dist/server-codegen.d.ts +5 -0
- package/dist/server-codegen.d.ts.map +1 -0
- package/dist/server-codegen.js +4 -0
- package/dist/server-cookies.d.ts +2 -0
- package/dist/server-cookies.d.ts.map +1 -0
- package/dist/server-cookies.js +15 -0
- package/dist/server-head.d.ts +10 -0
- package/dist/server-head.d.ts.map +1 -0
- package/dist/server-head.js +289 -0
- package/dist/server-jsgen.d.ts +6 -0
- package/dist/server-jsgen.d.ts.map +1 -0
- package/dist/server-jsgen.js +446 -0
- package/dist/server-render.d.ts +16 -0
- package/dist/server-render.d.ts.map +1 -0
- package/dist/server-render.js +397 -0
- package/dist/server-utils.d.ts +93 -0
- package/dist/server-utils.d.ts.map +1 -0
- package/dist/server-utils.js +747 -0
- package/dist/ssr-store.d.ts +4 -0
- package/dist/ssr-store.d.ts.map +1 -0
- package/dist/ssr-store.js +29 -0
- package/dist/strip-ts.d.ts +25 -0
- package/dist/strip-ts.d.ts.map +1 -0
- package/dist/strip-ts.js +171 -0
- package/dist/tokens.d.ts +50 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +334 -0
- package/dist/typecheck.d.ts +19 -0
- package/dist/typecheck.d.ts.map +1 -0
- package/dist/typecheck.js +365 -0
- package/dist/types.d.ts +147 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/vesk-plugin.d.ts +53 -0
- package/dist/vesk-plugin.d.ts.map +1 -0
- package/dist/vesk-plugin.js +413 -0
- package/dist/vsk-imports.d.ts +30 -0
- package/dist/vsk-imports.d.ts.map +1 -0
- package/dist/vsk-imports.js +141 -0
- package/dist/vsk-tsx.d.ts +3 -0
- package/dist/vsk-tsx.d.ts.map +1 -0
- package/dist/vsk-tsx.js +604 -0
- package/package.json +52 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { StaticNode, TextNode, DynamicBinding, HeadBlock, RuntimeStatement } from '@vesk/compiler/src/ir';
|
|
2
|
+
import { tryEvalExpr, escapeHtml } from '@vesk/compiler/src/server-utils';
|
|
3
|
+
import { isWhitespaceChar } from '@vesk/compiler/src/scan';
|
|
4
|
+
function isHtmlNameChar(ch) {
|
|
5
|
+
const code = ch.charCodeAt(0);
|
|
6
|
+
return ((code >= 48 && code <= 57) || (code >= 65 && code <= 90) || (code >= 97 && code <= 122) || ch === '-');
|
|
7
|
+
}
|
|
8
|
+
function isAttrBoundaryChar(ch) {
|
|
9
|
+
return isWhitespaceChar(ch) || ch === '=' || ch === '/' || ch === '>';
|
|
10
|
+
}
|
|
11
|
+
function isValueBoundaryChar(ch) {
|
|
12
|
+
return isWhitespaceChar(ch) || ch === '/' || ch === '>';
|
|
13
|
+
}
|
|
14
|
+
function evaluateLocals(comp, props) {
|
|
15
|
+
const locals = {};
|
|
16
|
+
for (const node of comp.body) {
|
|
17
|
+
if (node instanceof RuntimeStatement && node.ast) {
|
|
18
|
+
const stmt = node.ast;
|
|
19
|
+
if (stmt.type === 'VariableDeclaration') {
|
|
20
|
+
for (const decl of stmt.declarations) {
|
|
21
|
+
if (decl.id.type === 'Identifier' && decl.init && node.source) {
|
|
22
|
+
const name = decl.id.name;
|
|
23
|
+
const initSrc = node.source.slice(decl.init.start, decl.init.end);
|
|
24
|
+
try {
|
|
25
|
+
const fn = new Function('props', 'return (' + initSrc + ')');
|
|
26
|
+
locals[name] = fn(props);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// expression can't be evaluated — skip
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return locals;
|
|
37
|
+
}
|
|
38
|
+
function headElementKey(node, props, locals) {
|
|
39
|
+
if (!(node instanceof StaticNode))
|
|
40
|
+
return null;
|
|
41
|
+
const tag = node.tag;
|
|
42
|
+
if (tag === 'title')
|
|
43
|
+
return 'title';
|
|
44
|
+
if (tag === 'base')
|
|
45
|
+
return 'base';
|
|
46
|
+
const attrMap = new Map(node.attributes.map((a) => [a.name, a.value]));
|
|
47
|
+
for (const child of node.children) {
|
|
48
|
+
if (child instanceof DynamicBinding && child.kind === 'attribute' && child.target && child.target !== 'ref') {
|
|
49
|
+
try {
|
|
50
|
+
attrMap.set(child.target, String(tryEvalExpr(child.expression.raw, props, locals)));
|
|
51
|
+
}
|
|
52
|
+
catch { /* skip */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (tag === 'meta') {
|
|
56
|
+
if (attrMap.has('name'))
|
|
57
|
+
return `meta[name=${attrMap.get('name')}]`;
|
|
58
|
+
if (attrMap.has('property'))
|
|
59
|
+
return `meta[property=${attrMap.get('property')}]`;
|
|
60
|
+
if (attrMap.has('charset'))
|
|
61
|
+
return 'meta[charset]';
|
|
62
|
+
if (attrMap.has('http-equiv'))
|
|
63
|
+
return `meta[http-equiv=${attrMap.get('http-equiv')}]`;
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
if (tag === 'link') {
|
|
67
|
+
if (attrMap.has('href'))
|
|
68
|
+
return `link[href=${attrMap.get('href')}]`;
|
|
69
|
+
if (attrMap.has('id'))
|
|
70
|
+
return `link[id=${attrMap.get('id')}]`;
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
if (tag === 'script') {
|
|
74
|
+
if (attrMap.has('src'))
|
|
75
|
+
return `script[src=${attrMap.get('src')}]`;
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
if (tag === 'style')
|
|
79
|
+
return null;
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function irNodeToHeadHtml(node, props, locals = {}) {
|
|
83
|
+
if (node instanceof StaticNode) {
|
|
84
|
+
const attrMap = new Map(node.attributes.map((a) => [a.name, a.value]));
|
|
85
|
+
for (const child of node.children) {
|
|
86
|
+
if (child instanceof DynamicBinding && child.kind === 'attribute' && child.target && child.target !== 'ref') {
|
|
87
|
+
try {
|
|
88
|
+
const val = tryEvalExpr(child.expression.raw, props, locals);
|
|
89
|
+
attrMap.set(child.target, String(val));
|
|
90
|
+
}
|
|
91
|
+
catch { /* skip */ }
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
const attrs = [...attrMap.entries()]
|
|
95
|
+
.map(([k, v]) => ` ${k}="${escapeHtml(v)}"`)
|
|
96
|
+
.join('');
|
|
97
|
+
if (node.selfClosing)
|
|
98
|
+
return `<${node.tag}${attrs} />`;
|
|
99
|
+
const inner = node.children
|
|
100
|
+
.filter((c) => !(c instanceof DynamicBinding && c.kind === 'attribute' && c.target !== 'ref'))
|
|
101
|
+
.map((c) => irNodeToHeadHtml(c, props, locals))
|
|
102
|
+
.join('');
|
|
103
|
+
return `<${node.tag}${attrs}>${inner}</${node.tag}>`;
|
|
104
|
+
}
|
|
105
|
+
if (node instanceof TextNode)
|
|
106
|
+
return node.value;
|
|
107
|
+
if (node instanceof DynamicBinding) {
|
|
108
|
+
try {
|
|
109
|
+
const val = tryEvalExpr(node.expression.raw, props, locals);
|
|
110
|
+
return escapeHtml(String(val));
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return '';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return '';
|
|
117
|
+
}
|
|
118
|
+
export function renderHeadHtml(comp, props = {}) {
|
|
119
|
+
const locals = evaluateLocals(comp, props);
|
|
120
|
+
const seen = new Set();
|
|
121
|
+
const parts = [];
|
|
122
|
+
for (const node of comp.body) {
|
|
123
|
+
if (node instanceof HeadBlock) {
|
|
124
|
+
for (const child of node.children) {
|
|
125
|
+
const key = headElementKey(child, props, locals);
|
|
126
|
+
if (key !== null && seen.has(key))
|
|
127
|
+
continue;
|
|
128
|
+
if (key !== null)
|
|
129
|
+
seen.add(key);
|
|
130
|
+
parts.push(irNodeToHeadHtml(child, props, locals));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return parts.join('\n');
|
|
135
|
+
}
|
|
136
|
+
function scanHeadTag(html, lt) {
|
|
137
|
+
let i = lt + 1;
|
|
138
|
+
if (html[i] === '/')
|
|
139
|
+
i++;
|
|
140
|
+
const nameStart = i;
|
|
141
|
+
while (i < html.length && isHtmlNameChar(html[i]))
|
|
142
|
+
i++;
|
|
143
|
+
const tag = html.slice(nameStart, i).toLowerCase();
|
|
144
|
+
if (!tag)
|
|
145
|
+
return null;
|
|
146
|
+
const attrs = new Map();
|
|
147
|
+
let selfClosing = false;
|
|
148
|
+
while (i < html.length) {
|
|
149
|
+
while (i < html.length && isWhitespaceChar(html[i]))
|
|
150
|
+
i++;
|
|
151
|
+
if (html[i] === '>') {
|
|
152
|
+
i++;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
if (html[i] === '/' && html[i + 1] === '>') {
|
|
156
|
+
selfClosing = true;
|
|
157
|
+
i += 2;
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
if (i >= html.length || html[i] === '>' || html[i] === '/')
|
|
161
|
+
continue;
|
|
162
|
+
const aStart = i;
|
|
163
|
+
while (i < html.length && !isAttrBoundaryChar(html[i]))
|
|
164
|
+
i++;
|
|
165
|
+
const aName = html.slice(aStart, i).toLowerCase();
|
|
166
|
+
while (i < html.length && isWhitespaceChar(html[i]))
|
|
167
|
+
i++;
|
|
168
|
+
let value = '';
|
|
169
|
+
if (html[i] === '=') {
|
|
170
|
+
i++;
|
|
171
|
+
while (i < html.length && isWhitespaceChar(html[i]))
|
|
172
|
+
i++;
|
|
173
|
+
const q = html[i];
|
|
174
|
+
if (q === '"' || q === "'") {
|
|
175
|
+
i++;
|
|
176
|
+
const vStart = i;
|
|
177
|
+
while (i < html.length && html[i] !== q)
|
|
178
|
+
i++;
|
|
179
|
+
value = html.slice(vStart, i);
|
|
180
|
+
if (i < html.length)
|
|
181
|
+
i++;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const vStart = i;
|
|
185
|
+
while (i < html.length && !isValueBoundaryChar(html[i]))
|
|
186
|
+
i++;
|
|
187
|
+
value = html.slice(vStart, i);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (aName)
|
|
191
|
+
attrs.set(aName, value);
|
|
192
|
+
}
|
|
193
|
+
let raw = html.slice(lt, i);
|
|
194
|
+
if (!selfClosing && tag === 'title') {
|
|
195
|
+
const closeTag = html.indexOf('</title', i);
|
|
196
|
+
if (closeTag !== -1) {
|
|
197
|
+
const end = html.indexOf('>', closeTag);
|
|
198
|
+
if (end !== -1) {
|
|
199
|
+
raw = html.slice(lt, end + 1);
|
|
200
|
+
i = end + 1;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { raw, tag, attrs, selfClosing, end: i };
|
|
205
|
+
}
|
|
206
|
+
function parseHeadTags(html) {
|
|
207
|
+
const entries = [];
|
|
208
|
+
let i = 0;
|
|
209
|
+
while (i < html.length) {
|
|
210
|
+
const lt = html.indexOf('<', i);
|
|
211
|
+
if (lt === -1)
|
|
212
|
+
break;
|
|
213
|
+
if (html.startsWith('<!--', lt)) {
|
|
214
|
+
const close = html.indexOf('-->', lt + 4);
|
|
215
|
+
i = close === -1 ? html.length : close + 3;
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
const entry = scanHeadTag(html, lt);
|
|
219
|
+
if (!entry)
|
|
220
|
+
break;
|
|
221
|
+
entries.push(entry);
|
|
222
|
+
i = entry.end;
|
|
223
|
+
}
|
|
224
|
+
return entries;
|
|
225
|
+
}
|
|
226
|
+
export function mergeHeadHtml(pageHead, layoutHead) {
|
|
227
|
+
const extractKey = (entry) => {
|
|
228
|
+
if (entry.tag === 'title')
|
|
229
|
+
return 'title';
|
|
230
|
+
if (entry.tag === 'base') {
|
|
231
|
+
const h = entry.attrs.get('href');
|
|
232
|
+
return h !== undefined ? `base[href=${h}]` : 'base';
|
|
233
|
+
}
|
|
234
|
+
if (entry.tag === 'meta') {
|
|
235
|
+
const n = entry.attrs.get('name');
|
|
236
|
+
if (n !== undefined)
|
|
237
|
+
return `meta[name=${n}]`;
|
|
238
|
+
const p = entry.attrs.get('property');
|
|
239
|
+
if (p !== undefined)
|
|
240
|
+
return `meta[property=${p}]`;
|
|
241
|
+
if (entry.attrs.has('charset'))
|
|
242
|
+
return 'meta[charset]';
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
if (entry.tag === 'link') {
|
|
246
|
+
const h = entry.attrs.get('href');
|
|
247
|
+
if (h !== undefined)
|
|
248
|
+
return `link[href=${h}]`;
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
if (entry.tag === 'script') {
|
|
252
|
+
const s = entry.attrs.get('src');
|
|
253
|
+
if (s !== undefined)
|
|
254
|
+
return `script[src=${s}]`;
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
};
|
|
259
|
+
const layoutEntries = parseHeadTags(layoutHead);
|
|
260
|
+
const pageEntries = parseHeadTags(pageHead);
|
|
261
|
+
const merged = new Map();
|
|
262
|
+
for (const tag of layoutEntries) {
|
|
263
|
+
const key = extractKey(tag);
|
|
264
|
+
if (key)
|
|
265
|
+
merged.set(key, { html: tag.raw, source: 'layout' });
|
|
266
|
+
}
|
|
267
|
+
const conflicts = [];
|
|
268
|
+
for (const tag of pageEntries) {
|
|
269
|
+
const key = extractKey(tag);
|
|
270
|
+
if (key) {
|
|
271
|
+
if (merged.has(key) && merged.get(key).source === 'page') {
|
|
272
|
+
conflicts.push({ key, message: `Sibling conflict for <head> key "${key}":\n ${merged.get(key).html}\n ${tag.raw}` });
|
|
273
|
+
}
|
|
274
|
+
merged.set(key, { html: tag.raw, source: 'page' });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
const order = ['title', 'base', 'meta', 'link', 'script', 'style'];
|
|
278
|
+
const sorted = [...merged.values()].sort((a, b) => {
|
|
279
|
+
const ak = [...merged.entries()].find(e => e[1] === a)?.[0] || '';
|
|
280
|
+
const bk = [...merged.entries()].find(e => e[1] === b)?.[0] || '';
|
|
281
|
+
const ai = order.findIndex(o => ak.startsWith(o));
|
|
282
|
+
const bi = order.findIndex(o => bk.startsWith(o));
|
|
283
|
+
return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
|
|
284
|
+
});
|
|
285
|
+
return {
|
|
286
|
+
html: sorted.map(e => e.html).join('\n'),
|
|
287
|
+
conflicts,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { IRNode, ComponentIR, IRRoot } from '@vesk/compiler/src/ir';
|
|
2
|
+
import { type TrackedInfo } from '@vesk/compiler/src/client-codegen';
|
|
3
|
+
export declare function irNodeToJS(node: IRNode, importedNames?: Set<string> | null, isAsync?: boolean, tracked?: Map<string, TrackedInfo>): string;
|
|
4
|
+
export declare function generateFunctionBody(comp: ComponentIR, importedNames: Set<string>): string;
|
|
5
|
+
export declare function buildComponentMap(irRoot: IRRoot, useSharedScope: boolean): Map<string, Function>;
|
|
6
|
+
//# sourceMappingURL=server-jsgen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-jsgen.d.ts","sourceRoot":"","sources":["../src/server-jsgen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAOzE,OAAO,EAA4E,KAAK,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAU/I,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,OAAO,GAAE,OAAe,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CA8CjJ;AA4SD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAkD1F;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAwBhG"}
|