@vesk/compiler 0.2.12 → 0.2.15

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.
@@ -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,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"}
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,CAoC7D"}
package/dist/config.js CHANGED
@@ -119,10 +119,12 @@ export function validateConfig(config) {
119
119
  typeof plugin.onBuildStart === 'function' ||
120
120
  typeof plugin.onBuildEnd === 'function' ||
121
121
  typeof plugin.onRequest === 'function' ||
122
+ typeof plugin.onHead === 'function' ||
123
+ typeof plugin.onHtml === 'function' ||
122
124
  (plugin.provides && typeof plugin.provides === 'object' && Object.keys(plugin.provides).length > 0);
123
125
  if (!hasKnownHook) {
124
126
  throw new Error(`[vesk] Plugin "${plugin.name}" implements none of the recognized ` +
125
- 'hooks (onCSS, onFileWatch, onTransformJS, onBuildStart, onBuildEnd, onRequest) ' +
127
+ 'hooks (onCSS, onFileWatch, onTransformJS, onBuildStart, onBuildEnd, onRequest, onHead, onHtml) ' +
126
128
  'or provides — it will never be called. Check the plugin package version, or see ' +
127
129
  '/docu/cli/plugin-api.md for the current hook contract.');
128
130
  }
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAYD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,cAAc,EAAE,CAAA;CAAE,CA0KpG;AAED,wBAAgB,gBAAgB,IAAI,OAAO,KAAK,CAAC,MAAM,CAEtD;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CA+CzE"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAMtC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAYD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,cAAc,EAAE,CAAA;CAAE,CA0KpG;AAED,wBAAgB,gBAAgB,IAAI,OAAO,KAAK,CAAC,MAAM,CAEtD;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CA8CzE"}
package/dist/parser.js CHANGED
@@ -272,7 +272,6 @@ export function parse(source, options = {}) {
272
272
  'If you wrote literal { or } inside JSX text, escape them as {\'{\'} and {\'}\'} or use { }.',
273
273
  'Ensure all JSX tags are properly closed and component names start with an uppercase letter.',
274
274
  ],
275
- tip: 'Vesk parses with Acorn + TypeScript + JSX — use the code frame above to locate the error.',
276
275
  });
277
276
  }
278
277
  }
@@ -1,5 +1,5 @@
1
1
  export { setRuntimeModule, prettifyHtml, isStatic, escapeHtml, quoteAttr, safeJsonForScript, randomToken, DEFAULT_MAX_BODY_BYTES, raw, exprJS, tryEvalExpr, childrenToHTML, extractTopLevelNames, extractRuntimeNames, buildParamInit, resolveComponentName, loadRuntimeImports, evalTopLevelCode, callStaticProps, callLoadFunction, __vskHydrate, __vskId, __vskImportedNames, resetVskState, setVskHydrate, setVskImportedNames, securityHeaders, corsHeaders, corsPreflight, csrfToken, verifyCsrfToken, csrfGuard, csrfHmac, assertSameOrigin, signCookie, unsignCookie, setSignedCookie, readSignedCookie, securityComment, redactLog, setRedactLogging, createRateLimiter, getClientIp, getClientProtocol, applyTrustProxy, } from '@vesk/compiler/src/server-utils';
2
2
  export { renderHeadHtml, mergeHeadHtml, } from '@vesk/compiler/src/server-head';
3
3
  export { irNodeToJS, generateFunctionBody, buildComponentMap, } from '@vesk/compiler/src/server-jsgen';
4
- export { compileFile, render, renderPage, ssg, renderFullPage, renderPageStream, buildDataScripts, } from '@vesk/compiler/src/server-render';
4
+ export { compileFile, render, renderPage, ssg, renderFullPage, renderPageStream, buildDataScripts, applyHeadPlugins, applyHeadInjects, applyHtmlPlugins, } from '@vesk/compiler/src/server-render';
5
5
  //# sourceMappingURL=server-codegen.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-codegen.d.ts","sourceRoot":"","sources":["../src/server-codegen.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,GAAG,EACH,MAAM,EACN,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,aAAa,EACb,SAAS,EACT,eAAe,EACf,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,eAAe,GAChB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,cAAc,EACd,aAAa,GACd,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,WAAW,EACX,MAAM,EACN,UAAU,EACV,GAAG,EACH,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"server-codegen.d.ts","sourceRoot":"","sources":["../src/server-codegen.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,WAAW,EACX,sBAAsB,EACtB,GAAG,EACH,MAAM,EACN,WAAW,EACX,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,eAAe,EACf,WAAW,EACX,aAAa,EACb,SAAS,EACT,eAAe,EACf,SAAS,EACT,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,eAAe,GAChB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,cAAc,EACd,aAAa,GACd,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EACL,WAAW,EACX,MAAM,EACN,UAAU,EACV,GAAG,EACH,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,kCAAkC,CAAC"}
@@ -1,4 +1,4 @@
1
1
  export { setRuntimeModule, prettifyHtml, isStatic, escapeHtml, quoteAttr, safeJsonForScript, randomToken, DEFAULT_MAX_BODY_BYTES, raw, exprJS, tryEvalExpr, childrenToHTML, extractTopLevelNames, extractRuntimeNames, buildParamInit, resolveComponentName, loadRuntimeImports, evalTopLevelCode, callStaticProps, callLoadFunction, __vskHydrate, __vskId, __vskImportedNames, resetVskState, setVskHydrate, setVskImportedNames, securityHeaders, corsHeaders, corsPreflight, csrfToken, verifyCsrfToken, csrfGuard, csrfHmac, assertSameOrigin, signCookie, unsignCookie, setSignedCookie, readSignedCookie, securityComment, redactLog, setRedactLogging, createRateLimiter, getClientIp, getClientProtocol, applyTrustProxy, } from '@vesk/compiler/src/server-utils';
2
2
  export { renderHeadHtml, mergeHeadHtml, } from '@vesk/compiler/src/server-head';
3
3
  export { irNodeToJS, generateFunctionBody, buildComponentMap, } from '@vesk/compiler/src/server-jsgen';
4
- export { compileFile, render, renderPage, ssg, renderFullPage, renderPageStream, buildDataScripts, } from '@vesk/compiler/src/server-render';
4
+ export { compileFile, render, renderPage, ssg, renderFullPage, renderPageStream, buildDataScripts, applyHeadPlugins, applyHeadInjects, applyHtmlPlugins, } from '@vesk/compiler/src/server-render';
@@ -1 +1 @@
1
- {"version":3,"file":"server-head.d.ts","sourceRoot":"","sources":["../src/server-head.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AA+GzD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,CAe7F;AAmFD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CA6DxI"}
1
+ {"version":3,"file":"server-head.d.ts","sourceRoot":"","sources":["../src/server-head.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AA+GzD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,MAAM,CAe7F;AAoFD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAkExI"}
@@ -191,8 +191,9 @@ function scanHeadTag(html, lt) {
191
191
  attrs.set(aName, value);
192
192
  }
193
193
  let raw = html.slice(lt, i);
194
- if (!selfClosing && tag === 'title') {
195
- const closeTag = html.indexOf('</title', i);
194
+ const nonVoidTags = new Set(['title', 'script', 'style', 'noscript']);
195
+ if (!selfClosing && nonVoidTags.has(tag)) {
196
+ const closeTag = html.indexOf('</' + tag, i);
196
197
  if (closeTag !== -1) {
197
198
  const end = html.indexOf('>', closeTag);
198
199
  if (end !== -1) {
@@ -282,8 +283,13 @@ export function mergeHeadHtml(pageHead, layoutHead) {
282
283
  const bi = order.findIndex(o => bk.startsWith(o));
283
284
  return (ai === -1 ? 999 : ai) - (bi === -1 ? 999 : bi);
284
285
  });
286
+ const unkeyed = [];
287
+ for (const e of [...layoutEntries, ...pageEntries]) {
288
+ if (extractKey(e) === null && !unkeyed.includes(e.raw))
289
+ unkeyed.push(e.raw);
290
+ }
285
291
  return {
286
- html: sorted.map(e => e.html).join('\n'),
292
+ html: [...sorted.map(e => e.html), ...unkeyed].join('\n'),
287
293
  conflicts,
288
294
  };
289
295
  }
@@ -4,6 +4,27 @@ export declare function compileFile(source: string, options?: {
4
4
  }): CompileFileResult;
5
5
  export declare function render(source: string, componentName: string, props?: Record<string, unknown>, registry?: Map<string, Function>, options?: Record<string, unknown>): string | Promise<string>;
6
6
  export declare function renderPage(source: string, componentName: string, props?: Record<string, unknown>, registry?: Map<string, Function>, options?: Record<string, unknown>): RenderPageResult | Promise<RenderPageResult>;
7
+ type RenderPluginLike = import('@vesk/types').VeskPlugin;
8
+ interface HeadInjectOptions {
9
+ plugins?: RenderPluginLike[];
10
+ headExtra?: string;
11
+ }
12
+ /**
13
+ * Run the active plugins' `onHead` hooks (config order) against an assembled
14
+ * `<head>` string. A hook returns the new head, or `null` to keep the input.
15
+ */
16
+ export declare function applyHeadPlugins(headHtml: string, plugins: RenderPluginLike[] | undefined | null, ctx?: import('@vesk/types').RenderPluginContext): Promise<string>;
17
+ /**
18
+ * Run the active plugins' `onHtml` hooks (config order) against a finalized
19
+ * full HTML document. Only valid for non-streamed documents.
20
+ */
21
+ export declare function applyHtmlPlugins(html: string, plugins: RenderPluginLike[] | undefined | null, ctx?: import('@vesk/types').RenderPluginContext): Promise<string>;
22
+ /**
23
+ * Resolve head integration for a render call: live `onHead` hooks when plugin
24
+ * objects are available (dev / build / SSG), otherwise merge the baked
25
+ * `headExtra` (prod path — page head wins over baked extras via mergeHeadHtml).
26
+ */
27
+ export declare function applyHeadInjects(headHtml: string, options: HeadInjectOptions, ctx?: import('@vesk/types').RenderPluginContext): Promise<string>;
7
28
  export declare function ssg(source: string, componentName?: string, customProps?: Record<string, unknown>, options?: {
8
29
  registry?: Map<string, Function>;
9
30
  cssUrl?: string;
@@ -14,4 +35,5 @@ export declare function ssg(source: string, componentName?: string, customProps?
14
35
  export declare function buildDataScripts(ssrProps: Record<string, unknown> | null | undefined, ssrData: Record<string, unknown>, external?: ExternalDataScript | null): string[];
15
36
  export declare function renderFullPage(source: string, componentName: string, props?: Record<string, unknown>, registry?: Map<string, Function>, options?: FullPageOptions): Promise<string>;
16
37
  export declare function renderPageStream(source: string, componentName: string, props?: Record<string, unknown>, registry?: Map<string, Function>, options?: FullPageOptions): AsyncGenerator<string>;
38
+ export {};
17
39
  //# sourceMappingURL=server-render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-render.d.ts","sourceRoot":"","sources":["../src/server-render.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,SAAS,EAAE,eAAe,EAAqB,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AA6BvJ,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,iBAAiB,CAEhG;AA6CD,wBAAgB,MAAM,CACpB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,QAAQ,GAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAa,EAC3C,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkC1B;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,QAAQ,GAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAa,EAC3C,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiE9C;AAcD,wBAAsB,GAAG,CACvB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrC,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAO,GACnI,OAAO,CAAC,SAAS,CAAC,CA8DpB;AAED,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,EACpD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,IAAI,GACnC,MAAM,EAAE,CAuBV;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,QAAQ,GAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAa,EAC3C,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAoEjB;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACnC,QAAQ,GAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAa,EAC3C,OAAO,GAAE,eAAoB,GAC5B,cAAc,CAAC,MAAM,CAAC,CA2FxB"}
1
+ {"version":3,"file":"server-render.d.ts","sourceRoot":"","sources":["../src/server-render.ts"],"names":[],"mappings":"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"}
@@ -191,6 +191,54 @@ function clearSsrCells(token) {
191
191
  cells.delete(k);
192
192
  }
193
193
  }
194
+ /**
195
+ * Run the active plugins' `onHead` hooks (config order) against an assembled
196
+ * `<head>` string. A hook returns the new head, or `null` to keep the input.
197
+ */
198
+ export async function applyHeadPlugins(headHtml, plugins, ctx) {
199
+ if (!plugins || plugins.length === 0)
200
+ return headHtml;
201
+ let out = headHtml;
202
+ for (const plugin of plugins) {
203
+ if (typeof plugin.onHead === 'function') {
204
+ const result = await plugin.onHead(out, ctx);
205
+ if (typeof result === 'string')
206
+ out = result;
207
+ }
208
+ }
209
+ return out;
210
+ }
211
+ /**
212
+ * Run the active plugins' `onHtml` hooks (config order) against a finalized
213
+ * full HTML document. Only valid for non-streamed documents.
214
+ */
215
+ export async function applyHtmlPlugins(html, plugins, ctx) {
216
+ if (!plugins || plugins.length === 0)
217
+ return html;
218
+ let out = html;
219
+ for (const plugin of plugins) {
220
+ if (typeof plugin.onHtml === 'function') {
221
+ const result = await plugin.onHtml(out, ctx);
222
+ if (typeof result === 'string')
223
+ out = result;
224
+ }
225
+ }
226
+ return out;
227
+ }
228
+ /**
229
+ * Resolve head integration for a render call: live `onHead` hooks when plugin
230
+ * objects are available (dev / build / SSG), otherwise merge the baked
231
+ * `headExtra` (prod path — page head wins over baked extras via mergeHeadHtml).
232
+ */
233
+ export async function applyHeadInjects(headHtml, options, ctx) {
234
+ if (options.plugins && options.plugins.length > 0) {
235
+ return applyHeadPlugins(headHtml, options.plugins, ctx);
236
+ }
237
+ if (options.headExtra) {
238
+ return mergeHeadHtml(headHtml, options.headExtra).html;
239
+ }
240
+ return headHtml;
241
+ }
194
242
  export async function ssg(source, componentName, customProps, options = {}) {
195
243
  const ast = parse(source, options.sourcePath ? { filename: options.sourcePath } : {});
196
244
  const ir = generateIR(ast, source, options.sourcePath);
@@ -230,16 +278,23 @@ export async function ssg(source, componentName, customProps, options = {}) {
230
278
  : `\n<script>const __vesk_props = ${serializedProps};\n<\/script>\n`;
231
279
  const cssUrls = options.cssUrls || (options.cssUrl ? [options.cssUrl] : []);
232
280
  const cssLink = cssUrls.map(u => `\t<link rel="stylesheet" href="${u}" />\n`).join('');
281
+ const renderCtx = { sourcePath: options.sourcePath };
282
+ let finalHead = ['\t<meta charset="utf-8" />', '\t<meta name="viewport" content="width=device-width, initial-scale=1" />'].join('\n');
283
+ if (cssLink)
284
+ finalHead += '\n' + cssLink.trimEnd();
285
+ if (headHtml)
286
+ finalHead += '\n' + headHtml.split('\n').map((l) => '\t' + l).join('\n');
287
+ finalHead = await applyHeadInjects(finalHead, { plugins: options.plugins, headExtra: options.headExtra }, renderCtx);
233
288
  const html = `<!DOCTYPE html>
234
289
  <html>
235
290
  <head>
236
- \t<meta charset="utf-8" />
237
- \t<meta name="viewport" content="width=device-width, initial-scale=1" />
238
- ${cssLink}${headHtml ? '\t' + headHtml.split('\n').join('\n\t') + '\n' : ''}</head>
291
+ ${finalHead}
292
+ </head>
239
293
  <body>
240
294
  ${bodyHtml}${scriptBlock}</body>
241
295
  </html>
242
296
  `;
297
+ const finalHtml = await applyHtmlPlugins(html, options.plugins, renderCtx);
243
298
  const staticLists = ir.components.some((c) => {
244
299
  return c.body.some((node) => {
245
300
  if (node instanceof MapRegion)
@@ -247,7 +302,7 @@ ${bodyHtml}${scriptBlock}</body>
247
302
  return false;
248
303
  });
249
304
  });
250
- return { html, body: bodyHtml, head: headHtml, props: serializedProps, clientCode, static: !hasClient, staticLists };
305
+ return { html: finalHtml, body: bodyHtml, head: headHtml, props: serializedProps, clientCode, static: !hasClient, staticLists };
251
306
  }
252
307
  export function buildDataScripts(ssrProps, ssrData, external) {
253
308
  const meaningfulKeys = ssrProps !== undefined && ssrProps !== null
@@ -332,16 +387,18 @@ export async function renderFullPage(source, componentName, props = {}, registry
332
387
  if (sec.autoEscape !== false)
333
388
  headLines.push(`\t<!-- vesk: auto-escape enabled -->`);
334
389
  }
335
- return `<!DOCTYPE html>
390
+ const finalHead = await applyHeadInjects(headLines.join('\n'), { plugins: options.plugins, headExtra: options.headExtra }, { sourcePath: options.sourcePath, url: options.__vesk?.url || undefined });
391
+ const docHtml = `<!DOCTYPE html>
336
392
  <html>
337
393
  <head>
338
- ${headLines.join('\n')}</head>
394
+ ${finalHead}</head>
339
395
  <body>
340
396
  <div id="root">
341
397
  ${bodyHtml}
342
398
  </div>
343
399
  ${dataScriptBlock}${clientScript}</body>
344
400
  </html>`;
401
+ return applyHtmlPlugins(docHtml, options.plugins, { sourcePath: options.sourcePath, url: options.__vesk?.url || undefined });
345
402
  }
346
403
  finally {
347
404
  delete globalThis.__vsk_ssr;
@@ -379,17 +436,17 @@ export function renderPageStream(source, componentName, props = {}, registry = n
379
436
  const targetComp = ir.components.find((c) => c.name === componentName);
380
437
  const cssUrls = options.cssUrls || (options.cssUrl ? [options.cssUrl] : []);
381
438
  const cssLink = cssUrls.map(u => `\t<link rel="stylesheet" href="${u}" />\n`).join('');
382
- yield '<!DOCTYPE html>\n<html>\n<head>\n\t<meta charset="utf-8" />\n\t<meta name="viewport" content="width=device-width, initial-scale=1" />\n';
439
+ const headParts = ['\t<meta charset="utf-8" />', '\t<meta name="viewport" content="width=device-width, initial-scale=1" />'];
383
440
  if (cssLink)
384
- yield cssLink;
441
+ headParts.push(cssLink.trimEnd());
385
442
  if (options.security) {
386
443
  const sec = options.security;
387
444
  if (sec.referrerPolicy !== false)
388
- yield `\t<meta name="referrer" content="${quoteAttr(sec.referrerPolicy || 'strict-origin-when-cross-origin')}" />\n`;
445
+ headParts.push(`\t<meta name="referrer" content="${quoteAttr(sec.referrerPolicy || 'strict-origin-when-cross-origin')}" />`);
389
446
  if (sec.contentSecurityPolicy !== false)
390
- yield `\t<meta http-equiv="Content-Security-Policy" content="${quoteAttr(sec.contentSecurityPolicy || "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'")}" />\n`;
447
+ headParts.push(`\t<meta http-equiv="Content-Security-Policy" content="${quoteAttr(sec.contentSecurityPolicy || "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; frame-src 'self'; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'")}" />`);
391
448
  if (sec.autoEscape !== false)
392
- yield `\t<!-- vesk: auto-escape enabled -->\n`;
449
+ headParts.push('\t<!-- vesk: auto-escape enabled -->');
393
450
  }
394
451
  if (targetComp) {
395
452
  let headHtml = renderHeadHtml(targetComp, ssrProps);
@@ -403,8 +460,11 @@ export function renderPageStream(source, componentName, props = {}, registry = n
403
460
  }
404
461
  }
405
462
  if (headHtml)
406
- yield '\t' + headHtml.split('\n').join('\n\t') + '\n';
463
+ headParts.push('\t' + headHtml.split('\n').join('\n\t'));
407
464
  }
465
+ yield '<!DOCTYPE html>\n<html>\n<head>\n';
466
+ const finalHead = await applyHeadInjects(headParts.join('\n'), { plugins: options.plugins, headExtra: options.headExtra }, { sourcePath: options.sourcePath, url: options.__vesk?.url || undefined });
467
+ yield finalHead + '\n';
408
468
  yield '</head>\n<body>\n<div id="root">\n';
409
469
  globalThis.__vsk_ssr = true;
410
470
  globalThis.__vsk_ssr_token = Math.random().toString(36).slice(2);
package/dist/types.d.ts CHANGED
@@ -16,6 +16,18 @@ export interface FullPageOptions {
16
16
  sourcePath?: string;
17
17
  externalDataScript?: import('@vesk/types').ExternalDataScript;
18
18
  cached?: CompileFileResult;
19
+ /**
20
+ * Active plugins whose `onHead`/`onHtml` hooks run live against this
21
+ * document. Used by dev servers and build/SSG, where plugin objects exist
22
+ * in-process. Prod SSR uses the build-time-baked {@link headExtra} instead.
23
+ */
24
+ plugins?: import('@vesk/types').VeskPlugin[];
25
+ /**
26
+ * Build-time-baked head snippet produced by active `onHead` plugins. Merged
27
+ * into the rendered head (page wins over extras) when no live `plugins` are
28
+ * available — the prod SSR path.
29
+ */
30
+ headExtra?: string;
19
31
  }
20
32
  export declare const VESK_BUILTINS: readonly ["useFetch", "useRouter", "useParams", "usePathname", "useSearchParams", "useNavigate", "useHead", "useTitle", "Form", "Field", "Link", "NavLink", "Outlet", "Image", "Portal", "Experiment", "LoadingIndicator", "useLoadingIndicator", "defineAction", "required", "email", "minLength", "maxLength", "pattern", "custom", "track", "get", "set", "derived", "effect", "batch", "untrack", "cookies", "headers", "locals", "VeskResponse", "VeskRequest", "ServerRequest", "ServerResponse", "redirect", "permanentRedirect", "notFound"];
21
33
  export type VeskBuiltin = typeof VESK_BUILTINS[number];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAIpD,YAAY,EACV,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,UAAU,EACV,OAAO,EACP,eAAe,EACf,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,OAAO,EACP,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,aAAa,EAAE,YAAY,CAAC;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,aAAa,EAAE,kBAAkB,CAAC;IAC9D,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,eAAO,MAAM,aAAa,shBAahB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAIpD,YAAY,EACV,SAAS,EACT,YAAY,EACZ,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,UAAU,EACV,OAAO,EACP,eAAe,EACf,aAAa,EACb,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,SAAS,EACT,iBAAiB,EACjB,kBAAkB,EAClB,OAAO,EACP,QAAQ,EACR,eAAe,EACf,qBAAqB,EACrB,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,aAAa,EAAE,YAAY,CAAC;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,aAAa,EAAE,kBAAkB,CAAC;IAC9D,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,aAAa,EAAE,UAAU,EAAE,CAAC;IAC7C;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,aAAa,shBAahB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vesk/compiler",
3
- "version": "0.2.12",
3
+ "version": "0.2.15",
4
4
  "type": "module",
5
5
  "description": "Vesk compiler — lexer, parser, semantic analysis, IR, codegen",
6
6
  "main": "./dist/index.js",
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "dependencies": {
22
22
  "@sveltejs/acorn-typescript": "^1.0.0",
23
- "@vesk/types": "^0.2.12",
23
+ "@vesk/types": "^0.2.15",
24
24
  "acorn": "^8.15.0",
25
25
  "esrap": "^2.3.0",
26
26
  "is-reference": "^3.0.0",