meno-core 1.0.38 → 1.0.39
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/build-astro.ts +914 -0
- package/dist/build-static.js +2 -2
- package/dist/chunks/{chunk-UR7L5UZ3.js → chunk-HNAS6BSS.js} +2 -2
- package/dist/chunks/{chunk-EUCAKI5U.js → chunk-W6HDII4T.js} +8 -1
- package/dist/chunks/{chunk-EUCAKI5U.js.map → chunk-W6HDII4T.js.map} +2 -2
- package/dist/chunks/{chunk-JACS3C25.js → chunk-WK5XLASY.js} +2 -2
- package/dist/entries/server-router.js +2 -2
- package/dist/lib/client/index.js +5 -3
- package/dist/lib/client/index.js.map +2 -2
- package/dist/lib/server/index.js +1840 -5
- package/dist/lib/server/index.js.map +4 -4
- package/dist/lib/shared/index.js +5 -3
- package/dist/lib/shared/index.js.map +2 -2
- package/lib/client/theme.ts +4 -1
- package/lib/server/astro/componentEmitter.ts +208 -0
- package/lib/server/astro/cssCollector.ts +147 -0
- package/lib/server/astro/index.ts +5 -0
- package/lib/server/astro/nodeToAstro.ts +771 -0
- package/lib/server/astro/pageEmitter.ts +190 -0
- package/lib/server/astro/tailwindMapper.ts +547 -0
- package/lib/server/index.ts +3 -0
- package/lib/server/ssr/htmlGenerator.ts +3 -0
- package/lib/server/ssr/ssrRenderer.test.ts +8 -4
- package/lib/server/ssr/ssrRenderer.ts +1 -3
- package/lib/shared/themeDefaults.test.ts +1 -1
- package/lib/shared/themeDefaults.ts +4 -1
- package/package.json +1 -1
- /package/dist/chunks/{chunk-UR7L5UZ3.js.map → chunk-HNAS6BSS.js.map} +0 -0
- /package/dist/chunks/{chunk-JACS3C25.js.map → chunk-WK5XLASY.js.map} +0 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page File Generator
|
|
3
|
+
* Generates .astro page files that import and compose components
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { JSONPage, ComponentDefinition } from '../../shared/types';
|
|
7
|
+
import type { BreakpointConfig } from '../../shared/breakpoints';
|
|
8
|
+
import { DEFAULT_BREAKPOINTS } from '../../shared/breakpoints';
|
|
9
|
+
import { nodeToAstro, type AstroEmitContext } from './nodeToAstro';
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Types
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
export interface PageEmitOptions {
|
|
16
|
+
/** Page data */
|
|
17
|
+
pageData: JSONPage;
|
|
18
|
+
/** All global components */
|
|
19
|
+
globalComponents: Record<string, ComponentDefinition>;
|
|
20
|
+
/** Page title */
|
|
21
|
+
title: string;
|
|
22
|
+
/** Page meta HTML */
|
|
23
|
+
meta: string;
|
|
24
|
+
/** Locale */
|
|
25
|
+
locale: string;
|
|
26
|
+
/** Default theme */
|
|
27
|
+
theme: string;
|
|
28
|
+
/** Font preloads HTML */
|
|
29
|
+
fontPreloads: string;
|
|
30
|
+
/** Library tags */
|
|
31
|
+
libraryTags: { headCSS?: string; headJS?: string; bodyEndJS?: string };
|
|
32
|
+
/** Script paths */
|
|
33
|
+
scriptPaths: string[];
|
|
34
|
+
/** Import path to BaseLayout */
|
|
35
|
+
layoutImportPath: string;
|
|
36
|
+
/** File depth relative to src/pages */
|
|
37
|
+
fileDepth: number;
|
|
38
|
+
/** SSR HTML fallbacks: node path → rendered HTML (for ListNode, LocaleListNode) */
|
|
39
|
+
ssrFallbacks: Map<string, string>;
|
|
40
|
+
/** Page name (without extension) */
|
|
41
|
+
pageName: string;
|
|
42
|
+
/** Breakpoint config for responsive Tailwind classes */
|
|
43
|
+
breakpoints?: BreakpointConfig;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Helpers
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
function escapeTemplateLiteral(s: string): string {
|
|
51
|
+
return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function escapeJSX(s: string): string {
|
|
55
|
+
return s.replace(/&/g, '&').replace(/"/g, '"');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Compute relative import path from page to components directory
|
|
60
|
+
*/
|
|
61
|
+
function componentImportPath(fileDepth: number, componentName: string): string {
|
|
62
|
+
// fileDepth 0 = src/pages/index.astro → ../components/X.astro
|
|
63
|
+
// fileDepth 1 = src/pages/en/index.astro → ../../components/X.astro
|
|
64
|
+
const ups = '../'.repeat(fileDepth + 1);
|
|
65
|
+
return `${ups}components/${componentName}.astro`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Main emitter
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Generate a page .astro file from page data with component imports
|
|
74
|
+
*/
|
|
75
|
+
export function emitAstroPage(options: PageEmitOptions): string {
|
|
76
|
+
const {
|
|
77
|
+
pageData,
|
|
78
|
+
globalComponents,
|
|
79
|
+
title,
|
|
80
|
+
meta,
|
|
81
|
+
locale,
|
|
82
|
+
theme,
|
|
83
|
+
fontPreloads,
|
|
84
|
+
libraryTags,
|
|
85
|
+
scriptPaths,
|
|
86
|
+
layoutImportPath,
|
|
87
|
+
fileDepth,
|
|
88
|
+
ssrFallbacks,
|
|
89
|
+
pageName,
|
|
90
|
+
breakpoints: breakpointsOpt,
|
|
91
|
+
} = options;
|
|
92
|
+
|
|
93
|
+
const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
|
|
94
|
+
|
|
95
|
+
const root = pageData.root;
|
|
96
|
+
if (!root) {
|
|
97
|
+
// Empty page - just layout wrapper
|
|
98
|
+
return buildEmptyPage(layoutImportPath, title, meta, locale, theme, fontPreloads, libraryTags, scriptPaths);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Build the Astro emit context
|
|
102
|
+
const ctx: AstroEmitContext = {
|
|
103
|
+
imports: new Set<string>(),
|
|
104
|
+
isComponentDef: false,
|
|
105
|
+
componentProps: {},
|
|
106
|
+
globalComponents,
|
|
107
|
+
indent: 1, // inside BaseLayout
|
|
108
|
+
ssrFallbacks,
|
|
109
|
+
elementPath: [0],
|
|
110
|
+
fileType: 'page',
|
|
111
|
+
fileName: pageName,
|
|
112
|
+
breakpoints,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Emit the template body
|
|
116
|
+
const templateBody = nodeToAstro(root, ctx);
|
|
117
|
+
|
|
118
|
+
// Build frontmatter with imports
|
|
119
|
+
const importLines: string[] = [];
|
|
120
|
+
importLines.push(`import BaseLayout from '${layoutImportPath}';`);
|
|
121
|
+
|
|
122
|
+
// Sort component imports alphabetically
|
|
123
|
+
const componentImports = Array.from(ctx.imports).sort();
|
|
124
|
+
for (const comp of componentImports) {
|
|
125
|
+
const path = componentImportPath(fileDepth, comp);
|
|
126
|
+
importLines.push(`import ${comp} from '${path}';`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Build script paths array
|
|
130
|
+
const scriptsArrayLiteral = scriptPaths.length > 0
|
|
131
|
+
? `[${scriptPaths.map((s) => `"${s}"`).join(', ')}]`
|
|
132
|
+
: '[]';
|
|
133
|
+
|
|
134
|
+
// Build library tags literal
|
|
135
|
+
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral(libraryTags.headCSS || '')}\`, headJS: \`${escapeTemplateLiteral(libraryTags.headJS || '')}\`, bodyEndJS: \`${escapeTemplateLiteral(libraryTags.bodyEndJS || '')}\` }`;
|
|
136
|
+
|
|
137
|
+
const escapedMeta = escapeTemplateLiteral(meta);
|
|
138
|
+
const escapedFontPreloads = escapeTemplateLiteral(fontPreloads);
|
|
139
|
+
|
|
140
|
+
return `---
|
|
141
|
+
${importLines.join('\n')}
|
|
142
|
+
---
|
|
143
|
+
<BaseLayout
|
|
144
|
+
title="${escapeJSX(title)}"
|
|
145
|
+
meta={\`${escapedMeta}\`}
|
|
146
|
+
scripts={${scriptsArrayLiteral}}
|
|
147
|
+
locale="${locale}"
|
|
148
|
+
theme="${theme}"
|
|
149
|
+
fontPreloads={\`${escapedFontPreloads}\`}
|
|
150
|
+
libraryTags={${libraryTagsLiteral}}
|
|
151
|
+
>
|
|
152
|
+
${templateBody}</BaseLayout>
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Build an empty page with just the layout wrapper
|
|
158
|
+
*/
|
|
159
|
+
function buildEmptyPage(
|
|
160
|
+
layoutImport: string,
|
|
161
|
+
title: string,
|
|
162
|
+
meta: string,
|
|
163
|
+
locale: string,
|
|
164
|
+
theme: string,
|
|
165
|
+
fontPreloads: string,
|
|
166
|
+
libraryTags: { headCSS?: string; headJS?: string; bodyEndJS?: string },
|
|
167
|
+
scriptPaths: string[]
|
|
168
|
+
): string {
|
|
169
|
+
const escapedMeta = escapeTemplateLiteral(meta);
|
|
170
|
+
const escapedFontPreloads = escapeTemplateLiteral(fontPreloads);
|
|
171
|
+
const scriptsArrayLiteral = scriptPaths.length > 0
|
|
172
|
+
? `[${scriptPaths.map((s) => `"${s}"`).join(', ')}]`
|
|
173
|
+
: '[]';
|
|
174
|
+
const libraryTagsLiteral = `{ headCSS: \`${escapeTemplateLiteral(libraryTags.headCSS || '')}\`, headJS: \`${escapeTemplateLiteral(libraryTags.headJS || '')}\`, bodyEndJS: \`${escapeTemplateLiteral(libraryTags.bodyEndJS || '')}\` }`;
|
|
175
|
+
|
|
176
|
+
return `---
|
|
177
|
+
import BaseLayout from '${layoutImport}';
|
|
178
|
+
---
|
|
179
|
+
<BaseLayout
|
|
180
|
+
title="${escapeJSX(title)}"
|
|
181
|
+
meta={\`${escapedMeta}\`}
|
|
182
|
+
scripts={${scriptsArrayLiteral}}
|
|
183
|
+
locale="${locale}"
|
|
184
|
+
theme="${theme}"
|
|
185
|
+
fontPreloads={\`${escapedFontPreloads}\`}
|
|
186
|
+
libraryTags={${libraryTagsLiteral}}
|
|
187
|
+
>
|
|
188
|
+
</BaseLayout>
|
|
189
|
+
`;
|
|
190
|
+
}
|