prisma-effect-kysely 1.8.2 → 1.8.3
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/CHANGELOG.md +37 -68
- package/dist/effect/join-table.d.ts +6 -1
- package/dist/effect/join-table.d.ts.map +1 -1
- package/dist/effect/join-table.js +16 -4
- package/dist/effect/join-table.js.map +1 -1
- package/dist/utils/naming.d.ts +12 -0
- package/dist/utils/naming.d.ts.map +1 -1
- package/dist/utils/naming.js +23 -0
- package/dist/utils/naming.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,83 +5,52 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [1.8.
|
|
9
|
-
|
|
10
|
-
### Fixed
|
|
11
|
-
|
|
12
|
-
#### Kysely Join Type Inference
|
|
13
|
-
- **DB interface now uses pre-resolved SelectEncoded types**: Fixed TypeScript compilation errors when using Kysely `innerJoin()` with junction tables
|
|
14
|
-
- **Problem**: `Schema.Schema.Encoded<typeof _table>` created conditional types too complex for Kysely's deep generic inference
|
|
15
|
-
- **Solution**: Use existing pre-resolved `*SelectEncoded` type aliases that already exist in generated code
|
|
16
|
-
- **Impact**: Kysely can now properly infer types for join operations without "Type instantiation is excessively deep" errors
|
|
17
|
-
- **Breaking**: None - only internal DB interface generation changed, user API remains identical
|
|
18
|
-
- Location: `src/kysely/type.ts:61-72`
|
|
19
|
-
|
|
20
|
-
#### Unused Enum Type Imports
|
|
21
|
-
- **types.ts now imports only Schema wrappers**: Eliminated TypeScript "declared but never read" warnings for enum types
|
|
22
|
-
- **Problem**: Generated `types.ts` imported both plain enum types (e.g., `BudgetStatus`) and schema wrappers (e.g., `BudgetStatusSchema`), but only the schema wrappers were used in field definitions
|
|
23
|
-
- **Solution**: Import generation now only includes `*Schema` wrappers, not plain enum types
|
|
24
|
-
- **Impact**: Eliminates all unused import warnings for enum types in generated code
|
|
25
|
-
- **Breaking**: None - users can still import plain enum types directly from `enums.ts` if needed
|
|
26
|
-
- Location: `src/effect/generator.ts:95-107`
|
|
8
|
+
## [1.8.3] - 2025-10-13
|
|
27
9
|
|
|
28
10
|
### Added
|
|
29
11
|
|
|
30
|
-
####
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
- Generated imports change from `import { Role, RoleSchema, Status, StatusSchema }` to `import { RoleSchema, StatusSchema }`
|
|
47
|
-
- Plain enum types still exported from `enums.ts` for direct use
|
|
48
|
-
|
|
49
|
-
**Overall:**
|
|
50
|
-
- Effect Schema functionality preserved - all 158 tests passing
|
|
51
|
-
- No type coercions introduced
|
|
52
|
-
- No breaking changes
|
|
12
|
+
#### Semantic Join Table Column Names
|
|
13
|
+
- **Generated join tables now use semantic snake_case field names** instead of Prisma's generic A/B columns
|
|
14
|
+
- **Problem**: Prisma's implicit M2M join tables use non-semantic `A` and `B` column names, causing poor developer experience and forcing developers to remember alphabetical model ordering
|
|
15
|
+
- **Solution**: Map semantic names like `product_id`, `product_tag_id` to actual database columns using Effect Schema's `propertySignature` with `fromKey`
|
|
16
|
+
- **Benefits**:
|
|
17
|
+
- Developer-friendly semantic names in TypeScript code
|
|
18
|
+
- Maintains Prisma A/B database compatibility (no migration required)
|
|
19
|
+
- Type-safe bidirectional transformation (encode/decode)
|
|
20
|
+
- Follows snake_case convention for database identifiers (Prisma best practice)
|
|
21
|
+
- **Example**:
|
|
22
|
+
```typescript
|
|
23
|
+
// Before (v1.8.2):
|
|
24
|
+
export const _ProductToProductTag = Schema.Struct({
|
|
25
|
+
A: columnType(Schema.UUID, Schema.Never, Schema.Never),
|
|
26
|
+
B: columnType(Schema.UUID, Schema.Never, Schema.Never),
|
|
27
|
+
});
|
|
53
28
|
|
|
54
|
-
|
|
29
|
+
// After (v1.8.3):
|
|
30
|
+
export const _ProductToProductTag = Schema.Struct({
|
|
31
|
+
product_id: Schema.propertySignature(columnType(Schema.UUID, Schema.Never, Schema.Never)).pipe(Schema.fromKey("A")),
|
|
32
|
+
product_tag_id: Schema.propertySignature(columnType(Schema.UUID, Schema.Never, Schema.Never)).pipe(Schema.fromKey("B")),
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
- Location: `src/effect/join-table.ts:37-69`
|
|
36
|
+
- New utility: `toSnakeCase()` in `src/utils/naming.ts:61-73`
|
|
55
37
|
|
|
56
38
|
### Fixed
|
|
57
39
|
|
|
58
|
-
####
|
|
59
|
-
- **
|
|
60
|
-
-
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
- Location: `src/generator
|
|
64
|
-
|
|
65
|
-
#### Custom Relation Name Support for Join Tables
|
|
66
|
-
- **Prisma custom relation names now respected**: Fixed implicit many-to-many join table naming
|
|
67
|
-
- `@relation("product_tags")` now correctly generates `_product_tags` table (not `_ProductToProductTag`)
|
|
68
|
-
- Matches Prisma's actual database table naming convention
|
|
69
|
-
- Both custom and default relation names work correctly
|
|
70
|
-
- Location: `src/prisma/relation.ts:106-115`
|
|
71
|
-
|
|
72
|
-
### Added
|
|
73
|
-
|
|
74
|
-
#### Test Coverage
|
|
75
|
-
- Added test case for custom relation names in implicit many-to-many relations
|
|
76
|
-
- Product/ProductTag models with `@relation("product_tags")`
|
|
77
|
-
- Validates correct table name generation (`_product_tags`)
|
|
78
|
-
- Location: `src/__tests__/fixtures/test.prisma:166-177`
|
|
40
|
+
#### Unused Enum Type Imports
|
|
41
|
+
- **types.ts now imports only Schema wrappers**: Eliminated TypeScript "declared but never read" warnings
|
|
42
|
+
- **Problem**: Generated `types.ts` imported both plain enum types (e.g., `BudgetStatus`) and schema wrappers (e.g., `BudgetStatusSchema`), but only schema wrappers were used
|
|
43
|
+
- **Solution**: Import generation now only includes `*Schema` wrappers
|
|
44
|
+
- **Impact**: Cleaner generated code, no TypeScript warnings
|
|
45
|
+
- Location: `src/effect/generator.ts:95-107`
|
|
79
46
|
|
|
80
47
|
### Technical Details
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
48
|
+
- **Quality Assurance**: All 165 tests passing (15 naming tests + 10 join table tests + 140 existing), zero TypeScript errors
|
|
49
|
+
- **Test Coverage**: New comprehensive tests for `toSnakeCase` utility and semantic join table column generation
|
|
50
|
+
- **Documentation**: Updated CLAUDE.md with join table naming behavior explanation
|
|
51
|
+
- **Research**: Verified snake_case follows Prisma generator best practices (community standard for database identifiers)
|
|
52
|
+
- **Backwards Compatible**: No breaking changes - existing queries continue to work
|
|
53
|
+
- **Effect Schema Integration**: Uses native `propertySignature` + `fromKey` pattern (official Effect Schema column mapping approach)
|
|
85
54
|
|
|
86
55
|
## [1.8.0] - 2025-10-12
|
|
87
56
|
|
|
@@ -4,10 +4,15 @@ import type { JoinTableInfo } from '../prisma/relation';
|
|
|
4
4
|
* Generate Effect Schema for an implicit many-to-many join table
|
|
5
5
|
*
|
|
6
6
|
* Structure:
|
|
7
|
-
* - Base schema with
|
|
7
|
+
* - Base schema with semantic snake_case field names mapped to A/B via fromKey
|
|
8
8
|
* - Operational schemas via getSchemas()
|
|
9
9
|
* - Type exports (Select, Insert, Update)
|
|
10
10
|
* - Encoded type exports
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* - Database columns: A, B (Prisma requirement)
|
|
14
|
+
* - TypeScript fields: product_id, product_tag_id (semantic snake_case)
|
|
15
|
+
* - Mapping: product_id → A, product_tag_id → B (via Schema.fromKey)
|
|
11
16
|
*/
|
|
12
17
|
export declare function generateJoinTableSchema(joinTable: JoinTableInfo, _dmmf: DMMF.Document): string;
|
|
13
18
|
//# sourceMappingURL=join-table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join-table.d.ts","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"join-table.d.ts","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAqBxD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,GAAG,MAAM,CAgD9F"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateJoinTableSchema = generateJoinTableSchema;
|
|
4
|
+
const naming_1 = require("../utils/naming");
|
|
4
5
|
/**
|
|
5
6
|
* Map join table column type to Effect Schema type
|
|
6
7
|
* Uses same mapping as regular fields
|
|
@@ -20,21 +21,32 @@ function mapColumnType(columnType, isUuid) {
|
|
|
20
21
|
* Generate Effect Schema for an implicit many-to-many join table
|
|
21
22
|
*
|
|
22
23
|
* Structure:
|
|
23
|
-
* - Base schema with
|
|
24
|
+
* - Base schema with semantic snake_case field names mapped to A/B via fromKey
|
|
24
25
|
* - Operational schemas via getSchemas()
|
|
25
26
|
* - Type exports (Select, Insert, Update)
|
|
26
27
|
* - Encoded type exports
|
|
28
|
+
*
|
|
29
|
+
* Example:
|
|
30
|
+
* - Database columns: A, B (Prisma requirement)
|
|
31
|
+
* - TypeScript fields: product_id, product_tag_id (semantic snake_case)
|
|
32
|
+
* - Mapping: product_id → A, product_tag_id → B (via Schema.fromKey)
|
|
27
33
|
*/
|
|
28
34
|
function generateJoinTableSchema(joinTable, _dmmf) {
|
|
29
|
-
const { tableName, relationName, columnAType, columnBType, columnAIsUuid, columnBIsUuid } = joinTable;
|
|
35
|
+
const { tableName, relationName, modelA, modelB, columnAType, columnBType, columnAIsUuid, columnBIsUuid, } = joinTable;
|
|
30
36
|
// Map column types to Effect Schema types
|
|
31
37
|
const columnASchema = mapColumnType(columnAType, columnAIsUuid);
|
|
32
38
|
const columnBSchema = mapColumnType(columnBType, columnBIsUuid);
|
|
39
|
+
// Generate semantic snake_case field names from model names
|
|
40
|
+
const columnAName = `${(0, naming_1.toSnakeCase)(modelA)}_id`;
|
|
41
|
+
const columnBName = `${(0, naming_1.toSnakeCase)(modelB)}_id`;
|
|
33
42
|
// Both columns are foreign keys, so use columnType for read-only behavior
|
|
34
|
-
|
|
35
|
-
const
|
|
43
|
+
// Use propertySignature with fromKey to map semantic names to actual A/B database columns
|
|
44
|
+
const columnAField = ` ${columnAName}: Schema.propertySignature(columnType(${columnASchema}, Schema.Never, Schema.Never)).pipe(Schema.fromKey("A"))`;
|
|
45
|
+
const columnBField = ` ${columnBName}: Schema.propertySignature(columnType(${columnBSchema}, Schema.Never, Schema.Never)).pipe(Schema.fromKey("B"))`;
|
|
36
46
|
// Generate base schema
|
|
37
47
|
const baseSchema = `// ${tableName} Join Table Schema
|
|
48
|
+
// Database columns: A (${modelA}), B (${modelB})
|
|
49
|
+
// TypeScript fields: ${columnAName}, ${columnBName}
|
|
38
50
|
export const _${relationName} = Schema.Struct({
|
|
39
51
|
${columnAField},
|
|
40
52
|
${columnBField},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"join-table.js","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"join-table.js","sourceRoot":"","sources":["../../src/effect/join-table.ts"],"names":[],"mappings":";;AAoCA,0DAgDC;AAlFD,4CAA8C;AAE9C;;;GAGG;AACH,SAAS,aAAa,CAAC,UAAkB,EAAE,MAAe;IACxD,IAAI,UAAU,KAAK,QAAQ,IAAI,MAAM,EAAE,CAAC;QACtC,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,MAAM,SAAS,GAA2B;QACxC,MAAM,EAAE,eAAe;QACvB,GAAG,EAAE,eAAe;QACpB,MAAM,EAAE,eAAe;KACxB,CAAC;IAEF,OAAO,SAAS,CAAC,UAAU,CAAC,IAAI,gBAAgB,CAAC;AACnD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,uBAAuB,CAAC,SAAwB,EAAE,KAAoB;IACpF,MAAM,EACJ,SAAS,EACT,YAAY,EACZ,MAAM,EACN,MAAM,EACN,WAAW,EACX,WAAW,EACX,aAAa,EACb,aAAa,GACd,GAAG,SAAS,CAAC;IAEd,0CAA0C;IAC1C,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAChE,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAEhE,4DAA4D;IAC5D,MAAM,WAAW,GAAG,GAAG,IAAA,oBAAW,EAAC,MAAM,CAAC,KAAK,CAAC;IAChD,MAAM,WAAW,GAAG,GAAG,IAAA,oBAAW,EAAC,MAAM,CAAC,KAAK,CAAC;IAEhD,0EAA0E;IAC1E,0FAA0F;IAC1F,MAAM,YAAY,GAAG,KAAK,WAAW,yCAAyC,aAAa,0DAA0D,CAAC;IACtJ,MAAM,YAAY,GAAG,KAAK,WAAW,yCAAyC,aAAa,0DAA0D,CAAC;IAEtJ,uBAAuB;IACvB,MAAM,UAAU,GAAG,MAAM,SAAS;0BACV,MAAM,SAAS,MAAM;wBACvB,WAAW,KAAK,WAAW;gBACnC,YAAY;EAC1B,YAAY;EACZ,YAAY;IACV,CAAC;IAEH,+BAA+B;IAC/B,MAAM,iBAAiB,GAAG,gBAAgB,YAAY,kBAAkB,YAAY,IAAI,CAAC;IAEzF,wBAAwB;IACxB,MAAM,WAAW,GAAG,eAAe,YAAY,sCAAsC,YAAY;cACrF,YAAY,sCAAsC,YAAY;cAC9D,YAAY,sCAAsC,YAAY,eAAe,CAAC;IAE1F,gCAAgC;IAChC,MAAM,cAAc,GAAG,eAAe,YAAY,gDAAgD,YAAY;cAClG,YAAY,gDAAgD,YAAY;cACxE,YAAY,gDAAgD,YAAY,eAAe,CAAC;IAEpG,OAAO,GAAG,UAAU,OAAO,iBAAiB,OAAO,WAAW,KAAK,cAAc,EAAE,CAAC;AACtF,CAAC"}
|
package/dist/utils/naming.d.ts
CHANGED
|
@@ -15,4 +15,16 @@
|
|
|
15
15
|
* toPascalCase('USER_ROLE', 'Type') // 'UserRoleType'
|
|
16
16
|
*/
|
|
17
17
|
export declare function toPascalCase(str: string, suffix?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Convert PascalCase or camelCase string to snake_case
|
|
20
|
+
* Used for generating database column names from model names
|
|
21
|
+
*
|
|
22
|
+
* @param str - The string to convert
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* toSnakeCase('User') // 'user'
|
|
26
|
+
* toSnakeCase('ProductTag') // 'product_tag'
|
|
27
|
+
* toSnakeCase('ProductStatus') // 'product_status'
|
|
28
|
+
*/
|
|
29
|
+
export declare function toSnakeCase(str: string): string;
|
|
18
30
|
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/utils/naming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA8BjE"}
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/utils/naming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA8BjE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAY/C"}
|
package/dist/utils/naming.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.toPascalCase = toPascalCase;
|
|
7
|
+
exports.toSnakeCase = toSnakeCase;
|
|
7
8
|
/**
|
|
8
9
|
* Convert any string to PascalCase with optional suffix
|
|
9
10
|
* Handles: snake_case, camelCase, kebab-case, or mixed formats
|
|
@@ -47,4 +48,26 @@ function toPascalCase(str, suffix) {
|
|
|
47
48
|
}
|
|
48
49
|
return suffix ? `${pascalCase}${suffix}` : pascalCase;
|
|
49
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Convert PascalCase or camelCase string to snake_case
|
|
53
|
+
* Used for generating database column names from model names
|
|
54
|
+
*
|
|
55
|
+
* @param str - The string to convert
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* toSnakeCase('User') // 'user'
|
|
59
|
+
* toSnakeCase('ProductTag') // 'product_tag'
|
|
60
|
+
* toSnakeCase('ProductStatus') // 'product_status'
|
|
61
|
+
*/
|
|
62
|
+
function toSnakeCase(str) {
|
|
63
|
+
if (!str)
|
|
64
|
+
return str;
|
|
65
|
+
return (str
|
|
66
|
+
// Insert underscore before uppercase letters (except at start)
|
|
67
|
+
.replace(/([A-Z])/g, '_$1')
|
|
68
|
+
// Remove leading underscore if present
|
|
69
|
+
.replace(/^_/, '')
|
|
70
|
+
// Convert to lowercase
|
|
71
|
+
.toLowerCase());
|
|
72
|
+
}
|
|
50
73
|
//# sourceMappingURL=naming.js.map
|
package/dist/utils/naming.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../../src/utils/naming.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAeH,oCA8BC;
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../../src/utils/naming.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAeH,oCA8BC;AAaD,kCAYC;AApED;;;;;;;;;;;;GAYG;AACH,SAAgB,YAAY,CAAC,GAAW,EAAE,MAAe;IACvD,sBAAsB;IACtB,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IAErB,0CAA0C;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAEnC,IAAI,UAAkB,CAAC;IAEvB,gEAAgE;IAChE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,gDAAgD;QAChD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC1C,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,UAAU,GAAG,UAAU;iBACpB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;iBACzE,IAAI,CAAC,EAAE,CAAC,CAAC;QACd,CAAC;aAAM,CAAC;YACN,6CAA6C;YAC7C,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,kCAAkC;QAClC,UAAU,GAAG,KAAK;aACf,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,uBAAuB;aACzD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;aACzE,IAAI,CAAC,EAAE,CAAC,CAAC;IACd,CAAC;IAED,OAAO,MAAM,CAAC,CAAC,CAAC,GAAG,UAAU,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;AACxD,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC,GAAG;QAAE,OAAO,GAAG,CAAC;IAErB,OAAO,CACL,GAAG;QACD,+DAA+D;SAC9D,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;QAC3B,uCAAuC;SACtC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAClB,uBAAuB;SACtB,WAAW,EAAE,CACjB,CAAC;AACJ,CAAC"}
|