cloesce 0.0.4-unstable.4 → 0.0.4-unstable.6
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 +122 -152
- package/dist/cli.js +26 -14
- package/dist/common.d.ts +14 -50
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +42 -22
- package/dist/extractor/extract.d.ts.map +1 -1
- package/dist/extractor/extract.js +44 -47
- package/dist/generator.wasm +0 -0
- package/dist/orm.wasm +0 -0
- package/dist/router/crud.d.ts.map +1 -1
- package/dist/router/crud.js +16 -11
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +25 -24
- package/dist/router/wasm.d.ts +9 -2
- package/dist/router/wasm.d.ts.map +1 -1
- package/dist/router/wasm.js +11 -5
- package/dist/ui/backend.d.ts +142 -84
- package/dist/ui/backend.d.ts.map +1 -1
- package/dist/ui/backend.js +176 -130
- package/package.json +1 -1
package/dist/common.js
CHANGED
|
@@ -107,28 +107,48 @@ export class ExtractorError {
|
|
|
107
107
|
this.context = fn(this.context ?? "");
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
110
|
+
export class Either {
|
|
111
|
+
inner;
|
|
112
|
+
constructor(inner) {
|
|
113
|
+
this.inner = inner;
|
|
114
|
+
}
|
|
115
|
+
get value() {
|
|
116
|
+
return this.inner.ok ? this.inner.right : this.inner.left;
|
|
117
|
+
}
|
|
118
|
+
static left(value) {
|
|
119
|
+
return new Either({ ok: false, left: value });
|
|
120
|
+
}
|
|
121
|
+
static right(value) {
|
|
122
|
+
return new Either({ ok: true, right: value });
|
|
123
|
+
}
|
|
124
|
+
isLeft() {
|
|
125
|
+
return !this.inner.ok;
|
|
126
|
+
}
|
|
127
|
+
isRight() {
|
|
128
|
+
return this.inner.ok;
|
|
129
|
+
}
|
|
130
|
+
unwrap() {
|
|
131
|
+
if (!this.inner.ok) {
|
|
132
|
+
throw new Error("Tried to unwrap a Left value");
|
|
133
|
+
}
|
|
134
|
+
return this.inner.right;
|
|
135
|
+
}
|
|
136
|
+
unwrapLeft() {
|
|
137
|
+
if (this.inner.ok) {
|
|
138
|
+
throw new Error("Tried to unwrapLeft a Right value");
|
|
139
|
+
}
|
|
140
|
+
return this.inner.left;
|
|
141
|
+
}
|
|
142
|
+
map(fn) {
|
|
143
|
+
return this.inner.ok
|
|
144
|
+
? Either.right(fn(this.inner.right))
|
|
145
|
+
: Either.left(this.inner.left);
|
|
146
|
+
}
|
|
147
|
+
mapLeft(fn) {
|
|
148
|
+
return this.inner.ok
|
|
149
|
+
? Either.right(this.inner.right)
|
|
150
|
+
: Either.left(fn(this.inner.left));
|
|
151
|
+
}
|
|
132
152
|
}
|
|
133
153
|
/**
|
|
134
154
|
* Represents the core middleware container for a Cloesce application.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extractor/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,IAAI,EACJ,UAAU,EAEV,iBAAiB,EAEjB,gBAAgB,EAEhB,UAAU,EAEX,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EAER,MAAM,EACN,QAAQ,EACR,KAAK,EAEL,WAAW,EAGX,WAAW,
|
|
1
|
+
{"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../src/extractor/extract.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,OAAO,EACP,IAAI,EACJ,UAAU,EAEV,iBAAiB,EAEjB,gBAAgB,EAEhB,UAAU,EAEX,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,eAAe,EACf,UAAU,EACV,QAAQ,EAER,MAAM,EACN,QAAQ,EACR,KAAK,EAEL,WAAW,EAGX,WAAW,EACX,cAAc,EAEd,cAAc,EAGf,MAAM,cAAc,CAAC;AAuBtB,qBAAa,aAAa;IAEf,WAAW,EAAE,MAAM;IACnB,OAAO,EAAE,MAAM;gBADf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM;IAGxB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,cAAc,EAAE,UAAU,CAAC;IA8F7D,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC;IA8BlE,MAAM,CAAC,KAAK,CACV,SAAS,EAAE,gBAAgB,EAC3B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC;IAgQhC,MAAM,CAAC,GAAG,CACR,SAAS,EAAE,gBAAgB,EAC3B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC;IAmCzC,MAAM,CAAC,GAAG,CACR,SAAS,EAAE,gBAAgB,EAC3B,UAAU,EAAE,UAAU,GACrB,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC;IAuBtC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CASjC;IAEF,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,IAAI,EACV,MAAM,GAAE,OAAe,GACtB,MAAM,CAAC,cAAc,EAAE,QAAQ,CAAC;IAkJnC,MAAM,CAAC,WAAW,CAChB,IAAI,EAAE,UAAU,GAAG,SAAS,EAC5B,YAAY,EAAE,gBAAgB,EAC9B,EAAE,EAAE,UAAU,GACb,MAAM,CAAC,cAAc,EAAE,eAAe,CAAC;IAiF1C,MAAM,CAAC,MAAM,CACX,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC;CA0EvC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Node as MorphNode, SyntaxKind, Scope, } from "ts-morph";
|
|
2
|
-
import {
|
|
2
|
+
import { Either, HttpVerb, ExtractorError, ExtractorErrorCode, CloesceApp, } from "../common.js";
|
|
3
3
|
import { TypeFormatFlags } from "typescript";
|
|
4
4
|
var AttributeDecoratorKind;
|
|
5
5
|
(function (AttributeDecoratorKind) {
|
|
@@ -38,10 +38,10 @@ export class CidlExtractor {
|
|
|
38
38
|
sourceFile.getBaseName() === "seed__app.cloesce.ts" // hardcoding for tests
|
|
39
39
|
) {
|
|
40
40
|
const app = CidlExtractor.app(sourceFile);
|
|
41
|
-
if (
|
|
41
|
+
if (app.isLeft()) {
|
|
42
42
|
return app;
|
|
43
43
|
}
|
|
44
|
-
app_source = app.
|
|
44
|
+
app_source = app.unwrap();
|
|
45
45
|
}
|
|
46
46
|
for (const classDecl of sourceFile.getClasses()) {
|
|
47
47
|
const notExportedErr = err(ExtractorErrorCode.MissingExport, (e) => {
|
|
@@ -53,11 +53,11 @@ export class CidlExtractor {
|
|
|
53
53
|
return notExportedErr;
|
|
54
54
|
const result = CidlExtractor.model(classDecl, sourceFile);
|
|
55
55
|
// Error: propogate from models
|
|
56
|
-
if (
|
|
56
|
+
if (result.isLeft()) {
|
|
57
57
|
result.value.addContext((prev) => `${classDecl.getName()}.${prev}`);
|
|
58
58
|
return result;
|
|
59
59
|
}
|
|
60
|
-
models[result.
|
|
60
|
+
models[result.unwrap().name] = result.unwrap();
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
63
|
if (hasDecorator(classDecl, ClassDecoratorKind.PlainOldObject)) {
|
|
@@ -65,11 +65,11 @@ export class CidlExtractor {
|
|
|
65
65
|
return notExportedErr;
|
|
66
66
|
const result = CidlExtractor.poo(classDecl, sourceFile);
|
|
67
67
|
// Error: propogate from models
|
|
68
|
-
if (
|
|
68
|
+
if (result.isLeft()) {
|
|
69
69
|
result.value.addContext((prev) => `${classDecl.getName()}.${prev}`);
|
|
70
70
|
return result;
|
|
71
71
|
}
|
|
72
|
-
poos[result.
|
|
72
|
+
poos[result.unwrap().name] = result.unwrap();
|
|
73
73
|
continue;
|
|
74
74
|
}
|
|
75
75
|
if (hasDecorator(classDecl, ClassDecoratorKind.WranglerEnv)) {
|
|
@@ -81,10 +81,10 @@ export class CidlExtractor {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
const result = CidlExtractor.env(classDecl, sourceFile);
|
|
84
|
-
if (
|
|
84
|
+
if (result.isLeft()) {
|
|
85
85
|
return result;
|
|
86
86
|
}
|
|
87
|
-
wranglerEnvs.push(result.
|
|
87
|
+
wranglerEnvs.push(result.unwrap());
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -96,7 +96,7 @@ export class CidlExtractor {
|
|
|
96
96
|
if (wranglerEnvs.length > 1) {
|
|
97
97
|
return err(ExtractorErrorCode.TooManyWranglerEnvs, (e) => (e.context = wranglerEnvs.map((w) => w.name).toString()));
|
|
98
98
|
}
|
|
99
|
-
return right({
|
|
99
|
+
return Either.right({
|
|
100
100
|
version: this.version,
|
|
101
101
|
project_name: this.projectName,
|
|
102
102
|
language: "TypeScript",
|
|
@@ -124,7 +124,7 @@ export class CidlExtractor {
|
|
|
124
124
|
};
|
|
125
125
|
const typeText = getTypeText();
|
|
126
126
|
if (typeText === CloesceApp.name) {
|
|
127
|
-
return right(sourceFile.getFilePath().toString());
|
|
127
|
+
return Either.right(sourceFile.getFilePath().toString());
|
|
128
128
|
}
|
|
129
129
|
return err(ExtractorErrorCode.AppMissingDefaultExport);
|
|
130
130
|
}
|
|
@@ -148,7 +148,7 @@ export class CidlExtractor {
|
|
|
148
148
|
const decorators = prop.getDecorators();
|
|
149
149
|
const typeRes = CidlExtractor.cidlType(prop.getType());
|
|
150
150
|
// Error: invalid property type
|
|
151
|
-
if (
|
|
151
|
+
if (typeRes.isLeft()) {
|
|
152
152
|
typeRes.value.context = prop.getName();
|
|
153
153
|
typeRes.value.snippet = prop.getText();
|
|
154
154
|
return typeRes;
|
|
@@ -160,7 +160,7 @@ export class CidlExtractor {
|
|
|
160
160
|
if (checkModifierRes !== undefined) {
|
|
161
161
|
return checkModifierRes;
|
|
162
162
|
}
|
|
163
|
-
const cidl_type = typeRes.
|
|
163
|
+
const cidl_type = typeRes.unwrap();
|
|
164
164
|
attributes.push({
|
|
165
165
|
foreign_key_reference: null,
|
|
166
166
|
value: {
|
|
@@ -179,7 +179,7 @@ export class CidlExtractor {
|
|
|
179
179
|
return checkModifierRes;
|
|
180
180
|
}
|
|
181
181
|
// Process decorator
|
|
182
|
-
const cidl_type = typeRes.
|
|
182
|
+
const cidl_type = typeRes.unwrap();
|
|
183
183
|
switch (decoratorName) {
|
|
184
184
|
case AttributeDecoratorKind.PrimaryKey: {
|
|
185
185
|
primary_key = {
|
|
@@ -282,14 +282,14 @@ export class CidlExtractor {
|
|
|
282
282
|
}
|
|
283
283
|
const initializer = prop.getInitializer();
|
|
284
284
|
const treeRes = CidlExtractor.includeTree(initializer, classDecl, sourceFile);
|
|
285
|
-
if (
|
|
285
|
+
if (treeRes.isLeft()) {
|
|
286
286
|
treeRes.value.addContext((prev) => `${prop.getName()} ${prev}`);
|
|
287
287
|
treeRes.value.snippet = prop.getText();
|
|
288
288
|
return treeRes;
|
|
289
289
|
}
|
|
290
290
|
data_sources[prop.getName()] = {
|
|
291
291
|
name: prop.getName(),
|
|
292
|
-
tree: treeRes.
|
|
292
|
+
tree: treeRes.unwrap(),
|
|
293
293
|
};
|
|
294
294
|
break;
|
|
295
295
|
}
|
|
@@ -310,13 +310,13 @@ export class CidlExtractor {
|
|
|
310
310
|
continue;
|
|
311
311
|
}
|
|
312
312
|
const result = CidlExtractor.method(name, m, httpVerb);
|
|
313
|
-
if (
|
|
313
|
+
if (result.isLeft()) {
|
|
314
314
|
result.value.addContext((prev) => `${m.getName()} ${prev}`);
|
|
315
|
-
return
|
|
315
|
+
return result;
|
|
316
316
|
}
|
|
317
|
-
methods[result.
|
|
317
|
+
methods[result.unwrap().name] = result.unwrap();
|
|
318
318
|
}
|
|
319
|
-
return right({
|
|
319
|
+
return Either.right({
|
|
320
320
|
name,
|
|
321
321
|
attributes,
|
|
322
322
|
primary_key,
|
|
@@ -333,7 +333,7 @@ export class CidlExtractor {
|
|
|
333
333
|
for (const prop of classDecl.getProperties()) {
|
|
334
334
|
const typeRes = CidlExtractor.cidlType(prop.getType());
|
|
335
335
|
// Error: invalid property type
|
|
336
|
-
if (
|
|
336
|
+
if (typeRes.isLeft()) {
|
|
337
337
|
typeRes.value.context = prop.getName();
|
|
338
338
|
typeRes.value.snippet = prop.getText();
|
|
339
339
|
return typeRes;
|
|
@@ -343,14 +343,14 @@ export class CidlExtractor {
|
|
|
343
343
|
if (modifierRes) {
|
|
344
344
|
return modifierRes;
|
|
345
345
|
}
|
|
346
|
-
const cidl_type = typeRes.
|
|
346
|
+
const cidl_type = typeRes.unwrap();
|
|
347
347
|
attributes.push({
|
|
348
348
|
name: prop.getName(),
|
|
349
349
|
cidl_type,
|
|
350
350
|
});
|
|
351
351
|
continue;
|
|
352
352
|
}
|
|
353
|
-
return right({
|
|
353
|
+
return Either.right({
|
|
354
354
|
name,
|
|
355
355
|
attributes,
|
|
356
356
|
source_path: sourceFile.getFilePath().toString(),
|
|
@@ -365,7 +365,7 @@ export class CidlExtractor {
|
|
|
365
365
|
if (!binding) {
|
|
366
366
|
return err(ExtractorErrorCode.MissingDatabaseBinding);
|
|
367
367
|
}
|
|
368
|
-
return right({
|
|
368
|
+
return Either.right({
|
|
369
369
|
name: classDecl.getName(),
|
|
370
370
|
source_path: sourceFile.getFilePath().toString(),
|
|
371
371
|
db_binding: binding.getName(),
|
|
@@ -384,11 +384,11 @@ export class CidlExtractor {
|
|
|
384
384
|
static cidlType(type, inject = false) {
|
|
385
385
|
// Void
|
|
386
386
|
if (type.isVoid()) {
|
|
387
|
-
return right("Void");
|
|
387
|
+
return Either.right("Void");
|
|
388
388
|
}
|
|
389
389
|
// Null
|
|
390
390
|
if (type.isNull()) {
|
|
391
|
-
return right({ Nullable: "Void" });
|
|
391
|
+
return Either.right({ Nullable: "Void" });
|
|
392
392
|
}
|
|
393
393
|
// Nullable via union
|
|
394
394
|
const [unwrappedType, nullable] = unwrapNullable(type);
|
|
@@ -399,7 +399,7 @@ export class CidlExtractor {
|
|
|
399
399
|
// Primitives
|
|
400
400
|
const prim = this.primTypeMap[tyText];
|
|
401
401
|
if (prim) {
|
|
402
|
-
return right(wrapNullable(prim, nullable));
|
|
402
|
+
return Either.right(wrapNullable(prim, nullable));
|
|
403
403
|
}
|
|
404
404
|
const generics = [
|
|
405
405
|
...unwrappedType.getAliasTypeArguments(),
|
|
@@ -412,14 +412,14 @@ export class CidlExtractor {
|
|
|
412
412
|
// No generics -> inject or object
|
|
413
413
|
if (generics.length === 0) {
|
|
414
414
|
const base = inject ? { Inject: tyText } : { Object: tyText };
|
|
415
|
-
return right(wrapNullable(base, nullable));
|
|
415
|
+
return Either.right(wrapNullable(base, nullable));
|
|
416
416
|
}
|
|
417
417
|
// Single generic
|
|
418
418
|
const genericTy = generics[0];
|
|
419
419
|
const symbolName = unwrappedType.getSymbol()?.getName();
|
|
420
420
|
const aliasName = unwrappedType.getAliasSymbol()?.getName();
|
|
421
421
|
if (aliasName === "DataSourceOf") {
|
|
422
|
-
return right(wrapNullable({
|
|
422
|
+
return Either.right(wrapNullable({
|
|
423
423
|
DataSource: genericTy.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope),
|
|
424
424
|
}, nullable));
|
|
425
425
|
}
|
|
@@ -435,7 +435,7 @@ export class CidlExtractor {
|
|
|
435
435
|
genericTyGenerics.length > 0) {
|
|
436
436
|
return err(ExtractorErrorCode.InvalidPartialType);
|
|
437
437
|
}
|
|
438
|
-
return right(wrapNullable({
|
|
438
|
+
return Either.right(wrapNullable({
|
|
439
439
|
Partial: genericTy
|
|
440
440
|
.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope)
|
|
441
441
|
.split("|")[0]
|
|
@@ -466,10 +466,7 @@ export class CidlExtractor {
|
|
|
466
466
|
function wrapGeneric(t, isNullable, wrapper) {
|
|
467
467
|
const res = CidlExtractor.cidlType(t, inject);
|
|
468
468
|
// Error: propogated from `cidlType`
|
|
469
|
-
|
|
470
|
-
return res;
|
|
471
|
-
}
|
|
472
|
-
return right(wrapNullable(wrapper(res.value), isNullable));
|
|
469
|
+
return res.map((inner) => wrapNullable(wrapper(inner), isNullable));
|
|
473
470
|
}
|
|
474
471
|
function unwrapNullable(ty) {
|
|
475
472
|
if (!ty.isUnion())
|
|
@@ -506,13 +503,13 @@ export class CidlExtractor {
|
|
|
506
503
|
}
|
|
507
504
|
const typeRes = CidlExtractor.cidlType(navProp.getType());
|
|
508
505
|
// Error: invalid referenced nav prop type
|
|
509
|
-
if (
|
|
506
|
+
if (typeRes.isLeft()) {
|
|
510
507
|
typeRes.value.snippet = navProp.getText();
|
|
511
508
|
typeRes.value.context = prop.getName();
|
|
512
509
|
return typeRes;
|
|
513
510
|
}
|
|
514
511
|
// Error: invalid referenced nav prop type
|
|
515
|
-
const cidl_type = typeRes.
|
|
512
|
+
const cidl_type = typeRes.unwrap();
|
|
516
513
|
if (typeof cidl_type === "string") {
|
|
517
514
|
return err(ExtractorErrorCode.InvalidNavigationPropertyReference, (e) => {
|
|
518
515
|
((e.snippet = navProp.getText()), (e.context = prop.getName()));
|
|
@@ -532,16 +529,16 @@ export class CidlExtractor {
|
|
|
532
529
|
if (targetClass) {
|
|
533
530
|
const treeRes = CidlExtractor.includeTree(initializer, targetClass, sf);
|
|
534
531
|
// Error: Propogated from `includeTree`
|
|
535
|
-
if (
|
|
532
|
+
if (treeRes.isLeft()) {
|
|
536
533
|
treeRes.value.snippet = expr.getText();
|
|
537
534
|
return treeRes;
|
|
538
535
|
}
|
|
539
|
-
nestedTree = treeRes.
|
|
536
|
+
nestedTree = treeRes.unwrap();
|
|
540
537
|
}
|
|
541
538
|
}
|
|
542
539
|
result[navProp.getName()] = nestedTree;
|
|
543
540
|
}
|
|
544
|
-
return right(result);
|
|
541
|
+
return Either.right(result);
|
|
545
542
|
}
|
|
546
543
|
static method(modelName, method, httpVerb) {
|
|
547
544
|
// Error: invalid method scope, must be public
|
|
@@ -558,21 +555,21 @@ export class CidlExtractor {
|
|
|
558
555
|
if (param.getDecorator(ParameterDecoratorKind.Inject)) {
|
|
559
556
|
const typeRes = CidlExtractor.cidlType(param.getType(), true);
|
|
560
557
|
// Error: invalid type
|
|
561
|
-
if (
|
|
558
|
+
if (typeRes.isLeft()) {
|
|
562
559
|
typeRes.value.snippet = method.getText();
|
|
563
560
|
typeRes.value.context = param.getName();
|
|
564
561
|
return typeRes;
|
|
565
562
|
}
|
|
566
563
|
parameters.push({
|
|
567
564
|
name: param.getName(),
|
|
568
|
-
cidl_type: typeRes.
|
|
565
|
+
cidl_type: typeRes.unwrap(),
|
|
569
566
|
});
|
|
570
567
|
continue;
|
|
571
568
|
}
|
|
572
569
|
// Handle all other params
|
|
573
570
|
const typeRes = CidlExtractor.cidlType(param.getType());
|
|
574
571
|
// Error: invalid type
|
|
575
|
-
if (
|
|
572
|
+
if (typeRes.isLeft()) {
|
|
576
573
|
typeRes.value.snippet = method.getText();
|
|
577
574
|
typeRes.value.context = param.getName();
|
|
578
575
|
return typeRes;
|
|
@@ -582,12 +579,12 @@ export class CidlExtractor {
|
|
|
582
579
|
}
|
|
583
580
|
parameters.push({
|
|
584
581
|
name: param.getName(),
|
|
585
|
-
cidl_type: typeRes.
|
|
582
|
+
cidl_type: typeRes.unwrap(),
|
|
586
583
|
});
|
|
587
584
|
}
|
|
588
585
|
const typeRes = CidlExtractor.cidlType(method.getReturnType());
|
|
589
586
|
// Error: invalid type
|
|
590
|
-
if (
|
|
587
|
+
if (typeRes.isLeft()) {
|
|
591
588
|
typeRes.value.snippet = method.getText();
|
|
592
589
|
return typeRes;
|
|
593
590
|
}
|
|
@@ -598,11 +595,11 @@ export class CidlExtractor {
|
|
|
598
595
|
cidl_type: { DataSource: modelName },
|
|
599
596
|
});
|
|
600
597
|
}
|
|
601
|
-
return right({
|
|
598
|
+
return Either.right({
|
|
602
599
|
name: method.getName(),
|
|
603
600
|
is_static: method.isStatic(),
|
|
604
601
|
http_verb: httpVerb,
|
|
605
|
-
return_type: typeRes.
|
|
602
|
+
return_type: typeRes.unwrap(),
|
|
606
603
|
parameters,
|
|
607
604
|
});
|
|
608
605
|
}
|
|
@@ -612,7 +609,7 @@ function err(code, fn) {
|
|
|
612
609
|
if (fn) {
|
|
613
610
|
fn(e);
|
|
614
611
|
}
|
|
615
|
-
return left(e);
|
|
612
|
+
return Either.left(e);
|
|
616
613
|
}
|
|
617
614
|
function getDecoratorName(decorator) {
|
|
618
615
|
const name = decorator.getName() ?? decorator.getExpression().getText();
|
package/dist/generator.wasm
CHANGED
|
Binary file
|
package/dist/orm.wasm
CHANGED
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/router/crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAC;AAG1D;;GAEG;AACH,qBAAa,WAAW;IAEpB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,IAAI;IAHd,OAAO;IAMP,MAAM,CAAC,YAAY,CACjB,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,GAAG,EACb,IAAI,EAAE,UAAU,MAAM,GACrB,WAAW;IAId,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,MAAM,GAAG,WAAW;IAIpE;;;OAGG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ;IAWrC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"crud.d.ts","sourceRoot":"","sources":["../../src/router/crud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAkB,MAAM,cAAc,CAAC;AAG1D;;GAEG;AACH,qBAAa,WAAW;IAEpB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,IAAI;IAHd,OAAO;IAMP,MAAM,CAAC,YAAY,CACjB,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,GAAG,EACb,IAAI,EAAE,UAAU,MAAM,GACrB,WAAW;IAId,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,MAAM,GAAG,WAAW;IAIpE;;;OAGG;IACH,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ;IAWrC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAiBrE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAU9D,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;CAW7D"}
|
package/dist/router/crud.js
CHANGED
|
@@ -32,34 +32,39 @@ export class CrudContext {
|
|
|
32
32
|
return fn ? fn.bind(this.instance) : map[methodName];
|
|
33
33
|
}
|
|
34
34
|
async upsert(obj, dataSource) {
|
|
35
|
-
const
|
|
36
|
-
const includeTree = normalizedDs ? this.ctor[normalizedDs] : null;
|
|
35
|
+
const includeTree = findIncludeTree(dataSource, this.ctor);
|
|
37
36
|
// Upsert
|
|
38
37
|
const orm = Orm.fromD1(this.d1);
|
|
39
38
|
const upsert = await orm.upsert(this.ctor, obj, includeTree);
|
|
40
|
-
if (
|
|
39
|
+
if (upsert.isLeft()) {
|
|
41
40
|
return { ok: false, status: 500, data: upsert.value }; // TODO: better status code?
|
|
42
41
|
}
|
|
43
42
|
// Get
|
|
44
|
-
const get = await orm.get(this.ctor, upsert.value,
|
|
45
|
-
return get.
|
|
43
|
+
const get = await orm.get(this.ctor, upsert.value, includeTree);
|
|
44
|
+
return get.isRight()
|
|
46
45
|
? { ok: true, status: 200, data: get.value }
|
|
47
46
|
: { ok: false, status: 500, data: get.value };
|
|
48
47
|
}
|
|
49
48
|
async get(id, dataSource) {
|
|
50
|
-
const
|
|
49
|
+
const includeTree = findIncludeTree(dataSource, this.ctor);
|
|
51
50
|
const orm = Orm.fromD1(this.d1);
|
|
52
|
-
const res = await orm.get(this.ctor, id,
|
|
53
|
-
return res.
|
|
51
|
+
const res = await orm.get(this.ctor, id, includeTree);
|
|
52
|
+
return res.isRight()
|
|
54
53
|
? { ok: true, status: 200, data: res.value }
|
|
55
54
|
: { ok: false, status: 500, data: res.value };
|
|
56
55
|
}
|
|
57
56
|
async list(dataSource) {
|
|
58
|
-
const
|
|
57
|
+
const includeTree = findIncludeTree(dataSource, this.ctor);
|
|
59
58
|
const orm = Orm.fromD1(this.d1);
|
|
60
|
-
const res = await orm.list(this.ctor,
|
|
61
|
-
|
|
59
|
+
const res = await orm.list(this.ctor, {
|
|
60
|
+
includeTree,
|
|
61
|
+
});
|
|
62
|
+
return res.isRight()
|
|
62
63
|
? { ok: true, status: 200, data: res.value }
|
|
63
64
|
: { ok: false, status: 500, data: res.value };
|
|
64
65
|
}
|
|
65
66
|
}
|
|
67
|
+
function findIncludeTree(dataSource, ctor) {
|
|
68
|
+
const normalizedDs = dataSource === NO_DATA_SOURCE ? null : dataSource;
|
|
69
|
+
return normalizedDs ? ctor[normalizedDs] : null;
|
|
70
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,MAAM,EACN,WAAW,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/router/router.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,MAAM,EACN,WAAW,EAEX,UAAU,EAEV,KAAK,EAGL,UAAU,EACV,gBAAgB,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAuB,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAGxC;;;;;GAKG;AACH,KAAK,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,CAAC,CAAC;AAE9D;;;GAGG;AACH,KAAK,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/C;;GAEG;AACH,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;aAGT,GAAG,EAAE,UAAU;aACf,mBAAmB,EAAE,wBAAwB;aAC7C,IAAI,EAAE,cAAc;IAJtC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA+B;IACtD,OAAO;WAMM,IAAI,CACf,GAAG,EAAE,UAAU,EACf,mBAAmB,EAAE,wBAAwB,EAC7C,IAAI,CAAC,EAAE,WAAW,CAAC,QAAQ;IAO7B,MAAM,CAAC,GAAG,IAAI,gBAAgB;CAG/B;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,UAAU,EACf,mBAAmB,EAAE,wBAAwB,EAC7C,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,QAAQ,CAAC,CAmFnB;AAED;;;;GAIG;AACH,iBAAS,UAAU,CACjB,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CACP,UAAU,EACV;IACE,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACnB,CACF,CAyCA;AAED;;;;GAIG;AACH,iBAAe,eAAe,CAC5B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,UAAU,EACf,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,WAAW,EACnB,EAAE,EAAE,MAAM,GAAG,IAAI,GAChB,OAAO,CACR,MAAM,CAAC,UAAU,EAAE;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAC3E,CA4DA;AAgED;;;GAGG;AACH,iBAAe,cAAc,CAC3B,OAAO,EAAE,WAAW,EACpB,gBAAgB,EAAE,gBAAgB,EAClC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAkD9B;AAoID;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;;CAK5B,CAAC"}
|
package/dist/router/router.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Either, isNullableType, getNavigationPropertyCidlType, NO_DATA_SOURCE, } from "../common.js";
|
|
2
2
|
import { mapSql, loadOrmWasm } from "./wasm.js";
|
|
3
3
|
import { CrudContext } from "./crud.js";
|
|
4
|
+
import { Orm } from "../ui/backend.js";
|
|
4
5
|
/**
|
|
5
6
|
* Singleton instance containing the cidl, constructor registry, and wasm binary.
|
|
6
7
|
* These values are guaranteed to never change throughout a workers lifetime.
|
|
@@ -49,10 +50,10 @@ export async function cloesce(request, env, ast, app, constructorRegistry, envMe
|
|
|
49
50
|
//#endregion
|
|
50
51
|
//#region Match the route to a model method
|
|
51
52
|
const route = matchRoute(request, ast, apiRoute);
|
|
52
|
-
if (
|
|
53
|
+
if (route.isLeft()) {
|
|
53
54
|
return toResponse(route.value);
|
|
54
55
|
}
|
|
55
|
-
const { method, model, id } = route.
|
|
56
|
+
const { method, model, id } = route.unwrap();
|
|
56
57
|
//#endregion
|
|
57
58
|
//#region Model Middleware
|
|
58
59
|
for (const m of app.model.get(model.name) ?? []) {
|
|
@@ -64,10 +65,10 @@ export async function cloesce(request, env, ast, app, constructorRegistry, envMe
|
|
|
64
65
|
//#endregion
|
|
65
66
|
//#region Validate request body to the model method
|
|
66
67
|
const validation = await validateRequest(request, ast, model, method, id);
|
|
67
|
-
if (
|
|
68
|
+
if (validation.isLeft()) {
|
|
68
69
|
return toResponse(validation.value);
|
|
69
70
|
}
|
|
70
|
-
const { params, dataSource } = validation.
|
|
71
|
+
const { params, dataSource } = validation.unwrap();
|
|
71
72
|
//#endregion
|
|
72
73
|
//#region Method Middleware
|
|
73
74
|
for (const m of app.method.get(model.name)?.get(method.name) ?? []) {
|
|
@@ -80,20 +81,17 @@ export async function cloesce(request, env, ast, app, constructorRegistry, envMe
|
|
|
80
81
|
//#region Instantatiate the model
|
|
81
82
|
const crudCtx = await (async () => {
|
|
82
83
|
if (method.is_static) {
|
|
83
|
-
return right(CrudContext.fromCtor(d1, constructorRegistry[model.name]));
|
|
84
|
+
return Either.right(CrudContext.fromCtor(d1, constructorRegistry[model.name]));
|
|
84
85
|
}
|
|
85
86
|
const hydratedModel = await hydrateModel(constructorRegistry, d1, model, id, // id must exist after matchRoute
|
|
86
87
|
dataSource);
|
|
87
|
-
|
|
88
|
-
return hydratedModel;
|
|
89
|
-
}
|
|
90
|
-
return right(CrudContext.fromInstance(d1, hydratedModel.value, constructorRegistry[model.name]));
|
|
88
|
+
return hydratedModel.map((_) => CrudContext.fromInstance(d1, hydratedModel.value, constructorRegistry[model.name]));
|
|
91
89
|
})();
|
|
92
|
-
if (
|
|
90
|
+
if (crudCtx.isLeft()) {
|
|
93
91
|
return toResponse(crudCtx.value);
|
|
94
92
|
}
|
|
95
93
|
//#endregion
|
|
96
|
-
return toResponse(await methodDispatch(crudCtx.
|
|
94
|
+
return toResponse(await methodDispatch(crudCtx.unwrap(), ir, method, params));
|
|
97
95
|
}
|
|
98
96
|
/**
|
|
99
97
|
* Matches a request to a method on a model.
|
|
@@ -104,7 +102,7 @@ function matchRoute(request, ast, apiRoute) {
|
|
|
104
102
|
const url = new URL(request.url);
|
|
105
103
|
// Error state: We expect an exact request format, and expect that the model
|
|
106
104
|
// and are apart of the CIDL
|
|
107
|
-
const notFound = (e) => left(errorState(404, `Path not found: ${e} ${url.pathname}`));
|
|
105
|
+
const notFound = (e) => Either.left(errorState(404, `Path not found: ${e} ${url.pathname}`));
|
|
108
106
|
const routeParts = url.pathname
|
|
109
107
|
.slice(apiRoute.length)
|
|
110
108
|
.split("/")
|
|
@@ -127,7 +125,7 @@ function matchRoute(request, ast, apiRoute) {
|
|
|
127
125
|
if (request.method !== method.http_verb) {
|
|
128
126
|
return notFound("Unmatched HTTP method");
|
|
129
127
|
}
|
|
130
|
-
return right({
|
|
128
|
+
return Either.right({
|
|
131
129
|
model,
|
|
132
130
|
method,
|
|
133
131
|
id,
|
|
@@ -140,7 +138,7 @@ function matchRoute(request, ast, apiRoute) {
|
|
|
140
138
|
*/
|
|
141
139
|
async function validateRequest(request, ast, model, method, id) {
|
|
142
140
|
// Error state: any missing parameter, body, or malformed input will exit with 400.
|
|
143
|
-
const invalidRequest = (e) => left(errorState(400, `Invalid Request Body: ${e}`));
|
|
141
|
+
const invalidRequest = (e) => Either.left(errorState(400, `Invalid Request Body: ${e}`));
|
|
144
142
|
if (!method.is_static && id == null) {
|
|
145
143
|
return invalidRequest("Id's are required for instantiated methods.");
|
|
146
144
|
}
|
|
@@ -183,7 +181,7 @@ async function validateRequest(request, ast, model, method, id) {
|
|
|
183
181
|
!(dataSource in model.data_sources)) {
|
|
184
182
|
return invalidRequest(`Unknown data source ${dataSource}`);
|
|
185
183
|
}
|
|
186
|
-
return right({ params, dataSource });
|
|
184
|
+
return Either.right({ params, dataSource });
|
|
187
185
|
}
|
|
188
186
|
/**
|
|
189
187
|
* Queries D1 for a particular model's ID, then transforms the SQL column output into
|
|
@@ -195,17 +193,19 @@ async function validateRequest(request, ast, model, method, id) {
|
|
|
195
193
|
async function hydrateModel(constructorRegistry, d1, model, id, dataSource) {
|
|
196
194
|
// Error state: If the D1 database has been tweaked outside of Cloesce
|
|
197
195
|
// resulting in a malformed query, exit with a 500.
|
|
198
|
-
const malformedQuery = (e) => left(errorState(500, `Error in hydration query, is the database out of sync with the backend?: ${e instanceof Error ? e.message : String(e)}`));
|
|
196
|
+
const malformedQuery = (e) => Either.left(errorState(500, `Error in hydration query, is the database out of sync with the backend?: ${e instanceof Error ? e.message : String(e)}`));
|
|
199
197
|
// Error state: If no record is found for the id, return a 404
|
|
200
|
-
const missingRecord = left(errorState(404, "Record not found"));
|
|
201
|
-
const pk = model.primary_key.name;
|
|
202
|
-
const query = dataSource !== NO_DATA_SOURCE
|
|
203
|
-
? `SELECT * FROM "${model.name}.${dataSource}" WHERE "${pk}" = ?`
|
|
204
|
-
: `SELECT * FROM "${model.name}" WHERE "${pk}" = ?`;
|
|
198
|
+
const missingRecord = Either.left(errorState(404, "Record not found"));
|
|
205
199
|
// Query DB
|
|
206
200
|
let records;
|
|
207
201
|
try {
|
|
208
|
-
|
|
202
|
+
let includeTree = dataSource === NO_DATA_SOURCE
|
|
203
|
+
? null
|
|
204
|
+
: constructorRegistry[model.name][dataSource];
|
|
205
|
+
records = await d1
|
|
206
|
+
.prepare(Orm.getQuery(constructorRegistry[model.name], includeTree).unwrap())
|
|
207
|
+
.bind(id)
|
|
208
|
+
.run();
|
|
209
209
|
if (!records?.results) {
|
|
210
210
|
return missingRecord;
|
|
211
211
|
}
|
|
@@ -218,7 +218,7 @@ async function hydrateModel(constructorRegistry, d1, model, id, dataSource) {
|
|
|
218
218
|
}
|
|
219
219
|
// Hydrate
|
|
220
220
|
const models = mapSql(constructorRegistry[model.name], records.results, model.data_sources[dataSource]?.tree ?? {}).value;
|
|
221
|
-
return right(models[0]);
|
|
221
|
+
return Either.right(models[0]);
|
|
222
222
|
}
|
|
223
223
|
/**
|
|
224
224
|
* Calls a method on a model given a list of parameters.
|
|
@@ -326,6 +326,7 @@ function validateCidlType(ast, value, cidlType, isPartial) {
|
|
|
326
326
|
if (!poo.attributes.every((attr) => validateCidlType(ast, valueObj[attr.name], attr.cidl_type, isPartial))) {
|
|
327
327
|
return false;
|
|
328
328
|
}
|
|
329
|
+
return true;
|
|
329
330
|
}
|
|
330
331
|
if ("Array" in cidlType) {
|
|
331
332
|
const arr = cidlType.Array;
|
package/dist/router/wasm.d.ts
CHANGED
|
@@ -10,8 +10,9 @@ export interface OrmWasmExports {
|
|
|
10
10
|
set_meta_ptr(ptr: number, len: number): number;
|
|
11
11
|
alloc(len: number): number;
|
|
12
12
|
dealloc(ptr: number, len: number): void;
|
|
13
|
-
|
|
13
|
+
map_sql(model_name_ptr: number, model_name_len: number, sql_rows_ptr: number, sql_rows_len: number, include_tree_ptr: number, include_tree_len: number): boolean;
|
|
14
14
|
upsert_model(model_name_ptr: number, model_name_len: number, new_model_ptr: number, new_model_len: number, include_tree_ptr: number, include_tree_len: number): boolean;
|
|
15
|
+
list_models(model_name_ptr: number, model_name_len: number, include_tree_ptr: number, include_tree_len: number, tag_cte_ptr: number, tag_cte_len: number, custom_from_ptr: number, custom_from_len: number): boolean;
|
|
15
16
|
}
|
|
16
17
|
/**
|
|
17
18
|
* RAII for wasm memory
|
|
@@ -28,7 +29,13 @@ export declare class WasmResource {
|
|
|
28
29
|
static fromString(str: string, wasm: OrmWasmExports): WasmResource;
|
|
29
30
|
}
|
|
30
31
|
export declare function loadOrmWasm(ast: CloesceAst, wasm?: WebAssembly.Instance): Promise<OrmWasmExports>;
|
|
31
|
-
|
|
32
|
+
/**
|
|
33
|
+
* Invokes a WASM ORM function with the provided arguments, handling memory
|
|
34
|
+
* allocation and deallocation.
|
|
35
|
+
*
|
|
36
|
+
* Returns an Either where Left is an error message and Right the raw string result.
|
|
37
|
+
*/
|
|
38
|
+
export declare function invokeOrmWasm(fn: (...args: number[]) => boolean, args: WasmResource[], wasm: OrmWasmExports): Either<string, string>;
|
|
32
39
|
/**
|
|
33
40
|
* Calls `object_relational_mapping` to turn a row of SQL records into
|
|
34
41
|
* an instantiated object.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wasm.d.ts","sourceRoot":"","sources":["../../src/router/wasm.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"wasm.d.ts","sourceRoot":"","sources":["../../src/router/wasm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAS,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAM/C;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IAC3B,cAAc,IAAI,MAAM,CAAC;IACzB,cAAc,IAAI,MAAM,CAAC;IACzB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/C,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAExC,OAAO,CACL,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC;IAEX,YAAY,CACV,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC;IAEX,WAAW,CACT,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,gBAAgB,EAAE,MAAM,EACxB,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC;CACZ;AAED;;GAEG;AACH,qBAAa,YAAY;IAErB,OAAO,CAAC,IAAI;IACL,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;gBAFV,IAAI,EAAE,cAAc,EACrB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM;IAEpB,IAAI;IAIJ;;OAEG;IACH,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,YAAY;CAQnE;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,UAAU,EACf,IAAI,CAAC,EAAE,WAAW,CAAC,QAAQ,GAC1B,OAAO,CAAC,cAAc,CAAC,CAmBzB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,EAClC,IAAI,EAAE,YAAY,EAAE,EACpB,IAAI,EAAE,cAAc,GACnB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkBxB;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,EACrC,IAAI,EAAE,UAAU,CAAC,EACjB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EAC9B,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,eAAe,GAAG,IAAI,GACnD,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAsDrB"}
|