@atscript/typescript 0.1.16 → 0.1.18
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/cli.cjs +84 -45
- package/dist/index.cjs +79 -40
- package/dist/index.mjs +79 -40
- package/dist/utils.cjs +35 -17
- package/dist/utils.d.ts +5 -5
- package/dist/utils.mjs +35 -17
- package/package.json +42 -42
package/dist/cli.cjs
CHANGED
|
@@ -23,10 +23,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
|
|
24
24
|
//#endregion
|
|
25
25
|
const __moostjs_event_cli = __toESM(require("@moostjs/event-cli"));
|
|
26
|
-
const
|
|
26
|
+
const fs = __toESM(require("fs"));
|
|
27
27
|
const path = __toESM(require("path"));
|
|
28
28
|
const __atscript_core = __toESM(require("@atscript/core"));
|
|
29
|
-
const
|
|
29
|
+
const moost = __toESM(require("moost"));
|
|
30
30
|
|
|
31
31
|
//#region packages/typescript/src/codegen/code-printer.ts
|
|
32
32
|
function _define_property$5(obj, key, value) {
|
|
@@ -111,7 +111,7 @@ else if (this.currentLine.length > 0) this.lines.push(this.currentLine);
|
|
|
111
111
|
return this;
|
|
112
112
|
}
|
|
113
113
|
doPop(withNewLine) {
|
|
114
|
-
if (
|
|
114
|
+
if (this.blockStack.length === 0) throw new Error("No block to pop (stack is empty).");
|
|
115
115
|
const closing = this.blockStack.pop();
|
|
116
116
|
this.unindent();
|
|
117
117
|
if (withNewLine) this.writeln(closing);
|
|
@@ -310,7 +310,7 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
|
|
|
310
310
|
propsDefs.add(renderedDef);
|
|
311
311
|
renderedDef.split("\n").forEach((l) => this.writeln(l));
|
|
312
312
|
}
|
|
313
|
-
if (patterns.length) {
|
|
313
|
+
if (patterns.length > 0) {
|
|
314
314
|
this.write(`[key: string]: `);
|
|
315
315
|
if (patterns.length > 0) {
|
|
316
316
|
for (const prop of patterns) propsDefs.add(this.renderTypeDefString(prop.getDefinition()));
|
|
@@ -588,7 +588,7 @@ var Validator = class {
|
|
|
588
588
|
}
|
|
589
589
|
let i = 0;
|
|
590
590
|
for (const item of def.type.items) {
|
|
591
|
-
this.push(
|
|
591
|
+
this.push(String(i));
|
|
592
592
|
if (!this.validateSafe(item, value[i])) {
|
|
593
593
|
this.pop(true);
|
|
594
594
|
return false;
|
|
@@ -624,7 +624,7 @@ var Validator = class {
|
|
|
624
624
|
let i = 0;
|
|
625
625
|
let passed = true;
|
|
626
626
|
for (const item of value) {
|
|
627
|
-
this.push(
|
|
627
|
+
this.push(String(i));
|
|
628
628
|
if (!this.validateSafe(def.type.of, item)) {
|
|
629
629
|
passed = false;
|
|
630
630
|
this.pop(true);
|
|
@@ -676,7 +676,7 @@ else {
|
|
|
676
676
|
pattern,
|
|
677
677
|
def: propDef
|
|
678
678
|
});
|
|
679
|
-
if (matched.length) {
|
|
679
|
+
if (matched.length > 0) {
|
|
680
680
|
let keyPassed = false;
|
|
681
681
|
for (const { def: def$1 } of matched) if (this.validateSafe(def$1, value[key])) {
|
|
682
682
|
this.pop(false);
|
|
@@ -703,7 +703,7 @@ else {
|
|
|
703
703
|
return passed;
|
|
704
704
|
}
|
|
705
705
|
validatePrimitive(def, value) {
|
|
706
|
-
if (
|
|
706
|
+
if (def.type.value !== undefined) {
|
|
707
707
|
if (value !== def.type.value) {
|
|
708
708
|
this.error(`Expected ${def.type.value}, got ${value}`);
|
|
709
709
|
return false;
|
|
@@ -712,40 +712,46 @@ else {
|
|
|
712
712
|
}
|
|
713
713
|
const typeOfValue = Array.isArray(value) ? "array" : typeof value;
|
|
714
714
|
switch (def.type.designType) {
|
|
715
|
-
case "never":
|
|
715
|
+
case "never": {
|
|
716
716
|
this.error(`This type is impossible, must be an internal problem`);
|
|
717
717
|
return false;
|
|
718
|
+
}
|
|
718
719
|
case "any": return true;
|
|
719
|
-
case "string":
|
|
720
|
+
case "string": {
|
|
720
721
|
if (typeOfValue !== def.type.designType) {
|
|
721
722
|
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
722
723
|
return false;
|
|
723
724
|
}
|
|
724
725
|
return this.validateString(def, value);
|
|
725
|
-
|
|
726
|
+
}
|
|
727
|
+
case "number": {
|
|
726
728
|
if (typeOfValue !== def.type.designType) {
|
|
727
729
|
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
728
730
|
return false;
|
|
729
731
|
}
|
|
730
732
|
return this.validateNumber(def, value);
|
|
731
|
-
|
|
733
|
+
}
|
|
734
|
+
case "boolean": {
|
|
732
735
|
if (typeOfValue !== def.type.designType) {
|
|
733
736
|
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
734
737
|
return false;
|
|
735
738
|
}
|
|
736
739
|
return this.validateBoolean(def, value);
|
|
737
|
-
|
|
740
|
+
}
|
|
741
|
+
case "undefined": {
|
|
738
742
|
if (value !== undefined) {
|
|
739
743
|
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
740
744
|
return false;
|
|
741
745
|
}
|
|
742
746
|
return true;
|
|
743
|
-
|
|
747
|
+
}
|
|
748
|
+
case "null": {
|
|
744
749
|
if (value !== null) {
|
|
745
750
|
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
746
751
|
return false;
|
|
747
752
|
}
|
|
748
753
|
return true;
|
|
754
|
+
}
|
|
749
755
|
default: throw new Error(`Unknown type "${def.type.designType}"`);
|
|
750
756
|
}
|
|
751
757
|
}
|
|
@@ -957,7 +963,6 @@ else throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
|
957
963
|
}
|
|
958
964
|
if (!newBase && keys) throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
959
965
|
else if (!newBase) throw new Error(`"${typeName}" is not annotated type`);
|
|
960
|
-
for (const [k, v] of newBase.metadata.entries()) if (!metadata.has(k)) metadata.set(k, Array.isArray(v) ? [...v] : v);
|
|
961
966
|
this.$type = {
|
|
962
967
|
__is_atscript_annotated_type: true,
|
|
963
968
|
type: newBase.type,
|
|
@@ -1001,7 +1006,7 @@ function buildJsonSchema(type) {
|
|
|
1001
1006
|
type: "object",
|
|
1002
1007
|
properties
|
|
1003
1008
|
};
|
|
1004
|
-
if (required.length) schema.required = required;
|
|
1009
|
+
if (required.length > 0) schema.required = required;
|
|
1005
1010
|
return schema;
|
|
1006
1011
|
},
|
|
1007
1012
|
array(d) {
|
|
@@ -1264,34 +1269,39 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1264
1269
|
annotations?.forEach((a) => {
|
|
1265
1270
|
switch (a.name) {
|
|
1266
1271
|
case "expect.minLength":
|
|
1267
|
-
case "expect.maxLength":
|
|
1272
|
+
case "expect.maxLength": {
|
|
1268
1273
|
if (a.args[0]) handle.annotate(a.name, {
|
|
1269
1274
|
length: Number(a.args[0].text),
|
|
1270
1275
|
message: a.args[1]?.text
|
|
1271
1276
|
});
|
|
1272
1277
|
break;
|
|
1273
|
-
|
|
1278
|
+
}
|
|
1279
|
+
case "expect.min": {
|
|
1274
1280
|
if (a.args[0]) handle.annotate(a.name, {
|
|
1275
1281
|
minValue: Number(a.args[0].text),
|
|
1276
1282
|
message: a.args[1]?.text
|
|
1277
1283
|
});
|
|
1278
1284
|
break;
|
|
1279
|
-
|
|
1285
|
+
}
|
|
1286
|
+
case "expect.max": {
|
|
1280
1287
|
if (a.args[0]) handle.annotate(a.name, {
|
|
1281
1288
|
maxValue: Number(a.args[0].text),
|
|
1282
1289
|
message: a.args[1]?.text
|
|
1283
1290
|
});
|
|
1284
1291
|
break;
|
|
1285
|
-
|
|
1292
|
+
}
|
|
1293
|
+
case "expect.pattern": {
|
|
1286
1294
|
handle.annotate(a.name, {
|
|
1287
1295
|
pattern: a.args[0]?.text || "",
|
|
1288
1296
|
flags: a.args[1]?.text,
|
|
1289
1297
|
message: a.args[2]?.text
|
|
1290
1298
|
}, true);
|
|
1291
1299
|
break;
|
|
1292
|
-
|
|
1300
|
+
}
|
|
1301
|
+
case "expect.int": {
|
|
1293
1302
|
handle.annotate(a.name, true);
|
|
1294
1303
|
break;
|
|
1304
|
+
}
|
|
1295
1305
|
default:
|
|
1296
1306
|
}
|
|
1297
1307
|
});
|
|
@@ -1306,11 +1316,24 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1306
1316
|
const ref = node;
|
|
1307
1317
|
const decl = this.doc.unwindType(ref.id, ref.chain)?.def;
|
|
1308
1318
|
if ((0, __atscript_core.isPrimitive)(decl)) {
|
|
1309
|
-
this.
|
|
1310
|
-
|
|
1319
|
+
const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
|
|
1320
|
+
if (!ownerDecl?.node || ownerDecl.node.entity !== "type" && ownerDecl.node.entity !== "interface") {
|
|
1321
|
+
this.annotateType(decl, name);
|
|
1322
|
+
return this;
|
|
1323
|
+
}
|
|
1311
1324
|
}
|
|
1312
1325
|
const chain = ref.hasChain ? `, [${ref.chain.map((c) => `"${escapeQuotes(c.text)}"`).join(", ")}]` : "";
|
|
1313
|
-
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`)
|
|
1326
|
+
this.writeln(`$(${name ? `"", ${name}` : ""})`).indent().writeln(`.refTo(${ref.id}${chain})`);
|
|
1327
|
+
if (!ref.hasChain) {
|
|
1328
|
+
const ownerDecl = this.doc.getDeclarationOwnerNode(ref.id);
|
|
1329
|
+
if (ownerDecl?.node) {
|
|
1330
|
+
const typeAnnotations = ownerDecl.doc.evalAnnotationsForNode(ownerDecl.node);
|
|
1331
|
+
typeAnnotations?.forEach((an) => {
|
|
1332
|
+
this.resolveAnnotationValue(ownerDecl.node, an);
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
this.unindent();
|
|
1314
1337
|
return this;
|
|
1315
1338
|
}
|
|
1316
1339
|
case "primitive": {
|
|
@@ -1339,7 +1362,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1339
1362
|
return this;
|
|
1340
1363
|
}
|
|
1341
1364
|
default: {
|
|
1342
|
-
console.log("!!!!!!! UNKNOWN
|
|
1365
|
+
console.log("!!!!!!! UNKNOWN", node.entity);
|
|
1343
1366
|
return this;
|
|
1344
1367
|
}
|
|
1345
1368
|
}
|
|
@@ -1364,7 +1387,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1364
1387
|
case "final": return this.writeln(`$(${d()}).designType("${def.value === "void" ? "undefined" : def.value}")`);
|
|
1365
1388
|
case "union":
|
|
1366
1389
|
case "intersection":
|
|
1367
|
-
case "tuple":
|
|
1390
|
+
case "tuple": {
|
|
1368
1391
|
this.writeln(`$(${d(def.kind)})`);
|
|
1369
1392
|
this.indent();
|
|
1370
1393
|
for (const itemDef of def.items) {
|
|
@@ -1377,7 +1400,8 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1377
1400
|
}
|
|
1378
1401
|
this.unindent();
|
|
1379
1402
|
return;
|
|
1380
|
-
|
|
1403
|
+
}
|
|
1404
|
+
case "array": {
|
|
1381
1405
|
this.writeln(`$(${d("array")})`);
|
|
1382
1406
|
this.indent();
|
|
1383
1407
|
this.write(".of(");
|
|
@@ -1388,7 +1412,8 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1388
1412
|
this.writeln(`)`);
|
|
1389
1413
|
this.unindent();
|
|
1390
1414
|
return;
|
|
1391
|
-
|
|
1415
|
+
}
|
|
1416
|
+
case "object": {
|
|
1392
1417
|
this.writeln(`$(${d("object")})`);
|
|
1393
1418
|
this.indent();
|
|
1394
1419
|
for (const [key, propDef] of Object.entries(def.props)) {
|
|
@@ -1415,6 +1440,7 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1415
1440
|
}
|
|
1416
1441
|
this.unindent();
|
|
1417
1442
|
return;
|
|
1443
|
+
}
|
|
1418
1444
|
default: return this.writeln(`$(${d()}).designType("any")`);
|
|
1419
1445
|
}
|
|
1420
1446
|
}
|
|
@@ -1454,7 +1480,20 @@ else handle.prop(prop.id, propHandle.$type);
|
|
|
1454
1480
|
return this;
|
|
1455
1481
|
}
|
|
1456
1482
|
defineMetadata(node) {
|
|
1457
|
-
let annotations
|
|
1483
|
+
let annotations;
|
|
1484
|
+
const nodeDef = node.getDefinition?.();
|
|
1485
|
+
if (nodeDef && (0, __atscript_core.isRef)(nodeDef)) {
|
|
1486
|
+
const refNode = nodeDef;
|
|
1487
|
+
if (!refNode.hasChain) {
|
|
1488
|
+
const resolved = this.doc.unwindType(refNode.id, refNode.chain)?.def;
|
|
1489
|
+
if (resolved && !(0, __atscript_core.isPrimitive)(resolved)) annotations = node.annotations ?? [];
|
|
1490
|
+
else if (resolved && (0, __atscript_core.isPrimitive)(resolved)) {
|
|
1491
|
+
const ownerDecl = this.doc.getDeclarationOwnerNode(refNode.id);
|
|
1492
|
+
if (ownerDecl?.node && (ownerDecl.node.entity === "type" || ownerDecl.node.entity === "interface")) annotations = node.annotations ?? [];
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
if (annotations === undefined) annotations = this.doc.evalAnnotationsForNode(node);
|
|
1458
1497
|
if (this._adHocAnnotations && this._propPath.length > 0) {
|
|
1459
1498
|
const path$3 = this._propPath.join(".");
|
|
1460
1499
|
const adHoc = this._adHocAnnotations.get(path$3);
|
|
@@ -1505,7 +1544,7 @@ else targetValue = "true";
|
|
|
1505
1544
|
}
|
|
1506
1545
|
} else {
|
|
1507
1546
|
multiple = node.countAnnotations(an.name) > 1 || an.args.length > 1;
|
|
1508
|
-
if (an.args.length) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1547
|
+
if (an.args.length > 0) targetValue = an.args[0].type === "text" ? `"${escapeQuotes(an.args[0].text)}"` : an.args[0].text;
|
|
1509
1548
|
}
|
|
1510
1549
|
return {
|
|
1511
1550
|
value: targetValue,
|
|
@@ -1567,7 +1606,7 @@ else targetValue = "true";
|
|
|
1567
1606
|
* Returns multiple paths when a property appears in multiple union branches.
|
|
1568
1607
|
*/ buildMutatingAccessors(targetName, targetDef, parts) {
|
|
1569
1608
|
let accessors = [{
|
|
1570
|
-
prefix: targetName
|
|
1609
|
+
prefix: `${targetName}.type`,
|
|
1571
1610
|
def: targetDef
|
|
1572
1611
|
}];
|
|
1573
1612
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -1575,17 +1614,17 @@ else targetValue = "true";
|
|
|
1575
1614
|
for (const { prefix, def } of accessors) {
|
|
1576
1615
|
const results = this.buildPropPaths(def, parts[i]);
|
|
1577
1616
|
if (results.length > 0) for (const result of results) if (i < parts.length - 1) nextAccessors.push({
|
|
1578
|
-
prefix: prefix
|
|
1617
|
+
prefix: `${prefix}${result.path}?.type`,
|
|
1579
1618
|
def: result.propDef
|
|
1580
1619
|
});
|
|
1581
1620
|
else nextAccessors.push({
|
|
1582
|
-
prefix: prefix
|
|
1621
|
+
prefix: `${prefix}${result.path}?`,
|
|
1583
1622
|
def: result.propDef
|
|
1584
1623
|
});
|
|
1585
1624
|
else {
|
|
1586
|
-
const suffix = `.props.get("${escapeQuotes(parts[i])}")
|
|
1625
|
+
const suffix = `.props.get("${escapeQuotes(parts[i])}")${i < parts.length - 1 ? "?.type" : "?"}`;
|
|
1587
1626
|
nextAccessors.push({
|
|
1588
|
-
prefix: prefix
|
|
1627
|
+
prefix: `${prefix}${suffix}`,
|
|
1589
1628
|
def: undefined
|
|
1590
1629
|
});
|
|
1591
1630
|
}
|
|
@@ -1640,9 +1679,9 @@ function resolveJsonSchemaMode(opts) {
|
|
|
1640
1679
|
}
|
|
1641
1680
|
const tsPlugin = (opts) => {
|
|
1642
1681
|
return {
|
|
1643
|
-
name: "
|
|
1682
|
+
name: "typescript",
|
|
1644
1683
|
render(doc, format) {
|
|
1645
|
-
if (format === "dts") return [{
|
|
1684
|
+
if (format === "dts" || format === __atscript_core.DEFAULT_FORMAT) return [{
|
|
1646
1685
|
fileName: `${doc.name}.d.ts`,
|
|
1647
1686
|
content: new TypeRenderer(doc, opts).render()
|
|
1648
1687
|
}];
|
|
@@ -1652,19 +1691,19 @@ const tsPlugin = (opts) => {
|
|
|
1652
1691
|
}];
|
|
1653
1692
|
},
|
|
1654
1693
|
async buildEnd(output, format, repo) {
|
|
1655
|
-
if (format === "dts") {
|
|
1694
|
+
if (format === "dts" || format === __atscript_core.DEFAULT_FORMAT) {
|
|
1656
1695
|
const annotations = await repo.getUsedAnnotations();
|
|
1657
1696
|
const tags = await repo.getPrimitivesTags() || new Set();
|
|
1658
|
-
|
|
1697
|
+
const rendered = [];
|
|
1659
1698
|
for (const [key, val] of Object.entries(annotations)) {
|
|
1660
1699
|
const multiple = val.multiple;
|
|
1661
|
-
|
|
1700
|
+
const typeLine = Array.from(val.types).map((t) => {
|
|
1662
1701
|
if (t.type === "object") return `{ ${Object.entries(t.props).map(([k, v]) => `${wrapProp(k)}${v.optional ? "?" : ""}: ${v.type}`).join(", ")} }`;
|
|
1663
1702
|
else return t.optional ? `${t.type} | true` : t.type;
|
|
1664
1703
|
}).join(" | ");
|
|
1665
1704
|
rendered.push(`${wrapProp(key)}: ${multiple ? "(" : ""}${typeLine}${multiple ? ")[]" : ""}`);
|
|
1666
1705
|
}
|
|
1667
|
-
|
|
1706
|
+
const renderedTags = Array.from(tags).map((f) => `"${escapeQuotes(f)}"`).join(" | ");
|
|
1668
1707
|
output.push({
|
|
1669
1708
|
content: "// prettier-ignore-start\n/* eslint-disable */\n/* oxlint-disable */\n/**\n * 🪄 This file was generated by Atscript\n * It is generated based on annotations used in this project\n * Do not edit this file!\n *\n * Use `npx asc -f dts` command to re-generate this file\n */\nexport {}\n\ndeclare global {\n interface AtscriptMetadata {\n " + rendered.join("\n ") + "\n }\n" + " type AtscriptPrimitiveTags = " + renderedTags + "\n" + "}\n" + "// prettier-ignore-end",
|
|
1670
1709
|
fileName: "atscript.d.ts",
|
|
@@ -1705,7 +1744,7 @@ function _ts_param(paramIndex, decorator) {
|
|
|
1705
1744
|
var Commands = class {
|
|
1706
1745
|
async default(configFile, format, noEmit, skipDiag) {
|
|
1707
1746
|
const config = await this.getConfig(configFile);
|
|
1708
|
-
|
|
1747
|
+
config.format = format || __atscript_core.DEFAULT_FORMAT;
|
|
1709
1748
|
this.logger.log(`Format: ${"\x1B[36m"}${config.format}${"\x1B[39m"}`);
|
|
1710
1749
|
const builder = await (0, __atscript_core.build)(config);
|
|
1711
1750
|
let errorCount = 0;
|
|
@@ -1751,7 +1790,7 @@ else if (m.severity === 2) warningCount++;
|
|
|
1751
1790
|
}
|
|
1752
1791
|
this.logger.log(`No atscript config file found`);
|
|
1753
1792
|
return {
|
|
1754
|
-
format:
|
|
1793
|
+
format: __atscript_core.DEFAULT_FORMAT,
|
|
1755
1794
|
plugins: [tsPlugin()]
|
|
1756
1795
|
};
|
|
1757
1796
|
}
|
|
@@ -1773,7 +1812,7 @@ _ts_decorate([
|
|
|
1773
1812
|
_ts_param(0, (0, moost.Description)("Path to config file")),
|
|
1774
1813
|
_ts_param(1, (0, __moostjs_event_cli.CliOption)("f", "format")),
|
|
1775
1814
|
_ts_param(1, (0, moost.Optional)()),
|
|
1776
|
-
_ts_param(1, (0, moost.Description)("Output format (js
|
|
1815
|
+
_ts_param(1, (0, moost.Description)("Output format (e.g. js, dts). Omit to run all plugins with their default output.")),
|
|
1777
1816
|
_ts_param(2, (0, __moostjs_event_cli.CliOption)("noEmit")),
|
|
1778
1817
|
_ts_param(2, (0, moost.Optional)()),
|
|
1779
1818
|
_ts_param(2, (0, moost.Description)("Only run diagnostics without emitting files")),
|
|
@@ -1793,7 +1832,7 @@ Commands = _ts_decorate([
|
|
|
1793
1832
|
(0, moost.Controller)(),
|
|
1794
1833
|
_ts_param(0, (0, moost.InjectMoostLogger)("asc")),
|
|
1795
1834
|
_ts_metadata("design:type", Function),
|
|
1796
|
-
_ts_metadata("design:paramtypes", [typeof
|
|
1835
|
+
_ts_metadata("design:paramtypes", [typeof TConsoleBase === "undefined" ? Object : TConsoleBase])
|
|
1797
1836
|
], Commands);
|
|
1798
1837
|
|
|
1799
1838
|
//#endregion
|