@zphhpzzph/vue-route-gen 1.1.0 → 3.0.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/README.md CHANGED
@@ -2,303 +2,350 @@
2
2
 
3
3
  > [English](./README_en.md) | 简体中文
4
4
 
5
- Vue 3 基于文件系统的路由生成器,为 Vue Router 提供完整的类型推断支持。
5
+ Vue 3 基于文件系统的路由生成器,为 Vue Router 提供完整的类型推断支持。类似 Nuxt 的路由系统,但更轻量。
6
6
 
7
- ## 特性
7
+ ## 特性
8
8
 
9
- - 从文件结构自动发现路由
10
- - 支持布局文件 (`layout.vue` `layout/index.vue`)
11
- - 动态路由参数 (`$param` `[param]`)
12
- - 缓存机制,快速重建
13
- - TypeScript 支持并生成完整类型
14
- - **类型安全的路由 Hooks**(`useRoute` 和 `useRouter` 提供完整类型推断)
15
- - **自动从动态路由提取参数类型**
9
+ - 📁 **自动路由生成** - 基于 `pages/` 目录结构自动生成路由
10
+ - 🔒 **类型安全** - 路由跳转和参数���取都有完整的 TypeScript 类型检查
11
+ - 🎨 **完整路由配置** - 支持所有 Vue Router 配置(`<route>` 块或 `defineRoute()` 宏)
12
+ - 📦 **开箱即用** - 5 分钟即可完成配置
16
13
 
17
- ## 安装
14
+ ## 📦 快速开始
15
+
16
+ ### 1. 安装
18
17
 
19
18
  ```bash
20
- npm install @zphhpzzph/vue-route-gen
21
- # 或
22
19
  pnpm install @zphhpzzph/vue-route-gen
23
- # 或
24
- yarn add @zphhpzzph/vue-route-gen
25
20
  ```
26
21
 
27
- ## 使用方法
28
-
29
- ### CLI
22
+ ### 2. 配置 Vite
30
23
 
31
- ```bash
32
- vue-route-gen
33
- ```
34
-
35
- ### 编程方式
24
+ 在 `vite.config.ts` 中添加插件:
36
25
 
37
26
  ```typescript
38
- import { generateRoutes } from '@zphhpzzph/vue-route-gen';
39
-
40
- // 使用默认选项生成路由
41
- generateRoutes();
42
-
43
- // 或指定自定义目录
44
- generateRoutes({
45
- pagesDir: './src/pages',
46
- outFile: './src/router/route.gen.ts'
27
+ import { defineConfig } from 'vite';
28
+ import vue from '@vitejs/plugin-vue';
29
+ import { routeBlockPlugin, routeGenPlugin } from '@zphhpzzph/vue-route-gen/vite';
30
+
31
+ export default defineConfig({
32
+ plugins: [
33
+ routeBlockPlugin(), // 处理 <route> 自定义块
34
+ routeGenPlugin(), // 自动生成路由
35
+ vue(),
36
+ ],
47
37
  });
48
38
  ```
49
39
 
50
- ## 文件结构
40
+ ### 3. 创建页面文件
41
+
42
+ 在 `src/pages/` 目录下创建 `.vue` 文件:
51
43
 
52
44
  ```
53
45
  src/pages/
54
- ├── layout.vue # 根布局
55
- ├── index.vue # 首页 (/)
56
- ├── about.vue # 关于页面 (/about)
57
- ├── users/
58
- │ ├── layout.vue # 用户布局 (/users)
59
- │ ├── index.vue # 用户列表 (/users)
60
- │ └── [id].vue # 用户详情 (/users/:id)
61
- └── $slug.vue # 通配路由 (/:slug)
46
+ ├── index.vue # 首页 → /
47
+ ├── about.vue # 关于页 /about
48
+ └── users/
49
+ ├── index.vue # 用户列表 → /users
50
+ └── [id].vue # 用户详情 /users/:id
62
51
  ```
63
52
 
64
- ## 配置选项
65
-
66
- ### 选项
53
+ ### 4. 配置路由
67
54
 
68
- - `pagesDir`: 页面目录路径(默认:`src/pages`)
69
- - `outFile`: 输出文件路径(默认:`src/router/route.gen.ts`)
55
+ `src/router/index.ts` 中使用生成的路由:
70
56
 
71
- ### 自动排除的目录
72
-
73
- 以下目录会被自动排除:
74
- - `components`
75
- - `hooks`
76
- - `services`
77
- - `types`
78
- - `constants`
79
- - `utils`
57
+ ```typescript
58
+ import { createRouter } from 'vue-router';
59
+ import { routes } from './route.gen';
80
60
 
81
- ## 生成内容
61
+ export const router = createRouter({
62
+ routes,
63
+ // ... 其他配置
64
+ });
65
+ ```
82
66
 
83
- 生成器会创建:
67
+ **就这么简单!** 路由会自动生成并保持更新。
84
68
 
85
- 1. `ROUTE_NAME` - 路由名称常量
86
- 2. `ROUTE_PATH` - 路由路径常量
87
- 3. `ROUTE_PATH_BY_NAME` - 按名称查找路径
88
- 4. `RouteParams` - 每个路由的参数类型接口
89
- 5. `RouteParamsByName<T>` - 根据路由名称获取参数类型的工具类型
90
- 6. `routes` - Vue Router 路由记录数组
91
- 7. `useRoute()` - 类型安全的路由访问 Hook,提供参数类型推断
92
- 8. `useRouter()` - 类型安全的路由导航 Hook,提供参数验证
69
+ ## 🚀 常见用法
93
70
 
94
- ## 类型安全的路由
71
+ ### 路由跳转(类型安全)
95
72
 
96
- ### 自动生成的参数类型
73
+ ```vue
74
+ <script setup lang="ts">
75
+ import { useRouter, ROUTE_NAME } from '@/router/route.gen';
97
76
 
98
- 对于 `/users/[id].vue` 这样的路由,生成器会自动提取 `id` 参数:
77
+ const router = useRouter();
99
78
 
100
- ```typescript
101
- // route.gen.ts 中生成
102
- export interface RouteParams {
103
- 'users-id': {
104
- id: string;
105
- };
106
- // ... 其他路由
79
+ // 跳转到用户详情页
80
+ function goToUser(userId: string) {
81
+ router.push({
82
+ name: ROUTE_NAME.USERS_ID,
83
+ params: { id: userId } // ✅ TypeScript 会检查参数
84
+ });
107
85
  }
86
+ </script>
108
87
  ```
109
88
 
110
- ### 使用 useRoute
89
+ ### 获取路由参数(类型安全)
111
90
 
112
- 生成的 `useRoute` Hook 为路由参数提供完整的类型推断:
113
-
114
- ```typescript
115
- import { useRoute, ROUTE_NAME } from '@/router/route.gen';
91
+ ```vue
92
+ <script setup lang="ts">
93
+ import { useRoute } from '@/router/route.gen';
116
94
 
117
- const route = useRoute<'users-id'>();
118
- // route.params.id 的类型为 `string`
95
+ const route = useRoute();
119
96
 
97
+ // 当在用户详情页时
120
98
  if (route.name === ROUTE_NAME.USERS_ID) {
121
- console.log(route.params.id); // 完整类型支持!
99
+ console.log(route.params.id); // ✅ 类型为 string
122
100
  }
101
+ </script>
123
102
  ```
124
103
 
125
- ### 使用 useRouter
104
+ ### 覆盖默认路由配置
126
105
 
127
- 生成的 `useRouter` Hook 提供类型安全的导航:
106
+ 在组件中添加 `<route>` 自定义块,支持完整的路由配置,将覆盖文件路由的默认配置:
128
107
 
129
- ```typescript
130
- import { useRouter, ROUTE_NAME } from '@/router/route.gen';
108
+ ```vue
109
+ <template>
110
+ <div><h1>用户列表</h1></div>
111
+ </template>
112
+
113
+ <route>
114
+ {
115
+ "meta": {
116
+ "title": "用户列表",
117
+ "layout": "admin",
118
+ "requiresAuth": true,
119
+ "roles": ["admin"]
120
+ }
121
+ }
122
+ </route>
123
+ ```
131
124
 
132
- const router = useRouter();
125
+ 或者使用 `defineRoute()` 宏:
133
126
 
134
- // 类型安全的导航 - TypeScript 会验证参数
135
- router.push({
136
- name: ROUTE_NAME.USERS_ID,
137
- params: { id: '123' } // 必需的参数会被检查
127
+ ```vue
128
+ <script setup lang="ts">
129
+ defineRoute({
130
+ meta: {
131
+ title: '用户列表',
132
+ layout: 'admin',
133
+ requiresAuth: true,
134
+ roles: ['admin']
135
+ }
138
136
  });
137
+ </script>
138
+ ```
139
+
140
+ **注意**:可以自定义路径、别名等所有 Vue Router 配置项,详见 [路由配置指南](./docs/RouteConfig.md)。
141
+
142
+ ### 在路由守卫中使用元数据
139
143
 
140
- // 错误:类型 '{ id: string; }' 不能赋值给类型 'Record<string, never>'
141
- router.push({
142
- name: ROUTE_NAME.HOME, // HOME 路由没有参数
143
- params: { id: '123' } // TypeScript 报错!
144
+ ```typescript
145
+ // router/guards.ts
146
+ router.beforeEach((to, from, next) => {
147
+ // 设置页面标题
148
+ if (to.meta.title) {
149
+ document.title = to.meta.title;
150
+ }
151
+
152
+ // 检查认证
153
+ if (to.meta.requiresAuth && !isAuthenticated()) {
154
+ return next({ name: 'login' });
155
+ }
156
+
157
+ next();
144
158
  });
145
159
  ```
146
160
 
147
- ## 完整示例
148
-
149
- ### 项目结构
161
+ ## 📁 目录结构约定
150
162
 
151
163
  ```
152
- src/
153
- ├── pages/
154
- ├── index.vue # 首页
155
- ├── users/
156
- │ │ ├── [id].vue # 用户详情页
157
- │ └── index.vue # 用户列表页
158
- └── posts/
159
- └── $slug.vue # 文章详情页
160
- └── router/
161
- └── route.gen.ts # 自动生成
164
+ src/pages/
165
+ ├── layout.vue # 根布局
166
+ ├── index.vue # 首页 (/)
167
+ ├── about.vue # 关于页面 (/about)
168
+ ├── users/
169
+ ├── layout.vue # 用户布局(嵌套)
170
+ ├── index.vue # 用户列表 (/users)
171
+ └── [id].vue # 用户详情 (/users/:id)
172
+ └── $slug.vue # 通配路由 (/:slug)
162
173
  ```
163
174
 
164
- ### 生成的类型定义
175
+ **自动排除的目录**:`components/`、`hooks/`、`services/`、`types/`、`constants/`、`utils/`
165
176
 
166
- ```typescript
167
- // route.gen.ts (自动生成)
168
- export const ROUTE_NAME = {
169
- INDEX: "index",
170
- USERS_INDEX: "users-index",
171
- USERS_ID: "users-[id]",
172
- POSTS_SLUG: "posts-$slug",
173
- } as const;
174
-
175
- export interface RouteParams {
176
- index: Record<string, never>;
177
- 'users-index': Record<string, never>;
178
- 'users-[id]': {
179
- id: string;
180
- };
181
- 'posts-$slug': {
182
- slug: string;
183
- };
184
- }
177
+ ## ⚙️ 配置
178
+
179
+ ### Vite 插件配置
185
180
 
186
- export function useRoute<TName extends RouteName = RouteName>(
187
- name?: TName
188
- ): /* 类型增强的路由对象 */;
181
+ 如需自定义页面目录或输出文件路径:
189
182
 
190
- export function useRouter(): /* 类型增强的路由对象 */;
183
+ ```typescript
184
+ // vite.config.ts
185
+ export default defineConfig({
186
+ plugins: [
187
+ routeBlockPlugin(),
188
+ routeGenPlugin({
189
+ pagesDir: './src/pages', // 可选,默认 'src/pages'
190
+ outFile: './src/router/route.gen.ts', // 可选,默认 'src/router/route.gen.ts'
191
+ }),
192
+ vue(),
193
+ ],
194
+ });
191
195
  ```
192
196
 
193
- ### 在组件中使用
197
+ ### 自定义路由元数据类型
194
198
 
195
- ```vue
196
- <script setup lang="ts">
197
- import { useRoute, useRouter, ROUTE_NAME } from '@/router/route.gen';
198
-
199
- const route = useRoute();
200
- const router = useRouter();
199
+ 在项目中扩展路由元数据类型:
201
200
 
202
- // 访问路由参数(完全类型安全)
203
- if (route.name === ROUTE_NAME.USERS_ID) {
204
- const userId = route.params.id; // 类型为 string
201
+ ```typescript
202
+ // src/types/router.d.ts
203
+ declare module '@zphhpzzph/vue-route-gen/runtime' {
204
+ interface RouteMeta {
205
+ icon?: string; // 菜单图标
206
+ hidden?: boolean; // 是否隐藏
207
+ order?: number; // 排序
208
+ }
205
209
  }
210
+ ```
206
211
 
207
- // 导航到其他路由(参数类型受保护)
208
- function navigateToUser(userId: string) {
209
- router.push({
210
- name: ROUTE_NAME.USERS_ID,
211
- params: { id: userId } // TypeScript 会检查参数类型
212
- });
212
+ 然后在 `<route>` 块中使用:
213
+
214
+ ```vue
215
+ <route>
216
+ {
217
+ "title": "仪表盘",
218
+ "icon": "Dashboard",
219
+ "hidden": false,
220
+ "order": 1
213
221
  }
214
- </script>
222
+ </route>
215
223
  ```
216
224
 
217
- ## 高级用法
225
+ ### 支持的路由配置
218
226
 
219
- ### 获取特定路由的参数类型
227
+ 支持所有 Vue Router 配置项及自定义元数据:
220
228
 
221
- ```typescript
222
- import type { RouteParamsByName } from '@/router/route.gen';
229
+ | 配置项 | 类型 | 说明 |
230
+ |--------|------|------|
231
+ | `path` | `string` | 自定义路由路径 |
232
+ | `name` | `string` | 自定义路由名称 |
233
+ | `alias` | `string \| string[]` | 路由别名 |
234
+ | `redirect` | `string \| object` | 重定向配置 |
235
+ | `props` | `boolean \| object` | 路由参数传递 |
236
+ | `meta` | `object` | 路由元数据(见下表) |
223
237
 
224
- type UserDetailParams = RouteParamsByName<'users-[id]'>;
225
- // 类型为:{ id: string }
238
+ **常用 meta 属性**:
226
239
 
227
- function fetchUserData(params: UserDetailParams) {
228
- // params.id 的类型为 string
229
- return api.get(`/users/${params.id}`);
230
- }
231
- ```
240
+ | 属性 | 类型 | 说明 |
241
+ |------|------|------|
242
+ | `title` | `string` | 页面标题 |
243
+ | `layout` | `string \| false` | 布局组件或 `false` 禁用 |
244
+ | `keepAlive` | `boolean` | 是否缓存页面 |
245
+ | `requiresAuth` | `boolean` | 是否需要认证 |
246
+ | `roles` | `string[]` | 允许的角色 |
247
+ | `icon` | `string` | 菜单图标 |
248
+ | `hidden` | `boolean` | 是否隐藏菜单 |
249
+ | `*` | `any` | 支持任何自定义属性 |
250
+
251
+ 完整配置示例请查看 [路由配置指南](./docs/RouteConfig.md)。
252
+
253
+ ## 📖 实用示例
232
254
 
233
- ### 布局嵌套
255
+ ### 示例 1:创建嵌套路由
234
256
 
235
257
  ```
236
258
  src/pages/
237
- ├── layout.vue # 根布局
238
- ├── index.vue # / (使用根布局)
259
+ ├── layout.vue # 根布局
260
+ ├── index.vue # /
239
261
  ├── admin/
240
- │ ├── layout.vue # /admin 布局
241
- │ ├── index.vue # /admin (使用 admin 布局)
262
+ │ ├── layout.vue # 管理后台布局
263
+ │ ├── index.vue # /admin
242
264
  │ └── users/
243
- └── [id].vue # /admin/users/:id (使用 admin 布局)
265
+ ├── index.vue # /admin/users
266
+ │ └── [id].vue # → /admin/users/:id
244
267
  ```
245
268
 
246
- ## 最佳实践
269
+ ### 示例 2:动态路由参数
247
270
 
248
- 1. **始终使用生成的常量**:使用 `ROUTE_NAME` 而不是硬编码字符串
249
- 2. **利用类型推断**:让 TypeScript 为你检查路由参数
250
- 3. **组合使用 Hooks**:`useRoute` 和 `useRouter` 提供完整的类型安全
271
+ 两种语法都支持:
251
272
 
252
- ## 发布新版本(维护者)
273
+ ```
274
+ # 方式 1:Vue Router 风格
275
+ users/[id].vue # → /users/:id
253
276
 
254
- ### 快速发布
277
+ # 方式 2:Nuxt 风格
278
+ posts/$slug.vue # → /posts/:slug
279
+ ```
255
280
 
256
- ```bash
257
- # 补丁版本 (1.0.0 -> 1.0.1)
258
- pnpm run release:patch
281
+ ### 示例 3:完整页面示例
259
282
 
260
- # 次要版本 (1.0.0 -> 1.1.0)
261
- pnpm run release:minor
283
+ ```vue
284
+ <!-- src/pages/users/[id].vue -->
285
+ <template>
286
+ <div>
287
+ <h1>用户详情</h1>
288
+ <p>用户 ID: {{ userId }}</p>
289
+ </div>
290
+ </template>
262
291
 
263
- # 主要版本 (1.0.0 -> 2.0.0)
264
- pnpm run release:major
265
- ```
292
+ <script setup lang="ts">
293
+ import { computed } from 'vue';
294
+ import { useRoute } from '@/router/route.gen';
266
295
 
267
- ### 预发布版本
296
+ const route = useRoute('users-[id]');
297
+ const userId = computed(() => route.params.id);
298
+ </script>
268
299
 
269
- ```bash
270
- # 预发布补丁 (1.0.0 -> 1.0.1-0)
271
- pnpm run release:pre
300
+ <route>
301
+ {
302
+ "path": "/users/:id",
303
+ "props": true,
304
+ "meta": {
305
+ "title": "用户详情",
306
+ "layout": "admin",
307
+ "requiresAuth": true,
308
+ "roles": ["admin", "moderator"]
309
+ }
310
+ }
311
+ </route>
272
312
  ```
273
313
 
274
- ### 手动发布流程
314
+ ## 🔍 生成的内容说明
275
315
 
276
- ```bash
277
- # 1. 更新版本号
278
- npm version patch|minor|major
316
+ `vue-route-gen` 会生成 `route.gen.ts` 文件,包含:
317
+
318
+ - **`routes`** - Vue Router 路由配置数组
319
+ - **`ROUTE_NAME`** - 路由名称常量(避免硬编码)
320
+ - **`useRoute()`** - 类型增强的路由 hook
321
+ - **`useRouter()`** - 类型增强的路由导航 hook
279
322
 
280
- # 2. 构建
281
- pnpm run build
323
+ **通常你只需要使用这几个导出即可,无需关心底层实现细节。**
282
324
 
283
- # 3. 发布到 npm
284
- npm publish --access public --registry https://registry.npmjs.org/
325
+ ## 常见问题
326
+
327
+ ### Q: 如何手动触发路由生成?
328
+
329
+ A: 运行 CLI 命令:
330
+ ```bash
331
+ pnpm exec vue-route-gen
285
332
  ```
286
333
 
287
- ### 发布脚本说明
334
+ ### Q: 如何禁用某个目录的路由生成?
335
+
336
+ A: 以下目录自动排除:`components/`、`hooks/`、`services/`、`types/`、`constants/`、`utils/`
337
+
338
+ ### Q: 开发时路由会自动更新吗?
339
+
340
+ A: 使用 `routeGenPlugin()` 后,路由会在文件变化时自动重新生成。
288
341
 
289
- - `release:patch` - 自动更新补丁版本并发布(bug 修复)
290
- - `release:minor` - 自动更新次要版本并发布(新功能)
291
- - `release:major` - 自动更新主要版本并发布(破坏性变更)
292
- - `release:pre` - 发布预发布版本(alpha/beta/rc)
293
- - `release` - 仅发布(不更新版本号)
294
- - `pre-release` - 发布预发布版本(不更新版本号)
342
+ ## 📚 深入阅读
295
343
 
296
- 这些脚本会自动:
297
- 1. 更新 package.json 中的版本号
298
- 2. 创建 git tag
299
- 3. 构建 TypeScript 代码
300
- 4. 发布到 npm registry
344
+ - **[文档索引](./docs/README.md)** - 完整文档导航
345
+ - **[更新日志](./CHANGELOG.md)** - 版本更新记录
346
+ - **[路由配置指南](./docs/RouteConfig.md)** - `<route>` 块和 `defineRoute()` 完整用法
347
+ - **[Vite 插件详解](./docs/VitePlugin.md)** - 插件工作原理
301
348
 
302
- ## License
349
+ ## 📄 License
303
350
 
304
351
  MIT
@@ -1,17 +1,28 @@
1
- export interface RouteMeta {
2
- title?: string;
3
- layout?: string | false;
4
- keepAlive?: boolean;
5
- requiresAuth?: boolean;
6
- roles?: string[];
7
- redirect?: string | {
8
- name: string;
9
- path?: string;
10
- };
1
+ import type { RouteRecordRaw, RouteRecordRedirectOption, _RouteRecordProps } from 'vue-router';
2
+ type RouteRecordProps = _RouteRecordProps;
3
+ /**
4
+ * Route configuration override interface
5
+ * Supports all RouteRecordRaw fields for complete customization
6
+ */
7
+ export interface RouteConfigOverride {
8
+ path?: string;
9
+ name?: string;
10
+ alias?: string | string[];
11
+ redirect?: RouteRecordRedirectOption;
12
+ props?: RouteRecordProps;
13
+ meta?: Record<string, any>;
14
+ children?: RouteRecordRaw[];
15
+ beforeEnter?: any;
11
16
  [key: string]: any;
12
17
  }
13
18
  /**
14
- * Parse Vue SFC and extract metadata from <route> custom block
19
+ * Parse Vue SFC and extract complete route configuration
20
+ * Supports both <route> custom block and defineRoute() macro
21
+ *
22
+ * @param filePath - Path to the Vue SFC file
23
+ * @returns Route configuration override, or undefined if no custom config
24
+ * @throws Error if both <route> block and defineRoute() are present
15
25
  */
16
- export declare function extractRouteMeta(filePath: string): RouteMeta;
26
+ export declare function extractRouteConfig(filePath: string): RouteConfigOverride | undefined;
27
+ export {};
17
28
  //# sourceMappingURL=extract-meta.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"extract-meta.d.ts","sourceRoot":"","sources":["../src/extract-meta.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,SAAS;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAqB5D"}
1
+ {"version":3,"file":"extract-meta.d.ts","sourceRoot":"","sources":["../src/extract-meta.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAG/F,KAAK,gBAAgB,GAAG,iBAAiB,CAAC;AAE1C;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,GAAG,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAiDpF"}