zengen 0.1.0

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/index.js ADDED
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NavigationGenerator = exports.TemplateEngine = exports.MarkdownConverter = exports.ZenBuilder = void 0;
4
+ var builder_1 = require("./builder");
5
+ Object.defineProperty(exports, "ZenBuilder", { enumerable: true, get: function () { return builder_1.ZenBuilder; } });
6
+ var markdown_1 = require("./markdown");
7
+ Object.defineProperty(exports, "MarkdownConverter", { enumerable: true, get: function () { return markdown_1.MarkdownConverter; } });
8
+ var template_1 = require("./template");
9
+ Object.defineProperty(exports, "TemplateEngine", { enumerable: true, get: function () { return template_1.TemplateEngine; } });
10
+ var navigation_1 = require("./navigation");
11
+ Object.defineProperty(exports, "NavigationGenerator", { enumerable: true, get: function () { return navigation_1.NavigationGenerator; } });
12
+ /**
13
+ * ZEN 文档构建工具
14
+ *
15
+ * 一个极简主义的 Markdown 文档站点生成器
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { ZenBuilder } from 'zengen';
20
+ *
21
+ * const builder = new ZenBuilder();
22
+ * await builder.build({
23
+ * srcDir: './docs',
24
+ * outDir: './dist'
25
+ * });
26
+ * ```
27
+ */
28
+ const builder_2 = require("./builder");
29
+ const markdown_2 = require("./markdown");
30
+ const template_2 = require("./template");
31
+ const navigation_2 = require("./navigation");
32
+ exports.default = {
33
+ Builder: builder_2.ZenBuilder,
34
+ MarkdownConverter: markdown_2.MarkdownConverter,
35
+ TemplateEngine: template_2.TemplateEngine,
36
+ NavigationGenerator: navigation_2.NavigationGenerator
37
+ };
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAAuC;AAA9B,qGAAA,UAAU,OAAA;AACnB,uCAA+C;AAAtC,6GAAA,iBAAiB,OAAA;AAC1B,uCAA4C;AAAnC,0GAAA,cAAc,OAAA;AACvB,2CAAmD;AAA1C,iHAAA,mBAAmB,OAAA;AAU5B;;;;;;;;;;;;;;;GAeG;AACH,uCAAuC;AACvC,yCAA+C;AAC/C,yCAA4C;AAC5C,6CAAmD;AAEnD,kBAAe;IACb,OAAO,EAAE,oBAAU;IACnB,iBAAiB,EAAE,4BAAiB;IACpC,cAAc,EAAE,yBAAc;IAC9B,mBAAmB,EAAE,gCAAmB;CACzC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { FileInfo, MarkdownProcessor } from './types';
2
+ export declare class MarkdownConverter {
3
+ private processors;
4
+ constructor(processors?: MarkdownProcessor[]);
5
+ /**
6
+ * 添加处理器
7
+ */
8
+ addProcessor(processor: MarkdownProcessor): void;
9
+ /**
10
+ * 解析 YAML frontmatter
11
+ */
12
+ private parseFrontmatter;
13
+ /**
14
+ * 从内容中提取标题
15
+ */
16
+ private extractTitle;
17
+ /**
18
+ * 转换 Markdown 文件
19
+ */
20
+ convert(fileInfo: FileInfo): Promise<FileInfo>;
21
+ /**
22
+ * 批量转换文件
23
+ */
24
+ convertFiles(files: FileInfo[]): Promise<FileInfo[]>;
25
+ /**
26
+ * 从文件路径读取并转换
27
+ */
28
+ convertFromPath(filePath: string, baseDir?: string): Promise<FileInfo>;
29
+ /**
30
+ * 从目录读取所有 Markdown 文件并转换
31
+ */
32
+ convertDirectory(dirPath: string): Promise<FileInfo[]>;
33
+ }
34
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AA0BtD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,UAAU,CAA2B;gBAEjC,UAAU,GAAE,iBAAiB,EAAO;IAIhD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI;IAIhD;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAqBxB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgBpB;;OAEG;IACG,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAiCpD;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAiB1D;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,MAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;IAiBhF;;OAEG;IACG,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CA+B7D"}
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.MarkdownConverter = void 0;
40
+ const marked_1 = require("marked");
41
+ const highlight_js_1 = __importDefault(require("highlight.js"));
42
+ const fs = __importStar(require("fs/promises"));
43
+ const path = __importStar(require("path"));
44
+ const yaml = __importStar(require("yaml"));
45
+ // 配置 marked 使用 highlight.js 进行代码高亮
46
+ marked_1.marked.setOptions({
47
+ highlight: function (code, lang) {
48
+ if (lang && highlight_js_1.default.getLanguage(lang)) {
49
+ try {
50
+ return highlight_js_1.default.highlight(code, { language: lang }).value;
51
+ }
52
+ catch (err) {
53
+ console.warn(`Failed to highlight code with language ${lang}:`, err);
54
+ }
55
+ }
56
+ return highlight_js_1.default.highlightAuto(code).value;
57
+ },
58
+ pedantic: false,
59
+ gfm: true,
60
+ breaks: false,
61
+ sanitize: false,
62
+ smartLists: true,
63
+ smartypants: false,
64
+ xhtml: false
65
+ });
66
+ class MarkdownConverter {
67
+ constructor(processors = []) {
68
+ this.processors = [];
69
+ this.processors = processors;
70
+ }
71
+ /**
72
+ * 添加处理器
73
+ */
74
+ addProcessor(processor) {
75
+ this.processors.push(processor);
76
+ }
77
+ /**
78
+ * 解析 YAML frontmatter
79
+ */
80
+ parseFrontmatter(content) {
81
+ const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
82
+ const match = content.match(frontmatterRegex);
83
+ if (!match) {
84
+ return { metadata: {}, content };
85
+ }
86
+ try {
87
+ const metadata = yaml.parse(match[1]) || {};
88
+ const remainingContent = content.slice(match[0].length);
89
+ return { metadata, content: remainingContent };
90
+ }
91
+ catch (error) {
92
+ console.warn('Failed to parse frontmatter:', error);
93
+ return { metadata: {}, content };
94
+ }
95
+ }
96
+ /**
97
+ * 从内容中提取标题
98
+ */
99
+ extractTitle(content) {
100
+ // 查找第一个一级标题
101
+ const h1Match = content.match(/^#\s+(.+)$/m);
102
+ if (h1Match) {
103
+ return h1Match[1].trim();
104
+ }
105
+ // 如果没有一级标题,查找第一个二级标题
106
+ const h2Match = content.match(/^##\s+(.+)$/m);
107
+ if (h2Match) {
108
+ return h2Match[1].trim();
109
+ }
110
+ return 'Untitled';
111
+ }
112
+ /**
113
+ * 转换 Markdown 文件
114
+ */
115
+ async convert(fileInfo) {
116
+ let { content, metadata } = this.parseFrontmatter(fileInfo.content);
117
+ // 应用前置处理器
118
+ for (const processor of this.processors) {
119
+ if (processor.beforeParse) {
120
+ content = await processor.beforeParse(content, fileInfo);
121
+ }
122
+ }
123
+ // 转换 Markdown 为 HTML
124
+ let html = marked_1.marked.parse(content);
125
+ // 应用后置处理器
126
+ for (const processor of this.processors) {
127
+ if (processor.afterParse) {
128
+ html = await processor.afterParse(html, fileInfo);
129
+ }
130
+ }
131
+ // 提取标题(如果 metadata 中没有)
132
+ if (!metadata.title) {
133
+ metadata.title = this.extractTitle(content);
134
+ }
135
+ return {
136
+ ...fileInfo,
137
+ content,
138
+ html,
139
+ metadata
140
+ };
141
+ }
142
+ /**
143
+ * 批量转换文件
144
+ */
145
+ async convertFiles(files) {
146
+ const results = [];
147
+ for (const file of files) {
148
+ try {
149
+ const result = await this.convert(file);
150
+ results.push(result);
151
+ }
152
+ catch (error) {
153
+ console.error(`Failed to convert file ${file.path}:`, error);
154
+ // 即使转换失败,也保留原始文件信息
155
+ results.push(file);
156
+ }
157
+ }
158
+ return results;
159
+ }
160
+ /**
161
+ * 从文件路径读取并转换
162
+ */
163
+ async convertFromPath(filePath, baseDir = '') {
164
+ const content = await fs.readFile(filePath, 'utf-8');
165
+ const relativePath = baseDir ? path.relative(baseDir, filePath) : filePath;
166
+ const ext = path.extname(filePath);
167
+ const name = path.basename(filePath, ext);
168
+ const fileInfo = {
169
+ path: filePath,
170
+ relativePath,
171
+ name,
172
+ ext,
173
+ content
174
+ };
175
+ return this.convert(fileInfo);
176
+ }
177
+ /**
178
+ * 从目录读取所有 Markdown 文件并转换
179
+ */
180
+ async convertDirectory(dirPath) {
181
+ const files = [];
182
+ async function scanDirectory(currentPath) {
183
+ const entries = await fs.readdir(currentPath, { withFileTypes: true });
184
+ for (const entry of entries) {
185
+ const fullPath = path.join(currentPath, entry.name);
186
+ if (entry.isDirectory()) {
187
+ await scanDirectory(fullPath);
188
+ }
189
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
190
+ const content = await fs.readFile(fullPath, 'utf-8');
191
+ const relativePath = path.relative(dirPath, fullPath);
192
+ const ext = path.extname(entry.name);
193
+ const name = path.basename(entry.name, ext);
194
+ files.push({
195
+ path: fullPath,
196
+ relativePath,
197
+ name,
198
+ ext,
199
+ content
200
+ });
201
+ }
202
+ }
203
+ }
204
+ await scanDirectory(dirPath);
205
+ return this.convertFiles(files);
206
+ }
207
+ }
208
+ exports.MarkdownConverter = MarkdownConverter;
209
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ import { NavigationItem, FileInfo } from './types';
2
+ export declare class NavigationGenerator {
3
+ /**
4
+ * 从文件信息生成导航结构
5
+ */
6
+ generate(files: FileInfo[]): NavigationItem[];
7
+ /**
8
+ * 将文件添加到导航树中
9
+ */
10
+ private addFileToNavigation;
11
+ /**
12
+ * 格式化标题(将连字符/下划线转换为空格并首字母大写)
13
+ */
14
+ private formatTitle;
15
+ /**
16
+ * 生成扁平化导航(所有页面在同一层级)
17
+ */
18
+ generateFlat(files: FileInfo[]): NavigationItem[];
19
+ /**
20
+ * 生成面包屑导航
21
+ */
22
+ generateBreadcrumbs(filePath: string, navigation: NavigationItem[]): NavigationItem[];
23
+ /**
24
+ * 在导航树中查找项目
25
+ */
26
+ private findNavigationItem;
27
+ /**
28
+ * 生成站点地图 XML
29
+ */
30
+ generateSitemap(files: FileInfo[], baseUrl?: string): string;
31
+ /**
32
+ * 生成 JSON 格式的导航数据(用于前端动态加载)
33
+ */
34
+ generateJsonNavigation(files: FileInfo[]): string;
35
+ }
36
+ //# sourceMappingURL=navigation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGnD,qBAAa,mBAAmB;IAC9B;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,cAAc,EAAE;IAgB7C;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoD3B;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,cAAc,EAAE;IAYjD;;OAEG;IACH,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE;IA4BrF;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAiB1B;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,GAAE,MAA8B,GAAG,MAAM;IAmBnF;;OAEG;IACH,sBAAsB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM;CAIlD"}
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NavigationGenerator = void 0;
4
+ class NavigationGenerator {
5
+ /**
6
+ * 从文件信息生成导航结构
7
+ */
8
+ generate(files) {
9
+ // 按路径排序
10
+ const sortedFiles = [...files].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
11
+ // 构建树形结构
12
+ const root = [];
13
+ for (const file of sortedFiles) {
14
+ this.addFileToNavigation(root, file);
15
+ }
16
+ return root;
17
+ }
18
+ /**
19
+ * 将文件添加到导航树中
20
+ */
21
+ addFileToNavigation(navigation, file) {
22
+ const parts = file.relativePath.split('/');
23
+ let currentLevel = navigation;
24
+ for (let i = 0; i < parts.length; i++) {
25
+ const part = parts[i];
26
+ const isLastPart = i === parts.length - 1;
27
+ const isMarkdownFile = part.endsWith('.md');
28
+ // 如果是 Markdown 文件,移除扩展名
29
+ const displayName = isMarkdownFile ? part.replace(/\.md$/, '') : part;
30
+ // 生成标题(使用文件名或 metadata 中的标题)
31
+ const title = file.metadata?.title || this.formatTitle(displayName);
32
+ // 生成路径
33
+ const itemPath = isMarkdownFile
34
+ ? `/${file.relativePath.replace(/\.md$/, '.html')}`
35
+ : `/${parts.slice(0, i + 1).join('/')}`;
36
+ if (isLastPart) {
37
+ // 添加文件节点
38
+ currentLevel.push({
39
+ title,
40
+ path: itemPath
41
+ });
42
+ }
43
+ else {
44
+ // 查找或创建目录节点
45
+ let dirItem = currentLevel.find(item => item.title === displayName && !item.path.endsWith('.html'));
46
+ if (!dirItem) {
47
+ dirItem = {
48
+ title: this.formatTitle(displayName),
49
+ path: itemPath,
50
+ children: []
51
+ };
52
+ currentLevel.push(dirItem);
53
+ }
54
+ // 确保 children 存在
55
+ if (!dirItem.children) {
56
+ dirItem.children = [];
57
+ }
58
+ // 进入下一层
59
+ currentLevel = dirItem.children;
60
+ }
61
+ }
62
+ }
63
+ /**
64
+ * 格式化标题(将连字符/下划线转换为空格并首字母大写)
65
+ */
66
+ formatTitle(name) {
67
+ // 移除扩展名
68
+ const baseName = name.replace(/\.[^/.]+$/, '');
69
+ // 将连字符、下划线、点替换为空格
70
+ const withSpaces = baseName.replace(/[-_.]/g, ' ');
71
+ // 首字母大写每个单词
72
+ return withSpaces
73
+ .split(' ')
74
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
75
+ .join(' ');
76
+ }
77
+ /**
78
+ * 生成扁平化导航(所有页面在同一层级)
79
+ */
80
+ generateFlat(files) {
81
+ return files.map(file => {
82
+ const title = file.metadata?.title || this.formatTitle(file.name);
83
+ const itemPath = `/${file.relativePath.replace(/\.md$/, '.html')}`;
84
+ return {
85
+ title,
86
+ path: itemPath
87
+ };
88
+ }).sort((a, b) => a.title.localeCompare(b.title));
89
+ }
90
+ /**
91
+ * 生成面包屑导航
92
+ */
93
+ generateBreadcrumbs(filePath, navigation) {
94
+ const parts = filePath.split('/').filter(part => part);
95
+ const breadcrumbs = [];
96
+ let currentNav = navigation;
97
+ for (let i = 0; i < parts.length; i++) {
98
+ const part = parts[i];
99
+ const isLast = i === parts.length - 1;
100
+ const searchPath = `/${parts.slice(0, i + 1).join('/')}`;
101
+ // 在当前层级查找匹配的导航项
102
+ const foundItem = this.findNavigationItem(currentNav, searchPath);
103
+ if (foundItem) {
104
+ breadcrumbs.push({
105
+ title: foundItem.title,
106
+ path: foundItem.path
107
+ });
108
+ if (foundItem.children && !isLast) {
109
+ currentNav = foundItem.children;
110
+ }
111
+ }
112
+ }
113
+ return breadcrumbs;
114
+ }
115
+ /**
116
+ * 在导航树中查找项目
117
+ */
118
+ findNavigationItem(navigation, searchPath) {
119
+ for (const item of navigation) {
120
+ if (item.path === searchPath) {
121
+ return item;
122
+ }
123
+ if (item.children) {
124
+ const found = this.findNavigationItem(item.children, searchPath);
125
+ if (found) {
126
+ return found;
127
+ }
128
+ }
129
+ }
130
+ return null;
131
+ }
132
+ /**
133
+ * 生成站点地图 XML
134
+ */
135
+ generateSitemap(files, baseUrl = 'https://example.com') {
136
+ const urls = files.map(file => {
137
+ const path = `/${file.relativePath.replace(/\.md$/, '.html')}`;
138
+ const lastmod = file.metadata?.last_modified || file.metadata?.date || new Date().toISOString().split('T')[0];
139
+ return ` <url>
140
+ <loc>${baseUrl}${path}</loc>
141
+ <lastmod>${lastmod}</lastmod>
142
+ <changefreq>weekly</changefreq>
143
+ <priority>0.8</priority>
144
+ </url>`;
145
+ }).join('\n');
146
+ return `<?xml version="1.0" encoding="UTF-8"?>
147
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
148
+ ${urls}
149
+ </urlset>`;
150
+ }
151
+ /**
152
+ * 生成 JSON 格式的导航数据(用于前端动态加载)
153
+ */
154
+ generateJsonNavigation(files) {
155
+ const navigation = this.generate(files);
156
+ return JSON.stringify(navigation, null, 2);
157
+ }
158
+ }
159
+ exports.NavigationGenerator = NavigationGenerator;
160
+ //# sourceMappingURL=navigation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../src/navigation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { TemplateData, NavigationItem, FileInfo } from './types';
2
+ export declare class TemplateEngine {
3
+ private defaultTemplate;
4
+ /**
5
+ * 生成导航 HTML
6
+ */
7
+ private generateNavigationHtml;
8
+ /**
9
+ * 简单的模板变量替换
10
+ */
11
+ private renderTemplate;
12
+ /**
13
+ * 渲染模板
14
+ */
15
+ render(data: TemplateData, templatePath?: string): Promise<string>;
16
+ /**
17
+ * 从文件信息生成模板数据
18
+ */
19
+ generateTemplateData(fileInfo: FileInfo, navigation: NavigationItem[]): TemplateData;
20
+ /**
21
+ * 生成输出文件路径
22
+ */
23
+ getOutputPath(fileInfo: FileInfo, outDir: string): string;
24
+ /**
25
+ * 保存渲染结果到文件
26
+ */
27
+ saveToFile(html: string, outputPath: string): Promise<void>;
28
+ }
29
+ //# sourceMappingURL=template.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAIjE,qBAAa,cAAc;IACzB,OAAO,CAAC,eAAe,CA6QhB;IAEP;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAqB9B;;OAEG;IACH,OAAO,CAAC,cAAc;IAiCtB;;OAEG;IACG,MAAM,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAcxE;;OAEG;IACH,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,YAAY;IAUpF;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAMzD;;OAEG;IACG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAQlE"}