@vesk/compiler 0.1.14 → 0.2.8
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/dist/api-routes.d.ts +6 -1
- package/dist/api-routes.d.ts.map +1 -1
- package/dist/api-routes.js +52 -7
- package/dist/client-codegen.d.ts +15 -0
- package/dist/client-codegen.d.ts.map +1 -1
- package/dist/client-codegen.js +73 -10
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +25 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +33 -4
- package/dist/ir-generator.d.ts.map +1 -1
- package/dist/ir-generator.js +109 -1
- package/dist/md-inline.d.ts +17 -0
- package/dist/md-inline.d.ts.map +1 -0
- package/dist/md-inline.js +149 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +42 -7
- package/dist/router.d.ts +2 -0
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +48 -3
- package/dist/server-codegen.d.ts +1 -1
- package/dist/server-codegen.d.ts.map +1 -1
- package/dist/server-codegen.js +1 -1
- package/dist/server-jsgen.js +1 -1
- package/dist/server-render.d.ts.map +1 -1
- package/dist/server-render.js +14 -8
- package/dist/server-utils.d.ts +31 -0
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +478 -52
- package/dist/typecheck.d.ts +2 -2
- package/dist/typecheck.d.ts.map +1 -1
- package/dist/typecheck.js +66 -27
- package/dist/types.d.ts +4 -129
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/vesk-plugin.d.ts +2 -0
- package/dist/vesk-plugin.d.ts.map +1 -1
- package/dist/vesk-plugin.js +152 -0
- package/dist/vsk-tsx.d.ts.map +1 -1
- package/dist/vsk-tsx.js +15 -5
- package/package.json +2 -1
package/dist/api-routes.d.ts
CHANGED
|
@@ -22,9 +22,14 @@ export type BuildWebRequestInput = {
|
|
|
22
22
|
* `json()`/`text()` are patched accordingly. A `cookies` getter is attached
|
|
23
23
|
* (NextRequest-compatible).
|
|
24
24
|
*/
|
|
25
|
-
export declare function buildWebRequest(nodeReq: BuildWebRequestInput, url: string, body?: BodyInit | null
|
|
25
|
+
export declare function buildWebRequest(nodeReq: BuildWebRequestInput, url: string, body?: BodyInit | null, options?: {
|
|
26
|
+
maxBodyBytes?: number;
|
|
27
|
+
}): Request & {
|
|
26
28
|
cookies: Record<string, string>;
|
|
27
29
|
query: Record<string, string>;
|
|
28
30
|
};
|
|
31
|
+
export declare function tooLargeError(max: number): Error & {
|
|
32
|
+
status: number;
|
|
33
|
+
};
|
|
29
34
|
export declare function executeApiRoute(filePath: string, method: string, request: Request, params?: Record<string, string>, locals?: Record<string, unknown>, devCache?: DevCache): Promise<Response | null>;
|
|
30
35
|
//# sourceMappingURL=api-routes.d.ts.map
|
package/dist/api-routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-routes.d.ts","sourceRoot":"","sources":["../src/api-routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"api-routes.d.ts","sourceRoot":"","sources":["../src/api-routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAW7D,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,EAAE,CAG5D;AA+ED,wBAAgB,WAAW,CAAC,IAAI,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,IAAI,CA0DjI;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWhE;AAED,MAAM,WAAW,QAAS,SAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;CAAG;AAExD,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IACjE,MAAM,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpC,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,CAAC;CAC/E,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,oBAAoB,EAC7B,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI,EACtB,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,OAAO,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CA4C9E;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAIrE;AAED,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,OAAO,EAChB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACnC,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA0J1B"}
|
package/dist/api-routes.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { readdirSync, statSync, existsSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
+
import { collapseSlashes } from '@vesk/compiler/src/router';
|
|
4
|
+
import { assertSameOrigin, DEFAULT_MAX_BODY_BYTES } from '@vesk/compiler/src/server-utils';
|
|
3
5
|
function basename(p) {
|
|
4
6
|
const idx = p.lastIndexOf('/');
|
|
5
7
|
return idx === -1 ? p : p.slice(idx + 1);
|
|
@@ -69,7 +71,7 @@ function scanApiDir(rootDir, dir, parentPath) {
|
|
|
69
71
|
: (parentPath || '/');
|
|
70
72
|
const node = {
|
|
71
73
|
path: seg,
|
|
72
|
-
fullPath: fullPath
|
|
74
|
+
fullPath: collapseSlashes(fullPath) || '/',
|
|
73
75
|
isDynamic,
|
|
74
76
|
isCatchAll,
|
|
75
77
|
filePath: hasRoute && routeFileName ? join(dir, routeFileName) : null,
|
|
@@ -95,7 +97,14 @@ function scanApiDir(rootDir, dir, parentPath) {
|
|
|
95
97
|
return nodes;
|
|
96
98
|
}
|
|
97
99
|
export function matchApiUrl(tree, pathname) {
|
|
98
|
-
|
|
100
|
+
let normalized = pathname.split('?')[0].split('#')[0];
|
|
101
|
+
// strip a leading /api segment (exact or followed by /) without regex
|
|
102
|
+
if (normalized === '/api') {
|
|
103
|
+
normalized = '/';
|
|
104
|
+
}
|
|
105
|
+
else if (normalized.startsWith('/api/') && !normalized.startsWith('//')) {
|
|
106
|
+
normalized = normalized.slice(4);
|
|
107
|
+
}
|
|
99
108
|
const parts = normalized.split('/').filter(Boolean);
|
|
100
109
|
const params = {};
|
|
101
110
|
function matchNodes(nodes, partIndex) {
|
|
@@ -169,7 +178,7 @@ export function parseCookies(str) {
|
|
|
169
178
|
* `json()`/`text()` are patched accordingly. A `cookies` getter is attached
|
|
170
179
|
* (NextRequest-compatible).
|
|
171
180
|
*/
|
|
172
|
-
export function buildWebRequest(nodeReq, url, body) {
|
|
181
|
+
export function buildWebRequest(nodeReq, url, body, options) {
|
|
173
182
|
const parsedUrl = new URL(url, `http://${nodeReq.headers?.host || 'localhost'}`);
|
|
174
183
|
const method = nodeReq.method || 'GET';
|
|
175
184
|
const headers = {};
|
|
@@ -183,8 +192,15 @@ export function buildWebRequest(nodeReq, url, body) {
|
|
|
183
192
|
if (_bodyBuffer)
|
|
184
193
|
return _bodyBuffer;
|
|
185
194
|
const chunks = [];
|
|
186
|
-
|
|
187
|
-
|
|
195
|
+
let total = 0;
|
|
196
|
+
const max = options?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
197
|
+
for await (const chunk of nodeReq) {
|
|
198
|
+
const bytes = typeof chunk === 'string' ? Buffer.from(chunk) : chunk;
|
|
199
|
+
total += bytes.byteLength;
|
|
200
|
+
if (total > max)
|
|
201
|
+
throw tooLargeError(max);
|
|
202
|
+
chunks.push(bytes);
|
|
203
|
+
}
|
|
188
204
|
_bodyBuffer = Buffer.concat(chunks);
|
|
189
205
|
return _bodyBuffer;
|
|
190
206
|
};
|
|
@@ -210,6 +226,11 @@ export function buildWebRequest(nodeReq, url, body) {
|
|
|
210
226
|
Object.defineProperty(webRequest, 'query', { get: () => query, enumerable: true });
|
|
211
227
|
return webRequest;
|
|
212
228
|
}
|
|
229
|
+
export function tooLargeError(max) {
|
|
230
|
+
const err = new Error(`Request body exceeds limit (${max} bytes)`);
|
|
231
|
+
err.status = 413;
|
|
232
|
+
return err;
|
|
233
|
+
}
|
|
213
234
|
export async function executeApiRoute(filePath, method, request, params = {}, locals = {}, devCache) {
|
|
214
235
|
let mod;
|
|
215
236
|
try {
|
|
@@ -224,11 +245,33 @@ export async function executeApiRoute(filePath, method, request, params = {}, lo
|
|
|
224
245
|
}
|
|
225
246
|
}
|
|
226
247
|
catch (e) {
|
|
227
|
-
|
|
248
|
+
// details only in dev (devCache present); prod gets a generic message
|
|
249
|
+
const body = devCache
|
|
250
|
+
? { error: 'Failed to load route module', details: e.message }
|
|
251
|
+
: { error: 'Failed to load route module' };
|
|
252
|
+
return new Response(JSON.stringify(body), {
|
|
228
253
|
status: 500, headers: { 'Content-Type': 'application/json' },
|
|
229
254
|
});
|
|
230
255
|
}
|
|
231
256
|
const routeConfig = (mod.config || {});
|
|
257
|
+
// Default CSRF defense for mutating API calls: same-origin check unless the
|
|
258
|
+
// route opts out via `config.csrf = false`.
|
|
259
|
+
{
|
|
260
|
+
const methodUpper = method.toUpperCase();
|
|
261
|
+
if (routeConfig.csrf !== false && methodUpper !== 'GET' && methodUpper !== 'HEAD' && methodUpper !== 'OPTIONS') {
|
|
262
|
+
try {
|
|
263
|
+
assertSameOrigin({
|
|
264
|
+
method: methodUpper,
|
|
265
|
+
headers: Object.fromEntries([...request.headers.entries()].map(([k, v]) => [k, Array.isArray(v) ? v.join(', ') : v])),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return new Response(JSON.stringify({ error: 'Cross-origin request blocked' }), {
|
|
270
|
+
status: 403, headers: { 'Content-Type': 'application/json' },
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
232
275
|
const handler = mod[method];
|
|
233
276
|
if (!handler) {
|
|
234
277
|
if (method === 'OPTIONS') {
|
|
@@ -326,7 +369,9 @@ export async function executeApiRoute(filePath, method, request, params = {}, lo
|
|
|
326
369
|
status: 404, headers: { 'Content-Type': 'application/json' },
|
|
327
370
|
});
|
|
328
371
|
}
|
|
329
|
-
|
|
372
|
+
// never leak internal error messages in production responses
|
|
373
|
+
const body = devCache ? { error: err.message } : { error: 'Internal Server Error' };
|
|
374
|
+
return new Response(JSON.stringify(body), {
|
|
330
375
|
status: 500, headers: { 'Content-Type': 'application/json' },
|
|
331
376
|
});
|
|
332
377
|
}
|
package/dist/client-codegen.d.ts
CHANGED
|
@@ -14,6 +14,21 @@ export declare function compileClient(source: string, _componentName: string | n
|
|
|
14
14
|
forceClient?: boolean;
|
|
15
15
|
hydrate?: boolean;
|
|
16
16
|
includeTopLevel?: boolean;
|
|
17
|
+
sourcePath?: string;
|
|
18
|
+
mdRoots?: string[];
|
|
17
19
|
}): string;
|
|
20
|
+
/**
|
|
21
|
+
* Compiles a component source in BOTH client modes (plain + hydrate)
|
|
22
|
+
* sharing a single parse/IR pass. Used by the dev-server hot path, where
|
|
23
|
+
* every edit otherwise pays the full acorn+TS parse twice. Also returns
|
|
24
|
+
* the resolved component name using the exact selection order of
|
|
25
|
+
* `resolveComponentName`, so callers don't need a second full parse just
|
|
26
|
+
* to learn the name.
|
|
27
|
+
*/
|
|
28
|
+
export declare function compileClientBoth(source: string, _componentName: string | null): {
|
|
29
|
+
comp: string;
|
|
30
|
+
hyd: string;
|
|
31
|
+
name: string | null;
|
|
32
|
+
};
|
|
18
33
|
export { compileClient as compile, isStaticIR };
|
|
19
34
|
//# sourceMappingURL=client-codegen.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client-codegen.d.ts","sourceRoot":"","sources":["../src/client-codegen.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAuB,MAAM,uBAAuB,CAAC;AACzE,OAAO,EAGL,cAAc,EAQd,gBAAgB,EAOjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAuCxD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1D;AAoBD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,CAwGlI;AAID,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAU5E;AAqjCD,iBAAS,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAe3C;AA2HD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO9C;AA2DD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAAG,MAAM,CAOnN;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAqBnI;AAED,OAAO,EAAE,aAAa,IAAI,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/client-codegen.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { walk } from 'zimmerframe';
|
|
2
2
|
import { print } from 'esrap';
|
|
3
3
|
import ts from 'esrap/languages/ts';
|
|
4
|
+
import tsx from 'esrap/languages/tsx';
|
|
4
5
|
import { StaticNode, TextNode, DynamicBinding, OpaqueDynamicRegion, MapRegion, WhileLoop, SwitchBlock, TryCatch, ForLoop, TrackDecl, RuntimeStatement, ComponentRef, ComponentCall, ServerBlock, ClientBlock, HeadBlock, SlotNode, } from '@vesk/compiler/src/ir';
|
|
5
6
|
import { parse } from '@vesk/compiler/src/parser';
|
|
6
7
|
import { generateIR } from '@vesk/compiler/src/ir-generator';
|
|
7
8
|
import { transformTopLevelForActions } from '@vesk/compiler/src/actions';
|
|
8
9
|
import { extractRuntimeNames } from '@vesk/compiler/src/server-utils';
|
|
9
10
|
import { stripTrackGeneric } from '@vesk/compiler/src/scan';
|
|
11
|
+
import { inlineMdImportsFrom } from '@vesk/compiler/src/md-inline';
|
|
10
12
|
import { stripTsTypes, hasTsSyntax } from '@vesk/compiler/src/strip-ts';
|
|
11
13
|
function memberExpr(object, property) {
|
|
12
14
|
return {
|
|
@@ -44,6 +46,28 @@ export function semicolonizeStatement(code) {
|
|
|
44
46
|
return code;
|
|
45
47
|
return code + ';';
|
|
46
48
|
}
|
|
49
|
+
function containsJsx(node, depth = 0) {
|
|
50
|
+
if (!node || typeof node !== 'object' || depth > 40)
|
|
51
|
+
return false;
|
|
52
|
+
if (Array.isArray(node)) {
|
|
53
|
+
for (const item of node) {
|
|
54
|
+
if (containsJsx(item, depth + 1))
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (typeof node.type === 'string' && (node.type === 'JSXElement' || node.type === 'JSXFragment'))
|
|
60
|
+
return true;
|
|
61
|
+
for (const key of Object.keys(node)) {
|
|
62
|
+
const v = node[key];
|
|
63
|
+
if (v && typeof v === 'object' && containsJsx(v, depth + 1))
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
function printAst(ast) {
|
|
69
|
+
return print(ast, containsJsx(ast) ? tsx() : ts()).code;
|
|
70
|
+
}
|
|
47
71
|
export function transformTracked(irNode, tracked) {
|
|
48
72
|
const ast = irNode.ast;
|
|
49
73
|
if (!ast)
|
|
@@ -51,7 +75,7 @@ export function transformTracked(irNode, tracked) {
|
|
|
51
75
|
if (tracked.size === 0) {
|
|
52
76
|
if (!hasTsSyntax(ast))
|
|
53
77
|
return irNode.raw;
|
|
54
|
-
return
|
|
78
|
+
return printAst(stripTsTypes(ast));
|
|
55
79
|
}
|
|
56
80
|
const stripped = stripTsTypes(ast);
|
|
57
81
|
const transformed = walk(stripped, tracked, {
|
|
@@ -139,7 +163,7 @@ export function transformTracked(irNode, tracked) {
|
|
|
139
163
|
return context.next();
|
|
140
164
|
},
|
|
141
165
|
});
|
|
142
|
-
return print(transformed, ts()).code;
|
|
166
|
+
return print(transformed, containsJsx(transformed) ? tsx() : ts()).code;
|
|
143
167
|
}
|
|
144
168
|
export function collectTrackedNames(body) {
|
|
145
169
|
const names = new Map();
|
|
@@ -1458,15 +1482,13 @@ function hasKeyedMap(nodes) {
|
|
|
1458
1482
|
}
|
|
1459
1483
|
export function escapeHtml(str) {
|
|
1460
1484
|
return str
|
|
1461
|
-
.
|
|
1462
|
-
.
|
|
1463
|
-
.
|
|
1464
|
-
.
|
|
1465
|
-
.
|
|
1485
|
+
.split('&').join('&')
|
|
1486
|
+
.split('<').join('<')
|
|
1487
|
+
.split('>').join('>')
|
|
1488
|
+
.split('"').join('"')
|
|
1489
|
+
.split("'").join(''');
|
|
1466
1490
|
}
|
|
1467
|
-
|
|
1468
|
-
const ast = parse(source);
|
|
1469
|
-
const ir = generateIR(ast, source);
|
|
1491
|
+
function emitClientFromIR(ir, options) {
|
|
1470
1492
|
const needsClient = ir.components.some((c) => c.isClient || !isStaticComponent(c));
|
|
1471
1493
|
if (!options.forceClient && !needsClient) {
|
|
1472
1494
|
return '';
|
|
@@ -1520,4 +1542,45 @@ ${exportCode}
|
|
|
1520
1542
|
`;
|
|
1521
1543
|
return moduleCode.trim();
|
|
1522
1544
|
}
|
|
1545
|
+
export function compileClient(source, _componentName, options = {}) {
|
|
1546
|
+
if (options.sourcePath) {
|
|
1547
|
+
source = inlineMdImportsFrom(source, options.sourcePath, options.mdRoots || []);
|
|
1548
|
+
}
|
|
1549
|
+
const ast = parse(source);
|
|
1550
|
+
const ir = generateIR(ast, source);
|
|
1551
|
+
return emitClientFromIR(ir, options);
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Compiles a component source in BOTH client modes (plain + hydrate)
|
|
1555
|
+
* sharing a single parse/IR pass. Used by the dev-server hot path, where
|
|
1556
|
+
* every edit otherwise pays the full acorn+TS parse twice. Also returns
|
|
1557
|
+
* the resolved component name using the exact selection order of
|
|
1558
|
+
* `resolveComponentName`, so callers don't need a second full parse just
|
|
1559
|
+
* to learn the name.
|
|
1560
|
+
*/
|
|
1561
|
+
export function compileClientBoth(source, _componentName) {
|
|
1562
|
+
const ast = parse(source);
|
|
1563
|
+
// Downstream type-stripping mutates AST nodes in place (stripTsTypes),
|
|
1564
|
+
// so each emit mode needs its own tree. Cloning is far cheaper than the
|
|
1565
|
+
// second full acorn+TS parse this replaces.
|
|
1566
|
+
const hydAst = structuredClone(ast);
|
|
1567
|
+
const ir = generateIR(ast, source);
|
|
1568
|
+
const irHyd = generateIR(hydAst, source);
|
|
1569
|
+
const defaultComp = ir.components.find((c) => c.defaultExport);
|
|
1570
|
+
let name = null;
|
|
1571
|
+
if (defaultComp)
|
|
1572
|
+
name = defaultComp.name;
|
|
1573
|
+
else if (ir.components.length > 0)
|
|
1574
|
+
name = ir.components[0].name;
|
|
1575
|
+
else {
|
|
1576
|
+
const exportedComp = ir.components.find((c) => c.exported);
|
|
1577
|
+
if (exportedComp)
|
|
1578
|
+
name = exportedComp.name;
|
|
1579
|
+
}
|
|
1580
|
+
return {
|
|
1581
|
+
comp: emitClientFromIR(ir, { forceClient: true }),
|
|
1582
|
+
hyd: emitClientFromIR(irHyd, { forceClient: true, hydrate: true, includeTopLevel: false }),
|
|
1583
|
+
name,
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1523
1586
|
export { compileClient as compile, isStaticIR };
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { VeskConfig, VeskPlugin, VeskSecurity } from '@vesk/compiler/src/types';
|
|
2
|
+
/** Tags allowed by default when md.html = 'allowlist' and no allowTags given. */
|
|
3
|
+
export declare const MD_DEFAULT_ALLOW_TAGS: string[];
|
|
2
4
|
export declare function preset(name: string, overrides?: VeskSecurity): VeskSecurity;
|
|
3
5
|
export declare function definePlugin<P extends VeskPlugin>(plugin: P): P;
|
|
4
6
|
export declare function defineConfig(config: VeskConfig): VeskConfig;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAgC,MAAM,0BAA0B,CAAC;AAGnH,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,UAIjC,CAAC;AA6CF,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,YAAiB,GAAG,YAAY,CAY/E;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,UAAU,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAQ/D;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAuB3D;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,UAAU,CAkC7D"}
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
import { VeskError } from '@vesk/compiler/src/errors';
|
|
2
|
+
/** Tags allowed by default when md.html = 'allowlist' and no allowTags given. */
|
|
3
|
+
export const MD_DEFAULT_ALLOW_TAGS = [
|
|
4
|
+
'a', 'abbr', 'b', 'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'del', 'dfn', 'em',
|
|
5
|
+
'i', 'ins', 'kbd', 'mark', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'small', 'span',
|
|
6
|
+
'strong', 'sub', 'sup', 'time', 'u', 'var', 'wbr',
|
|
7
|
+
];
|
|
8
|
+
const MD_HTML_MODES = ['escape', 'allow', 'allowlist'];
|
|
9
|
+
function normalizeMdConfig(md) {
|
|
10
|
+
if (!md || typeof md !== 'object')
|
|
11
|
+
return md;
|
|
12
|
+
if (md.html !== undefined && !MD_HTML_MODES.includes(md.html)) {
|
|
13
|
+
throw VeskError.configError(`Unknown md.html mode: "${md.html}".`, MD_HTML_MODES);
|
|
14
|
+
}
|
|
15
|
+
const out = { ...md };
|
|
16
|
+
if (out.allowTags) {
|
|
17
|
+
if (!Array.isArray(out.allowTags)) {
|
|
18
|
+
throw VeskError.configError('md.allowTags must be an array of tag names.', []);
|
|
19
|
+
}
|
|
20
|
+
out.allowTags = out.allowTags.map((t) => String(t).toLowerCase().replace(/[^a-z0-9-]/g, '')).filter(Boolean);
|
|
21
|
+
}
|
|
22
|
+
return out;
|
|
23
|
+
}
|
|
2
24
|
const SECURITY_PRESETS = {
|
|
3
25
|
strict: {
|
|
4
26
|
autoEscape: true,
|
|
@@ -71,6 +93,9 @@ export function defineConfig(config) {
|
|
|
71
93
|
sec.redactLogs = true;
|
|
72
94
|
if (config.routeDataCache === undefined)
|
|
73
95
|
config.routeDataCache = 0;
|
|
96
|
+
const md = normalizeMdConfig(config.md);
|
|
97
|
+
if (md !== undefined)
|
|
98
|
+
config.md = md;
|
|
74
99
|
return config;
|
|
75
100
|
}
|
|
76
101
|
export function validateConfig(config) {
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBxD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,WAAW,GAAE,MAAU,GAAG,MAAM,GAAG,IAAI,CAWrG;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAoBxD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,WAAW,GAAE,MAAU,GAAG,MAAM,GAAG,IAAI,CAWrG;AAqCD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAgBD,qBAAa,SAAU,SAAQ,KAAK;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEF,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB;IAYxD,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IA6BnG,MAAM,CAAC,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAmB3D,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAkBvF,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAkBvF,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAO3G,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAM,EAAO,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAWvG,MAAM,CAAC,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,SAAS;IAkB/G,QAAQ,IAAI,MAAM;IAgBlB,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAclC"}
|
package/dist/errors.js
CHANGED
|
@@ -31,19 +31,48 @@ export function didYouMean(name, candidates, maxDistance = 3) {
|
|
|
31
31
|
return best;
|
|
32
32
|
}
|
|
33
33
|
function extractLineColumn(message) {
|
|
34
|
-
const lineMatch = message.match(/(?:line|at\s+line)\s*(\d+)/i);
|
|
35
|
-
const colMatch = message.match(/(?:column|col)\s*(\d+)/i);
|
|
36
34
|
return {
|
|
37
|
-
line:
|
|
38
|
-
column:
|
|
35
|
+
line: findKeywordNumber(message, ['at line', 'line']),
|
|
36
|
+
column: findKeywordNumber(message, ['column', 'col']),
|
|
39
37
|
};
|
|
40
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Finds `<keyword><whitespace>*<digits>` in `message`, trying longer keyword
|
|
41
|
+
* variants first so 'column' is not matched as 'col' + 'umn'. Char-scan only.
|
|
42
|
+
*/
|
|
43
|
+
function findKeywordNumber(message, keywords) {
|
|
44
|
+
const lower = message.toLowerCase();
|
|
45
|
+
for (const kw of keywords) {
|
|
46
|
+
let from = 0;
|
|
47
|
+
while (from <= lower.length - kw.length) {
|
|
48
|
+
const idx = lower.indexOf(kw, from);
|
|
49
|
+
if (idx === -1)
|
|
50
|
+
break;
|
|
51
|
+
// word boundary before the keyword
|
|
52
|
+
const before = idx > 0 ? lower[idx - 1] : ' ';
|
|
53
|
+
if (!(before >= 'a' && before <= 'z')) {
|
|
54
|
+
let j = idx + kw.length;
|
|
55
|
+
while (j < message.length && (message[j] === ' ' || message[j] === '\t'))
|
|
56
|
+
j++;
|
|
57
|
+
if (message[j] >= '0' && message[j] <= '9') {
|
|
58
|
+
let end = j;
|
|
59
|
+
while (end < message.length && message[end] >= '0' && message[end] <= '9')
|
|
60
|
+
end++;
|
|
61
|
+
return parseInt(message.slice(j, end));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
from = idx + 1;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
41
69
|
const VESK_BUILTINS = [
|
|
42
70
|
'useFetch', 'useRouter', 'useParams', 'usePathname', 'useSearchParams',
|
|
43
71
|
'useNavigate', 'useHead', 'useTitle',
|
|
44
72
|
'Form', 'Field', 'Link', 'NavLink', 'Outlet',
|
|
45
73
|
'Image', 'Portal',
|
|
46
74
|
'Experiment',
|
|
75
|
+
'LoadingIndicator', 'useLoadingIndicator',
|
|
47
76
|
'required', 'email', 'minLength', 'maxLength', 'pattern', 'custom',
|
|
48
77
|
'track', 'get', 'set', 'derived', 'effect', 'batch', 'untrack',
|
|
49
78
|
'cookies', 'headers', 'locals',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAoBP,MAAM,uBAAuB,CAAC;AA+I/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;
|
|
1
|
+
{"version":3,"file":"ir-generator.d.ts","sourceRoot":"","sources":["../src/ir-generator.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EAoBP,MAAM,uBAAuB,CAAC;AA+I/B,wBAAgB,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,EAAE,CAAA;CAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAkCnL;AAmsBD,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CA0N3D"}
|
package/dist/ir-generator.js
CHANGED
|
@@ -238,6 +238,20 @@ function processAttribute(source, attr) {
|
|
|
238
238
|
}
|
|
239
239
|
return { name, value: '' };
|
|
240
240
|
}
|
|
241
|
+
/**
|
|
242
|
+
* Recognizes a statement-mode `if (cond)` opening among JSX children.
|
|
243
|
+
* Returns the condition source, or null when `text` does not open an if
|
|
244
|
+
* header (keyword + balanced parens).
|
|
245
|
+
*/
|
|
246
|
+
function extractIfHeader(text) {
|
|
247
|
+
if (!startsWithIdentifier(text, 'if'))
|
|
248
|
+
return null;
|
|
249
|
+
let i = skipWhitespace(text, 2);
|
|
250
|
+
if (text[i] !== '(')
|
|
251
|
+
return null;
|
|
252
|
+
const end = findBalancedEnd(text, i);
|
|
253
|
+
return text.slice(i + 1, end).trim();
|
|
254
|
+
}
|
|
241
255
|
function extractForHeader(text) {
|
|
242
256
|
if (!startsWithIdentifier(text, 'for'))
|
|
243
257
|
return null;
|
|
@@ -271,6 +285,67 @@ function processJSXChildren(source, children) {
|
|
|
271
285
|
i++;
|
|
272
286
|
continue;
|
|
273
287
|
}
|
|
288
|
+
// ── statement-mode if / else-if / else among element children ──
|
|
289
|
+
const ifCond = extractIfHeader(trimmed);
|
|
290
|
+
const seqNext = children[i + 1];
|
|
291
|
+
if (ifCond !== null &&
|
|
292
|
+
seqNext !== undefined &&
|
|
293
|
+
seqNext.type === 'JSXExpressionContainer' &&
|
|
294
|
+
seqNext.expression.type !== 'JSXEmptyExpression') {
|
|
295
|
+
const links = [];
|
|
296
|
+
let alternate = null;
|
|
297
|
+
const containerToNodes = (container) => {
|
|
298
|
+
const exprNode = container.expression;
|
|
299
|
+
if (exprNode.type === 'JSXFragment') {
|
|
300
|
+
const inner = [];
|
|
301
|
+
for (const c of exprNode.children)
|
|
302
|
+
inner.push(...processJSXChildren(source, [c]));
|
|
303
|
+
return inner;
|
|
304
|
+
}
|
|
305
|
+
if (exprNode.type === 'JSXElement')
|
|
306
|
+
return processJSXElement(source, exprNode);
|
|
307
|
+
return exprToIR(source, exprNode);
|
|
308
|
+
};
|
|
309
|
+
links.push({
|
|
310
|
+
cond: new Expression(ifCond, [], parseExprNode(ifCond), null),
|
|
311
|
+
nodes: containerToNodes(seqNext),
|
|
312
|
+
});
|
|
313
|
+
let j = i + 2;
|
|
314
|
+
while (j < children.length) {
|
|
315
|
+
const sep = children[j];
|
|
316
|
+
if (sep === undefined || sep.type !== 'JSXText')
|
|
317
|
+
break;
|
|
318
|
+
const sv = sep.value.trim();
|
|
319
|
+
const cont = children[j + 1];
|
|
320
|
+
if (sv.startsWith('} else if') || sv.startsWith('else if')) {
|
|
321
|
+
const ifIdx = sv.indexOf('if');
|
|
322
|
+
const header = extractIfHeader(sv.slice(ifIdx));
|
|
323
|
+
if (header === null || cont === undefined || cont.type !== 'JSXExpressionContainer')
|
|
324
|
+
break;
|
|
325
|
+
links.push({
|
|
326
|
+
cond: new Expression(header, [], parseExprNode(header), null),
|
|
327
|
+
nodes: containerToNodes(cont),
|
|
328
|
+
});
|
|
329
|
+
j += 2;
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
if (sv.startsWith('} else') || sv === 'else') {
|
|
333
|
+
if (cont === undefined || cont.type !== 'JSXExpressionContainer')
|
|
334
|
+
break;
|
|
335
|
+
alternate = containerToNodes(cont);
|
|
336
|
+
j += 2;
|
|
337
|
+
}
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
// Fold right-to-left: earlier conditions wrap later ones as alternate.
|
|
341
|
+
let tail = alternate || [];
|
|
342
|
+
for (let k = links.length - 1; k >= 0; k--) {
|
|
343
|
+
tail = [new OpaqueDynamicRegion(links[k].cond, links[k].nodes, tail)];
|
|
344
|
+
}
|
|
345
|
+
result.push(...tail);
|
|
346
|
+
i = j;
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
274
349
|
const forDecl = extractForHeader(trimmed);
|
|
275
350
|
const nextChild = children[i + 1];
|
|
276
351
|
if (forDecl !== null && nextChild !== undefined && (nextChild.type === 'JSXExpressionContainer' ||
|
|
@@ -835,6 +910,37 @@ function processEnum(node, source, exported) {
|
|
|
835
910
|
const prefix = exported ? `export const ${name}` : `const ${name}`;
|
|
836
911
|
return `${prefix} = { ${allPairs} };`;
|
|
837
912
|
}
|
|
913
|
+
/**
|
|
914
|
+
* Normalizes any `@vesk/runtime/<subpath>` import specifier to the bare
|
|
915
|
+
* `'@vesk/runtime'` form. The runtime resolves all subpaths onto the same
|
|
916
|
+
* module graph, and downstream consumers (client scope injection, chunk
|
|
917
|
+
* stripping) key off the canonical bare specifier. Char-scan based — no
|
|
918
|
+
* regex, per repo rule.
|
|
919
|
+
*/
|
|
920
|
+
function normalizeRuntimeSpecifier(stmt) {
|
|
921
|
+
const fromIdx = stmt.indexOf(' from ');
|
|
922
|
+
if (fromIdx === -1)
|
|
923
|
+
return stmt;
|
|
924
|
+
const q1 = idxOfQuote(stmt, fromIdx);
|
|
925
|
+
if (q1 === -1)
|
|
926
|
+
return stmt;
|
|
927
|
+
const quote = stmt[q1];
|
|
928
|
+
const q2 = stmt.indexOf(quote, q1 + 1);
|
|
929
|
+
if (q2 === -1)
|
|
930
|
+
return stmt;
|
|
931
|
+
const spec = stmt.slice(q1 + 1, q2);
|
|
932
|
+
if (spec === '@vesk/runtime' || !spec.startsWith('@vesk/runtime/'))
|
|
933
|
+
return stmt;
|
|
934
|
+
return stmt.slice(0, q1 + 1) + '@vesk/runtime' + stmt.slice(q2);
|
|
935
|
+
}
|
|
936
|
+
function idxOfQuote(s, from) {
|
|
937
|
+
for (let i = from; i < s.length; i++) {
|
|
938
|
+
const c = s[i];
|
|
939
|
+
if (c === "'" || c === '"')
|
|
940
|
+
return i;
|
|
941
|
+
}
|
|
942
|
+
return -1;
|
|
943
|
+
}
|
|
838
944
|
export function generateIR(ast, source) {
|
|
839
945
|
__vskAnnotations = ast.__vskAnnotations ?? [];
|
|
840
946
|
const components = [];
|
|
@@ -846,9 +952,10 @@ export function generateIR(ast, source) {
|
|
|
846
952
|
for (const node of ast.body) {
|
|
847
953
|
if (node.type === 'ImportDeclaration') {
|
|
848
954
|
const raw = getSource(source, node);
|
|
849
|
-
|
|
955
|
+
let cleaned = stripTypeImport(raw);
|
|
850
956
|
if (cleaned === null)
|
|
851
957
|
continue;
|
|
958
|
+
cleaned = normalizeRuntimeSpecifier(cleaned);
|
|
852
959
|
imports.push(cleaned);
|
|
853
960
|
for (const spec of node.specifiers) {
|
|
854
961
|
if (spec.importKind === 'type')
|
|
@@ -991,6 +1098,7 @@ export function generateIR(ast, source) {
|
|
|
991
1098
|
'Link', 'NavLink', 'Outlet', 'Redirect',
|
|
992
1099
|
'Image', 'Portal',
|
|
993
1100
|
'Experiment',
|
|
1101
|
+
'LoadingIndicator', 'useLoadingIndicator',
|
|
994
1102
|
'JsonLd', 'ArticleSchema', 'ProductSchema', 'FAQPageSchema', 'BreadcrumbListSchema',
|
|
995
1103
|
'OrganizationSchema', 'LocalBusinessSchema', 'VideoSchema',
|
|
996
1104
|
'effect', 'derived', 'untrack', 'peek', 'tick', 'flushSync', 'on_destroy',
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rewrites static `content="<file>.md"` attributes on <Md> elements into
|
|
3
|
+
* inlined constants. Returns the transformed source; when nothing matches,
|
|
4
|
+
* the original string is returned untouched.
|
|
5
|
+
*
|
|
6
|
+
* `mdRoots` are candidate project roots for absolute-style specifiers
|
|
7
|
+
* ("/x.md"); each root is tried as <root>/public<x> and <root><x>.
|
|
8
|
+
*/
|
|
9
|
+
export declare function inlineMdContentAttrs(source: string, importerDir: string | null, mdRoots?: string[]): string;
|
|
10
|
+
/**
|
|
11
|
+
* Candidate project roots for absolute-style specifiers: walks up from
|
|
12
|
+
* `dir` collecting directories that contain a package.json (bounded).
|
|
13
|
+
*/
|
|
14
|
+
export declare function guessProjectRoots(dir: string | null): string[];
|
|
15
|
+
/** Convenience wrapper used by pipelines that already know the file dir. */
|
|
16
|
+
export declare function inlineMdImportsFrom(source: string, importerFile: string | null, mdRoots?: string[]): string;
|
|
17
|
+
//# sourceMappingURL=md-inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"md-inline.d.ts","sourceRoot":"","sources":["../src/md-inline.ts"],"names":[],"mappings":"AA2CA;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,OAAO,GAAE,MAAM,EAAO,GACpB,MAAM,CAoDR;AAoBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,EAAE,CAY9D;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,GAAE,MAAM,EAAO,GAAG,MAAM,CAG/G"}
|