@constela/start 1.3.5 → 1.4.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.
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  generateHydrationScript,
3
+ generateMetaTags,
3
4
  renderPage,
4
5
  wrapHtml
5
- } from "./chunk-CYMS3K6V.js";
6
+ } from "./chunk-XAC4ETQU.js";
6
7
 
7
8
  // src/router/file-router.ts
8
9
  import fg from "fast-glob";
@@ -1933,9 +1934,11 @@ var JsonPageLoader = class {
1933
1934
  if (this.cache.has(pagePath)) {
1934
1935
  return this.cache.get(pagePath);
1935
1936
  }
1936
- const pageInfo = await loadJsonPage(this.projectRoot, pagePath, {
1937
- routesDir: this.routesDir
1938
- });
1937
+ const options = {};
1938
+ if (this.routesDir !== void 0) {
1939
+ options.routesDir = this.routesDir;
1940
+ }
1941
+ const pageInfo = await loadJsonPage(this.projectRoot, pagePath, options);
1939
1942
  this.cache.set(pagePath, pageInfo);
1940
1943
  return pageInfo;
1941
1944
  }
@@ -2172,7 +2175,13 @@ async function createDevServer(options = {}) {
2172
2175
  path: pathname
2173
2176
  };
2174
2177
  const hydrationScript = generateHydrationScript(composedProgram, widgets, routeContext);
2178
+ const metaTags = generateMetaTags(composedProgram.route, {
2179
+ params: match.params,
2180
+ query: Object.fromEntries(url.searchParams.entries()),
2181
+ path: pathname
2182
+ });
2175
2183
  const cssHead = css ? (Array.isArray(css) ? css : [css]).map((p) => `<link rel="stylesheet" href="/${p}">`).join("\n") : "";
2184
+ const head = [metaTags, cssHead].filter(Boolean).join("\n");
2176
2185
  const themeState = composedProgram.state?.["theme"];
2177
2186
  const initialTheme = themeState?.initial;
2178
2187
  const importMap = {
@@ -2182,7 +2191,7 @@ async function createDevServer(options = {}) {
2182
2191
  "marked": "/node_modules/marked/lib/marked.esm.js",
2183
2192
  "monaco-editor": "/node_modules/monaco-editor/esm/vs/editor/editor.api.js"
2184
2193
  };
2185
- const html = wrapHtml(content, hydrationScript, cssHead, {
2194
+ const html = wrapHtml(content, hydrationScript, head || void 0, {
2186
2195
  ...initialTheme ? {
2187
2196
  theme: initialTheme,
2188
2197
  defaultTheme: initialTheme,
@@ -136,9 +136,65 @@ ${processedScript}
136
136
  </body>
137
137
  </html>`;
138
138
  }
139
+ function escapeHtmlForMeta(str) {
140
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
141
+ }
142
+ function evaluateMetaExpression(expr, ctx) {
143
+ switch (expr.expr) {
144
+ case "lit":
145
+ return String(expr.value);
146
+ case "route":
147
+ if (expr.source === "param") {
148
+ return ctx.params[expr.name] || "";
149
+ } else if (expr.source === "query") {
150
+ return ctx.query[expr.name] || "";
151
+ } else if (expr.source === "path") {
152
+ return ctx.path;
153
+ }
154
+ return "";
155
+ case "bin":
156
+ if (expr.op === "+") {
157
+ return evaluateMetaExpression(expr.left, ctx) + evaluateMetaExpression(expr.right, ctx);
158
+ }
159
+ return "";
160
+ case "concat":
161
+ return expr.items.map((item) => evaluateMetaExpression(item, ctx)).join("");
162
+ default:
163
+ return "";
164
+ }
165
+ }
166
+ function generateMetaTags(route, ctx) {
167
+ if (!route) {
168
+ return "";
169
+ }
170
+ const tags = [];
171
+ if (route.title) {
172
+ const titleValue = evaluateMetaExpression(route.title, ctx);
173
+ if (titleValue) {
174
+ tags.push(`<title>${escapeHtmlForMeta(titleValue)}</title>`);
175
+ }
176
+ }
177
+ if (route.meta) {
178
+ for (const [key, expr] of Object.entries(route.meta)) {
179
+ const value = evaluateMetaExpression(expr, ctx);
180
+ if (!value) {
181
+ continue;
182
+ }
183
+ const escapedValue = escapeHtmlForMeta(value);
184
+ if (key.startsWith("og:") || key.startsWith("twitter:")) {
185
+ tags.push(`<meta property="${key}" content="${escapedValue}">`);
186
+ } else {
187
+ tags.push(`<meta name="${key}" content="${escapedValue}">`);
188
+ }
189
+ }
190
+ }
191
+ return tags.join("\n");
192
+ }
139
193
 
140
194
  export {
141
195
  renderPage,
142
196
  generateHydrationScript,
143
- wrapHtml
197
+ wrapHtml,
198
+ evaluateMetaExpression,
199
+ generateMetaTags
144
200
  };
package/dist/cli/index.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  hyperlink,
5
5
  loadConfig,
6
6
  resolveConfig
7
- } from "../chunk-QEXDD2F2.js";
8
- import "../chunk-CYMS3K6V.js";
7
+ } from "../chunk-UVD2DNVT.js";
8
+ import "../chunk-XAC4ETQU.js";
9
9
 
10
10
  // src/cli/index.ts
11
11
  import { Command } from "commander";
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { CompiledProgram, CompiledNode } from '@constela/compiler';
2
2
  import { LayoutProgram, Program, StaticPathsDefinition, DataSource } from '@constela/core';
3
+ export { MetaContext, evaluateMetaExpression, generateMetaTags } from './runtime/entry-server.js';
3
4
 
4
5
  /**
5
6
  * Scanned route from file system
package/dist/index.js CHANGED
@@ -24,12 +24,14 @@ import {
24
24
  transformCsv,
25
25
  transformMdx,
26
26
  transformYaml
27
- } from "./chunk-QEXDD2F2.js";
27
+ } from "./chunk-UVD2DNVT.js";
28
28
  import {
29
+ evaluateMetaExpression,
29
30
  generateHydrationScript,
31
+ generateMetaTags,
30
32
  renderPage,
31
33
  wrapHtml
32
- } from "./chunk-CYMS3K6V.js";
34
+ } from "./chunk-XAC4ETQU.js";
33
35
 
34
36
  // src/build/ssg.ts
35
37
  import { mkdir, writeFile } from "fs/promises";
@@ -113,6 +115,11 @@ async function generateSinglePage(pattern, outDir, program, params = {}) {
113
115
  path: pattern
114
116
  };
115
117
  const hydrationScript = generateHydrationScript(program, void 0, routeContext);
118
+ const metaTags = generateMetaTags(program.route, {
119
+ params,
120
+ query: {},
121
+ path: pattern
122
+ });
116
123
  const wrapOptions = {};
117
124
  const themeState = program.state?.["theme"];
118
125
  if (themeState?.initial) {
@@ -122,7 +129,7 @@ async function generateSinglePage(pattern, outDir, program, params = {}) {
122
129
  const html = wrapHtml(
123
130
  content,
124
131
  hydrationScript,
125
- void 0,
132
+ metaTags || void 0,
126
133
  Object.keys(wrapOptions).length > 0 ? wrapOptions : void 0
127
134
  );
128
135
  await writeFile(outputPath, html, "utf-8");
@@ -344,7 +351,9 @@ export {
344
351
  createAdapter,
345
352
  createDevServer,
346
353
  createMiddlewareChain,
354
+ evaluateMetaExpression,
347
355
  filePathToPattern,
356
+ generateMetaTags,
348
357
  generateStaticPages,
349
358
  generateStaticPaths,
350
359
  getMimeType,
@@ -1,4 +1,4 @@
1
- import { CompiledProgram } from '@constela/compiler';
1
+ import { CompiledRouteDefinition, CompiledExpression, CompiledProgram } from '@constela/compiler';
2
2
 
3
3
  /**
4
4
  * Server-side entry point for Constela applications
@@ -76,5 +76,21 @@ declare function generateHydrationScript(program: CompiledProgram, widgets?: Wid
76
76
  * @returns Complete HTML document string
77
77
  */
78
78
  declare function wrapHtml(content: string, hydrationScript: string, head?: string, options?: WrapHtmlOptions): string;
79
+ /**
80
+ * Context for evaluating meta tag expressions
81
+ */
82
+ interface MetaContext {
83
+ params: Record<string, string>;
84
+ query: Record<string, string>;
85
+ path: string;
86
+ }
87
+ /**
88
+ * Evaluates a compiled expression for meta tag values.
89
+ */
90
+ declare function evaluateMetaExpression(expr: CompiledExpression, ctx: MetaContext): string;
91
+ /**
92
+ * Generates HTML meta tags from route definition.
93
+ */
94
+ declare function generateMetaTags(route: CompiledRouteDefinition | undefined, ctx: MetaContext): string;
79
95
 
80
- export { type HydrationRouteContext, type SSRContext, type WidgetConfig, type WrapHtmlOptions, generateHydrationScript, renderPage, wrapHtml };
96
+ export { type HydrationRouteContext, type MetaContext, type SSRContext, type WidgetConfig, type WrapHtmlOptions, evaluateMetaExpression, generateHydrationScript, generateMetaTags, renderPage, wrapHtml };
@@ -1,10 +1,14 @@
1
1
  import {
2
+ evaluateMetaExpression,
2
3
  generateHydrationScript,
4
+ generateMetaTags,
3
5
  renderPage,
4
6
  wrapHtml
5
- } from "../chunk-CYMS3K6V.js";
7
+ } from "../chunk-XAC4ETQU.js";
6
8
  export {
9
+ evaluateMetaExpression,
7
10
  generateHydrationScript,
11
+ generateMetaTags,
8
12
  renderPage,
9
13
  wrapHtml
10
14
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/start",
3
- "version": "1.3.5",
3
+ "version": "1.4.1",
4
4
  "description": "Meta-framework for Constela applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,11 +43,11 @@
43
43
  "postcss": "^8.5.0",
44
44
  "@tailwindcss/postcss": "^4.0.0",
45
45
  "tailwindcss": "^4.0.0",
46
- "@constela/core": "0.10.0",
47
46
  "@constela/compiler": "0.10.0",
47
+ "@constela/server": "6.0.0",
48
+ "@constela/core": "0.10.0",
48
49
  "@constela/router": "11.0.0",
49
- "@constela/runtime": "0.13.0",
50
- "@constela/server": "6.0.0"
50
+ "@constela/runtime": "0.13.0"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/mdast": "^4.0.4",