firestore-dart-generator 1.0.0-beta.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.
Files changed (40) hide show
  1. package/CONFIG_FILE_GUIDE.md +445 -0
  2. package/IMPLEMENTATION_SUMMARY.md +305 -0
  3. package/LICENSE +22 -0
  4. package/QUICK_START.md +241 -0
  5. package/README.md +590 -0
  6. package/dist/config-file-loader.d.ts +35 -0
  7. package/dist/config-file-loader.d.ts.map +1 -0
  8. package/dist/config-file-loader.js +130 -0
  9. package/dist/config-file-loader.js.map +1 -0
  10. package/dist/config-loader.d.ts +21 -0
  11. package/dist/config-loader.d.ts.map +1 -0
  12. package/dist/config-loader.js +125 -0
  13. package/dist/config-loader.js.map +1 -0
  14. package/dist/dart-generator.d.ts +35 -0
  15. package/dist/dart-generator.d.ts.map +1 -0
  16. package/dist/dart-generator.js +167 -0
  17. package/dist/dart-generator.js.map +1 -0
  18. package/dist/firestore-client.d.ts +49 -0
  19. package/dist/firestore-client.d.ts.map +1 -0
  20. package/dist/firestore-client.js +227 -0
  21. package/dist/firestore-client.js.map +1 -0
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +65 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/interactive-cli.d.ts +5 -0
  27. package/dist/interactive-cli.d.ts.map +1 -0
  28. package/dist/interactive-cli.js +310 -0
  29. package/dist/interactive-cli.js.map +1 -0
  30. package/dist/schema-analyzer.d.ts +38 -0
  31. package/dist/schema-analyzer.d.ts.map +1 -0
  32. package/dist/schema-analyzer.js +350 -0
  33. package/dist/schema-analyzer.js.map +1 -0
  34. package/dist/templates/model.hbs +39 -0
  35. package/dist/types.d.ts +58 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +3 -0
  38. package/dist/types.js.map +1 -0
  39. package/firestore-dart-gen.example.yaml +28 -0
  40. package/package.json +61 -0
package/README.md ADDED
@@ -0,0 +1,590 @@
1
+ # Firestore Dart Generator
2
+
3
+ A TypeScript CLI tool that automatically generates Dart models from Firestore collections by analyzing document schemas in your Firebase project.
4
+
5
+ ## Features
6
+
7
+ - 🎮 **Interactive Mode**: Guided CLI experience with collection selection
8
+ - 🔥 Connects directly to Firebase Firestore
9
+ - 📊 Analyzes real documents to infer field types
10
+ - 🎯 Generates clean Dart models with `fromJson`/`toJson`
11
+ - 🔍 Detects optional and nullable fields automatically
12
+ - ✅ **Multiple selection**: Choose multiple collections at once with checkboxes
13
+ - 🌳 **Auto-discovery**: Automatically detects and offers subcollections
14
+ - 🎨 **Auto-formats generated code with `dart format`**
15
+ - ⚡ Fast and easy to use
16
+
17
+ ## Installation
18
+
19
+ ### Global Installation (Recommended)
20
+
21
+ ```bash
22
+ npm install -g firestore-dart-generator
23
+ ```
24
+
25
+ ### Using npx (No Installation Required)
26
+
27
+ ```bash
28
+ npx firestore-dart-generator --help
29
+ ```
30
+
31
+ ### Local Installation
32
+
33
+ ```bash
34
+ npm install --save-dev firestore-dart-generator
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ 1. **Install the tool**:
40
+ ```bash
41
+ npm install -g firestore-dart-generator
42
+ ```
43
+
44
+ 2. **Run interactively**:
45
+ ```bash
46
+ firestore-dart-gen --service-account firebase_service_account.json
47
+ ```
48
+
49
+ 3. **Follow the prompts**:
50
+ - ✨ View your Firebase project name
51
+ - ✅ Select collections with checkboxes (Space to select, Enter to confirm)
52
+ - 🌳 Choose whether to include subcollections (auto-detected)
53
+ - 📁 Configure output directory and sample size
54
+ - 🎯 Review summary and confirm
55
+
56
+ Done! Your Dart models are generated.
57
+
58
+ ## Prerequisites
59
+
60
+ - Node.js 18+ with npm
61
+ - Firebase project with Firestore
62
+ - Firebase service account JSON file (for authentication)
63
+ - (Optional) Dart SDK for auto-formatting
64
+
65
+ ## Firebase Authentication Setup
66
+
67
+ ### 1. Create a Firebase Service Account
68
+
69
+ 1. Go to [Firebase Console](https://console.firebase.google.com/)
70
+ 2. Select your project
71
+ 3. Go to **Project Settings** > **Service Accounts**
72
+ 4. Click **Generate New Private Key**
73
+ 5. Save the JSON file securely (e.g., `firebase_service_account.json`)
74
+
75
+ ⚠️ **Important**: Never commit this file to git!
76
+
77
+ ### 2. Configure Environment Variables (Optional)
78
+
79
+ Create a `.env` file in your project directory:
80
+
81
+ ```bash
82
+ GOOGLE_APPLICATION_CREDENTIALS=./firebase_service_account.json
83
+ FIREBASE_PROJECT_ID=your-project-id
84
+ ```
85
+
86
+ Or use the `--service-account` and `--project-id` flags when running the command.
87
+
88
+ ## Configuration File (Optional)
89
+
90
+ You can create a `firestore-dart-gen.yaml` file to:
91
+ - ✅ Specify Firebase credentials (no need to type them every time)
92
+ - ✅ Pre-select collections you use frequently
93
+ - ✅ Set default output directory and sample size
94
+ - ✅ Share configuration with your team (without credentials)
95
+
96
+ ### Example Configuration
97
+
98
+ Create `firestore-dart-gen.yaml` in your project root:
99
+
100
+ ```yaml
101
+ # Firebase Configuration
102
+ firebase:
103
+ serviceAccount: ./firebase_service_account.json
104
+ projectId: my-project-id # optional
105
+
106
+ # Pre-select these collections in the CLI
107
+ collections:
108
+ - users
109
+ - products
110
+ - orders
111
+
112
+ # Default output settings
113
+ output:
114
+ directory: ./lib/src/models
115
+ sampleSize: 20
116
+ ```
117
+
118
+ Copy from the example file:
119
+ ```bash
120
+ cp firestore-dart-gen.example.yaml firestore-dart-gen.yaml
121
+ # Edit with your settings
122
+ ```
123
+
124
+ ### Usage with Config File
125
+
126
+ ```bash
127
+ # CLI will automatically find firestore-dart-gen.yaml
128
+ firestore-dart-gen
129
+
130
+ # Or specify a custom config file
131
+ firestore-dart-gen --config my-config.yaml
132
+
133
+ # Override config with CLI arguments
134
+ firestore-dart-gen --service-account other.json
135
+ ```
136
+
137
+ ### Priority Order
138
+
139
+ Configuration is resolved in this order (highest to lowest priority):
140
+
141
+ 1. **CLI arguments** (e.g., `--service-account other.json`)
142
+ 2. **Config file** (`firestore-dart-gen.yaml`)
143
+ 3. **Environment variables** (`.env` file)
144
+
145
+ **Example:** If you have `serviceAccount` in the YAML but also pass `--service-account`, the CLI argument wins.
146
+
147
+ ### Benefits
148
+
149
+ - ✅ Save time - no need to type credentials every run
150
+ - ✅ Pre-select collections you work with frequently
151
+ - ✅ Team consistency - share same defaults
152
+ - ✅ Flexible - can override with CLI args anytime
153
+
154
+ ⚠️ **Important:** Add `firestore-dart-gen.yaml` to `.gitignore` if it contains sensitive paths!
155
+
156
+ ## Usage
157
+
158
+ ### Interactive Mode (Default) 🎮
159
+
160
+ The tool runs in interactive mode by default, providing a guided experience:
161
+
162
+ **Features:**
163
+ - 🔍 **Auto-discovery**: Automatically lists all collections in your project
164
+ - ✅ **Multiple selection**: Use checkboxes to select multiple collections at once
165
+ - 🌳 **Subcollection detection**: Automatically finds and offers to include subcollections
166
+ - ⚙️ **Easy configuration**: Configure output directory and sample size with prompts
167
+ - 📊 **Summary review**: See exactly what will be generated before confirming
168
+
169
+ **Run the interactive mode:**
170
+
171
+ ```bash
172
+ firestore-dart-gen --service-account firebase_service_account.json
173
+ ```
174
+
175
+ **Example Session:**
176
+
177
+ ```
178
+ 🔥 Firestore Dart Generator - Interactive Mode
179
+
180
+ ✓ Connected to Firebase Project: my-awesome-app
181
+
182
+ 🔍 Discovering collections...
183
+
184
+ Found 5 collection(s)
185
+
186
+ ? Select collections to generate models for: (Use arrow keys, Space to select, Enter to confirm)
187
+ ❯◯ users
188
+ ◯ products
189
+ ◯ orders
190
+ ◯ reviews
191
+ ◯ settings
192
+
193
+ 🌳 Checking for subcollections...
194
+
195
+ Analyzing users...
196
+ Found 2 subcollection(s): profiles, settings
197
+ Include subcollections for users? (Y/n) Yes
198
+
199
+ ? Output directory for generated Dart files: ./lib/src/models
200
+ ? Number of documents to sample per collection: 20
201
+
202
+ 📋 Generation Summary:
203
+ ────────────────────────────────────────────────────────────
204
+ Firebase Project: my-awesome-app
205
+ Collections: users, products
206
+ Subcollections:
207
+ └─ users: profiles, settings
208
+ Output: ./lib/src/models
209
+ Sample Size: 20 documents per collection
210
+ ────────────────────────────────────────────────────────────
211
+
212
+ ? Generate Dart models with these settings? (Y/n) Yes
213
+
214
+ 🚀 Starting generation...
215
+
216
+ 📦 Processing collection: users
217
+ ...
218
+
219
+ ✨ Success! Generated 4 model(s)
220
+
221
+ Generated files:
222
+ ✓ lib/src/models/user_dto.dart
223
+ ✓ lib/src/models/profile_dto.dart
224
+ ✓ lib/src/models/setting_dto.dart
225
+ ✓ lib/src/models/product_dto.dart
226
+
227
+ 📚 Next steps:
228
+ 1. Review the generated files
229
+ 2. Import the models in your Dart code
230
+ 3. Add 'equatable' to your pubspec.yaml if not already present
231
+ ```
232
+
233
+ ## Legacy Usage (Advanced)
234
+
235
+ ### Batch Mode (Legacy)
236
+
237
+ *Note: Interactive mode is now recommended for most use cases.*
238
+
239
+ Extract multiple collections using a YAML configuration file:
240
+
241
+ 1. **Create `collections.yaml`** (or copy from `collections.example.yaml`):
242
+
243
+ ```yaml
244
+ collections:
245
+ - name: users
246
+ output: ./lib/src/models
247
+ sampleSize: 20
248
+ subcollections:
249
+ - profiles
250
+ - settings
251
+
252
+ - name: products
253
+ output: ./lib/src/models
254
+ ```
255
+
256
+ 2. **Run the extractor**:
257
+
258
+ ```bash
259
+ firestore-dart-gen batch --service-account firebase_service_account.json
260
+ ```
261
+
262
+ That's it! All collections in the YAML file will be processed.
263
+
264
+ ### Single Collection Mode (Legacy)
265
+
266
+ *Note: Interactive mode is now recommended for most use cases.*
267
+
268
+ For programmatic use or CI/CD, you can still extract collections using the old commands (requires custom wrapper):
269
+
270
+ ```bash
271
+ firestore-dart-gen single \
272
+ --collection users \
273
+ --output ./lib/src/models \
274
+ --service-account firebase_service_account.json
275
+ ```
276
+
277
+ ### With Subcollections
278
+
279
+ ```bash
280
+ firestore-dart-gen single \
281
+ --collection orders \
282
+ --subcollections items,shipping_info \
283
+ --output ./lib/src/models \
284
+ --service-account firebase_service_account.json
285
+ ```
286
+
287
+ ## Command Line Options
288
+
289
+ ### Interactive Mode (Default)
290
+
291
+ | Option | Required | Description | Default |
292
+ |--------|----------|-------------|---------|
293
+ | `--service-account <path>` | No | Path to service account JSON | From env |
294
+ | `--project-id <id>` | No | Firebase project ID | From env |
295
+
296
+ ### Batch Mode (Legacy)
297
+
298
+ | Option | Alias | Required | Description | Default |
299
+ |--------|-------|----------|-------------|---------|
300
+ | `--config <path>` | `-f` | No | Path to collections.yaml | `collections.yaml` |
301
+ | `--service-account <path>` | - | No | Path to service account JSON | From env |
302
+ | `--project-id <id>` | - | No | Firebase project ID | From env |
303
+
304
+ ### Single Mode
305
+
306
+ | Option | Alias | Required | Description | Default |
307
+ |--------|-------|----------|-------------|---------|
308
+ | `--collection <name>` | `-c` | Yes | Firestore collection name | - |
309
+ | `--output <path>` | `-o` | Yes | Output directory for Dart files | - |
310
+ | `--subcollections <names>` | `-s` | No | Comma-separated subcollections | - |
311
+ | `--service-account <path>` | - | No | Path to service account JSON | From env |
312
+ | `--project-id <id>` | - | No | Firebase project ID | From env |
313
+ | `--sample-size <number>` | - | No | Number of docs to sample | 20 |
314
+
315
+ ## Configuration File
316
+
317
+ The `collections.yaml` file defines which collections to extract:
318
+
319
+ ```yaml
320
+ collections:
321
+ # Simple collection
322
+ - name: users
323
+ output: ./lib/src/models
324
+ sampleSize: 20 # Optional: number of documents to sample (default: 20)
325
+
326
+ # Collection with subcollections
327
+ - name: orders
328
+ output: ./lib/src/models
329
+ subcollections:
330
+ - items # Will extract from orders/{orderId}/items
331
+ - shipping_info # Will extract from orders/{orderId}/shipping_info
332
+ ```
333
+
334
+ ## Generated Output
335
+
336
+ ### Example Input (Firestore Document)
337
+
338
+ ```json
339
+ {
340
+ "id": "user123",
341
+ "email": "user@example.com",
342
+ "name": "John Doe",
343
+ "age": 30,
344
+ "isActive": true,
345
+ "createdAt": Timestamp(2024-01-01),
346
+ "metadata": {
347
+ "source": "mobile"
348
+ }
349
+ }
350
+ ```
351
+
352
+ ### Generated Dart Model
353
+
354
+ ```dart
355
+ import 'package:equatable/equatable.dart';
356
+
357
+ /// {@template user}
358
+ /// A model representing a users document from Firestore.
359
+ /// {@endtemplate}
360
+ class User extends Equatable {
361
+ /// {@macro user}
362
+ const User({
363
+ required this.id,
364
+ required this.email,
365
+ required this.isActive,
366
+ this.age,
367
+ this.name,
368
+ this.createdAt,
369
+ this.metadata,
370
+ });
371
+
372
+ /// Creates a [User] from a JSON map.
373
+ factory User.fromJson(Map<String, dynamic> json) {
374
+ return User(
375
+ id: json['id'] as String,
376
+ email: json['email'] as String,
377
+ isActive: json['isActive'] as bool,
378
+ age: json['age'] as int?,
379
+ name: json['name'] as String?,
380
+ createdAt: json['createdAt'] != null
381
+ ? DateTime.parse(json['createdAt'] as String)
382
+ : null,
383
+ metadata: json['metadata'] as Map<String, dynamic>?,
384
+ );
385
+ }
386
+
387
+ /// The id field.
388
+ final String id;
389
+
390
+ /// The email field.
391
+ final String email;
392
+
393
+ /// The isActive field.
394
+ final bool isActive;
395
+
396
+ /// The age field.
397
+ final int? age;
398
+
399
+ /// The name field.
400
+ final String? name;
401
+
402
+ /// The createdAt field.
403
+ final DateTime? createdAt;
404
+
405
+ /// The metadata field.
406
+ final Map<String, dynamic>? metadata;
407
+
408
+ @override
409
+ List<Object?> get props => [
410
+ id,
411
+ email,
412
+ isActive,
413
+ age,
414
+ name,
415
+ createdAt,
416
+ metadata,
417
+ ];
418
+
419
+ /// Converts this [User] to a JSON map.
420
+ Map<String, dynamic> toJson() {
421
+ return {
422
+ 'id': id,
423
+ 'email': email,
424
+ 'isActive': isActive,
425
+ if (age != null) 'age': age,
426
+ if (name != null) 'name': name,
427
+ if (createdAt != null) 'createdAt': createdAt?.toIso8601String(),
428
+ if (metadata != null) 'metadata': metadata,
429
+ };
430
+ }
431
+ }
432
+ ```
433
+
434
+ ## Type Detection
435
+
436
+ The tool automatically detects and maps Firestore types to Dart types:
437
+
438
+ | Firestore Type | Dart Type |
439
+ |----------------|-----------|
440
+ | String | `String` |
441
+ | Number (integer) | `int` |
442
+ | Number (float) | `double` |
443
+ | Boolean | `bool` |
444
+ | Timestamp | `DateTime` |
445
+ | Array | `List<dynamic>` |
446
+ | Map | `Map<String, dynamic>` |
447
+ | Null/Mixed | `dynamic` |
448
+
449
+ ### Optional Fields
450
+
451
+ - A field is marked **optional** (`field?`) if it doesn't appear in all sampled documents
452
+ - Optional fields use `if (field != null)` in `toJson()`
453
+
454
+ ### Nullable Fields
455
+
456
+ - A field is marked **nullable** (`Type?`) if it has inconsistent types across documents
457
+ - Required fields present in all documents are non-nullable
458
+
459
+ ## Workflow
460
+
461
+ ### 1. Extract Schema
462
+
463
+ ```bash
464
+ firestore-dart-gen single \
465
+ --collection users \
466
+ --output ./lib/src/models \
467
+ --service-account firebase_service_account.json
468
+ ```
469
+
470
+ ### 2. Review and Customize
471
+
472
+ **Note:** The tool automatically runs `dart format` on generated files, so formatting is already done!
473
+
474
+ The generated models are basic. You may want to:
475
+
476
+ - Add more detailed documentation
477
+ - Customize field names (if Firestore uses different naming)
478
+ - Add validation logic
479
+ - Use `json_serializable` for more complex scenarios
480
+
481
+ ### 3. Import in Your Code
482
+
483
+ ```dart
484
+ import 'package:your_package/models/user.dart';
485
+
486
+ final user = User.fromJson(firestoreDoc.data()!);
487
+ ```
488
+
489
+ ## Troubleshooting
490
+
491
+ ### "Service account file not found"
492
+
493
+ Make sure the path to your service account JSON is correct. Use absolute paths or paths relative to your current directory.
494
+
495
+ ### "No documents found in collection"
496
+
497
+ - Verify the collection name is correct
498
+ - Ensure the collection has at least one document
499
+ - Check Firebase rules allow read access for the service account
500
+
501
+ ### "Multiple types detected" warning
502
+
503
+ This happens when a field has different types across documents. The tool will use `dynamic` type. Consider:
504
+
505
+ - Cleaning up inconsistent data in Firestore
506
+ - Manually editing the generated model to use the correct type
507
+
508
+ ### "dart command not found" warning
509
+
510
+ The tool tries to auto-format generated files with `dart format`. If Dart SDK is not in your PATH, you'll see a warning:
511
+
512
+ ```
513
+ ⚠ Could not format files: dart command not found
514
+ ```
515
+
516
+ This is **non-fatal** - your files are still generated correctly, just not formatted. To fix:
517
+
518
+ 1. **Install Dart SDK** (if not installed): https://dart.dev/get-dart
519
+ 2. **Add to PATH**: Make sure `dart` command is available in your terminal
520
+ 3. **Manual format**: Run `dart format <output-directory>` manually after generation
521
+
522
+ Or ignore it - the generated code is valid, just might need manual formatting.
523
+
524
+ ## Development
525
+
526
+ ### Running Locally
527
+
528
+ 1. Clone the repository
529
+ 2. Install dependencies: `npm install`
530
+ 3. Build: `npm run build`
531
+ 4. Run: `npm run extract` or `npm run extract:single`
532
+
533
+ ### Testing
534
+
535
+ The project includes comprehensive golden tests to ensure code generation quality:
536
+
537
+ ```bash
538
+ # Run all tests
539
+ npm test
540
+
541
+ # Run tests in watch mode
542
+ npm run test:watch
543
+
544
+ # Run tests with coverage report
545
+ npm run test:coverage
546
+
547
+ # Update golden files (when intentionally changing output)
548
+ npm run test:update-goldens
549
+ ```
550
+
551
+ Golden tests verify that the generated Dart code matches expected output exactly. See [test/README.md](test/README.md) for more details.
552
+
553
+ ### Project Structure
554
+
555
+ ```
556
+ firestore-dart-generator/
557
+ ├── src/
558
+ │ ├── index.ts # CLI entry point
559
+ │ ├── firestore-client.ts # Firebase connection
560
+ │ ├── schema-analyzer.ts # Type detection logic
561
+ │ ├── dart-generator.ts # Code generation
562
+ │ ├── config-loader.ts # YAML config loader
563
+ │ ├── types.ts # TypeScript interfaces
564
+ │ └── templates/
565
+ │ └── model.hbs # Handlebars template
566
+ ├── dist/ # Compiled JavaScript
567
+ ├── package.json
568
+ ├── tsconfig.json
569
+ └── README.md
570
+ ```
571
+
572
+ ## Security Notes
573
+
574
+ - ⚠️ **Never commit** service account JSON files
575
+ - Add `*service-account.json` to `.gitignore`
576
+ - Use environment variables for sensitive data
577
+ - Limit service account permissions to read-only Firestore access
578
+
579
+ ## Contributing
580
+
581
+ Contributions are welcome! Please feel free to submit a Pull Request.
582
+
583
+ ## License
584
+
585
+ MIT
586
+
587
+ ## Support
588
+
589
+ If you encounter any issues or have questions, please [open an issue](https://github.com/your-username/firestore-dart-generator/issues) on GitHub.
590
+
@@ -0,0 +1,35 @@
1
+ export interface CLIConfig {
2
+ firebase?: {
3
+ serviceAccount?: string;
4
+ projectId?: string;
5
+ };
6
+ collections?: string[];
7
+ output?: {
8
+ directory?: string;
9
+ sampleSize?: number;
10
+ };
11
+ }
12
+ export declare class ConfigFileLoader {
13
+ private static CONFIG_FILES;
14
+ /**
15
+ * Load configuration from YAML file if exists
16
+ */
17
+ static loadConfig(configPath?: string): CLIConfig | null;
18
+ /**
19
+ * Load config from specific path
20
+ */
21
+ private static loadFromPath;
22
+ /**
23
+ * Validate configuration structure
24
+ */
25
+ private static validateConfig;
26
+ /**
27
+ * Resolve service account path
28
+ */
29
+ static resolveServiceAccountPath(config: CLIConfig | null, cliArg?: string): string | undefined;
30
+ /**
31
+ * Resolve project ID
32
+ */
33
+ static resolveProjectId(config: CLIConfig | null, cliArg?: string): string | undefined;
34
+ }
35
+ //# sourceMappingURL=config-file-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-file-loader.d.ts","sourceRoot":"","sources":["../src/config-file-loader.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE;QACT,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,YAAY,CAKzB;IAEF;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAkBxD;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAe3B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAoB7B;;OAEG;IACH,MAAM,CAAC,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAS/F;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAMvF"}