@atscript/typescript 0.1.32 → 0.1.33
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 +99 -59
- package/dist/index.cjs +99 -59
- package/dist/index.mjs +99 -59
- package/dist/utils.cjs +67 -88
- package/dist/utils.d.ts +9 -2
- package/dist/utils.mjs +67 -89
- package/package.json +2 -2
package/dist/cli.cjs
CHANGED
|
@@ -482,28 +482,72 @@ else {
|
|
|
482
482
|
*
|
|
483
483
|
* - **Single PK** (one `@meta.id`) → `static __pk: <scalar type>`
|
|
484
484
|
* - **Compound PK** (multiple `@meta.id`) → `static __pk: { field1: Type1; field2: Type2 }`
|
|
485
|
-
* - **No PK** → no `__pk` emitted
|
|
485
|
+
* - **No PK** → no `__pk` emitted (unless unique indexes exist)
|
|
486
|
+
* - **Unique indexes** (`@db.index.unique`) → appended as union members
|
|
487
|
+
* - **Mongo collection** → always includes `string` (ObjectId) in the union;
|
|
488
|
+
* if no `@meta.id` fields, `__pk` is just `string`
|
|
486
489
|
*/ renderPk(node) {
|
|
490
|
+
const isMongoCollection = !!node.annotations?.some((a) => a.name === "db.mongo.collection");
|
|
487
491
|
let struct;
|
|
488
492
|
if (node.hasExtends) struct = this.doc.resolveInterfaceExtends(node);
|
|
489
493
|
if (!struct) struct = node.getDefinition();
|
|
490
494
|
if (!struct || !(0, __atscript_core.isStructure)(struct)) return;
|
|
495
|
+
const structNode = struct;
|
|
491
496
|
const pkProps = [];
|
|
492
|
-
|
|
497
|
+
const uniqueByIndex = new Map();
|
|
498
|
+
for (const [name, prop] of structNode.props) {
|
|
493
499
|
if (prop.token("identifier")?.pattern) continue;
|
|
500
|
+
if (isMongoCollection && name === "_id") continue;
|
|
494
501
|
if (prop.countAnnotations("meta.id") > 0) pkProps.push({
|
|
495
502
|
name,
|
|
496
503
|
prop
|
|
497
504
|
});
|
|
505
|
+
if (prop.annotations) {
|
|
506
|
+
for (const ann of prop.annotations) if (ann.name === "db.index.unique") {
|
|
507
|
+
const indexName = ann.args[0]?.text ?? name;
|
|
508
|
+
let group = uniqueByIndex.get(indexName);
|
|
509
|
+
if (!group) {
|
|
510
|
+
group = [];
|
|
511
|
+
uniqueByIndex.set(indexName, group);
|
|
512
|
+
}
|
|
513
|
+
group.push({
|
|
514
|
+
name,
|
|
515
|
+
prop
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
const uniqueProps = [];
|
|
521
|
+
const pkNames = new Set(pkProps.map((p) => p.name));
|
|
522
|
+
for (const fields of uniqueByIndex.values()) if (fields.length === 1 && !pkNames.has(fields[0].name)) uniqueProps.push(fields[0]);
|
|
523
|
+
if (pkProps.length === 0 && uniqueProps.length === 0 && !isMongoCollection) return;
|
|
524
|
+
let mongoIdType;
|
|
525
|
+
if (isMongoCollection) {
|
|
526
|
+
const idProp = structNode.props.get("_id");
|
|
527
|
+
if (idProp) mongoIdType = this.renderTypeDefString(idProp.getDefinition()).trim();
|
|
528
|
+
mongoIdType ?? (mongoIdType = "string");
|
|
529
|
+
}
|
|
530
|
+
const uniqueTypes = [];
|
|
531
|
+
const seenTypes = new Set();
|
|
532
|
+
for (const { prop } of uniqueProps) {
|
|
533
|
+
const rendered = this.renderTypeDefString(prop.getDefinition()).trim();
|
|
534
|
+
if (!seenTypes.has(rendered)) {
|
|
535
|
+
seenTypes.add(rendered);
|
|
536
|
+
uniqueTypes.push(rendered);
|
|
537
|
+
}
|
|
498
538
|
}
|
|
499
|
-
if (pkProps.length === 0) return;
|
|
500
539
|
this.writeln();
|
|
501
|
-
|
|
540
|
+
const uniqueSuffix = uniqueTypes.length > 0 ? ` | ${uniqueTypes.join(" | ")}` : "";
|
|
541
|
+
if (pkProps.length === 0 && !isMongoCollection) this.writeln(`static __pk: ${uniqueTypes.join(" | ")}`);
|
|
542
|
+
else if (pkProps.length === 0) this.writeln(`static __pk: ${mongoIdType}${uniqueSuffix}`);
|
|
543
|
+
else if (pkProps.length === 1) {
|
|
502
544
|
this.write("static __pk: ");
|
|
503
|
-
|
|
504
|
-
renderedDef.
|
|
545
|
+
if (isMongoCollection) this.write(`${mongoIdType} | `);
|
|
546
|
+
const renderedDef = this.renderTypeDefString(pkProps[0].prop.getDefinition()).trim();
|
|
547
|
+
this.writeln(`${renderedDef}${uniqueSuffix}`);
|
|
505
548
|
} else {
|
|
506
549
|
this.write("static __pk: ");
|
|
550
|
+
if (isMongoCollection) this.write(`${mongoIdType} | `);
|
|
507
551
|
this.blockln("{}");
|
|
508
552
|
for (const { name, prop } of pkProps) {
|
|
509
553
|
this.write(wrapProp(name), ": ");
|
|
@@ -511,6 +555,7 @@ else {
|
|
|
511
555
|
renderedDef.split("\n").forEach((l) => this.writeln(l));
|
|
512
556
|
}
|
|
513
557
|
this.pop();
|
|
558
|
+
this.writeln(uniqueSuffix);
|
|
514
559
|
}
|
|
515
560
|
}
|
|
516
561
|
phantomPropType(def) {
|
|
@@ -998,6 +1043,24 @@ var ValidatorError = class extends Error {
|
|
|
998
1043
|
|
|
999
1044
|
//#endregion
|
|
1000
1045
|
//#region packages/typescript/src/annotated-type.ts
|
|
1046
|
+
const COMPLEX_KINDS = new Set([
|
|
1047
|
+
"union",
|
|
1048
|
+
"intersection",
|
|
1049
|
+
"tuple"
|
|
1050
|
+
]);
|
|
1051
|
+
/** Shared validator method reused by all annotated type nodes. */ function validatorMethod(opts) {
|
|
1052
|
+
return new Validator(this, opts);
|
|
1053
|
+
}
|
|
1054
|
+
function createAnnotatedTypeNode(type, metadata, opts) {
|
|
1055
|
+
return {
|
|
1056
|
+
__is_atscript_annotated_type: true,
|
|
1057
|
+
type,
|
|
1058
|
+
metadata,
|
|
1059
|
+
validator: validatorMethod,
|
|
1060
|
+
id: opts?.id,
|
|
1061
|
+
optional: opts?.optional
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1001
1064
|
function isAnnotatedType(type) {
|
|
1002
1065
|
return type && type.__is_atscript_annotated_type;
|
|
1003
1066
|
}
|
|
@@ -1014,38 +1077,24 @@ function defineAnnotatedType(_kind, base) {
|
|
|
1014
1077
|
const kind = _kind || "";
|
|
1015
1078
|
const type = base?.type || {};
|
|
1016
1079
|
type.kind = kind;
|
|
1017
|
-
if ([
|
|
1018
|
-
"union",
|
|
1019
|
-
"intersection",
|
|
1020
|
-
"tuple"
|
|
1021
|
-
].includes(kind)) type.items = [];
|
|
1080
|
+
if (COMPLEX_KINDS.has(kind)) type.items = [];
|
|
1022
1081
|
if (kind === "object") {
|
|
1023
1082
|
type.props = new Map();
|
|
1024
1083
|
type.propsPatterns = [];
|
|
1025
1084
|
}
|
|
1026
1085
|
type.tags = new Set();
|
|
1027
1086
|
const metadata = base?.metadata || new Map();
|
|
1028
|
-
|
|
1087
|
+
const payload = {
|
|
1029
1088
|
__is_atscript_annotated_type: true,
|
|
1030
1089
|
metadata,
|
|
1031
1090
|
type,
|
|
1032
|
-
validator
|
|
1033
|
-
return new Validator(this, opts);
|
|
1034
|
-
}
|
|
1035
|
-
});
|
|
1036
|
-
else base = {
|
|
1037
|
-
__is_atscript_annotated_type: true,
|
|
1038
|
-
metadata,
|
|
1039
|
-
type,
|
|
1040
|
-
validator(opts) {
|
|
1041
|
-
return new Validator(this, opts);
|
|
1042
|
-
}
|
|
1091
|
+
validator: validatorMethod
|
|
1043
1092
|
};
|
|
1093
|
+
base = base ? Object.assign(base, payload) : payload;
|
|
1044
1094
|
const handle = {
|
|
1045
1095
|
$type: base,
|
|
1046
1096
|
$def: type,
|
|
1047
1097
|
$metadata: metadata,
|
|
1048
|
-
_existingObject: undefined,
|
|
1049
1098
|
tags(...tags) {
|
|
1050
1099
|
for (const tag of tags) this.$def.tags.add(tag);
|
|
1051
1100
|
return this;
|
|
@@ -1086,27 +1135,18 @@ else base = {
|
|
|
1086
1135
|
return this;
|
|
1087
1136
|
},
|
|
1088
1137
|
refTo(type$1, chain) {
|
|
1138
|
+
if (!isAnnotatedType(type$1)) throw new Error(`${type$1} is not annotated type`);
|
|
1089
1139
|
let newBase = type$1;
|
|
1090
1140
|
const typeName = type$1.name || "Unknown";
|
|
1091
|
-
if (
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1141
|
+
if (chain) for (let i = 0; i < chain.length; i++) {
|
|
1142
|
+
const c = chain[i];
|
|
1143
|
+
if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
|
|
1144
|
+
else {
|
|
1145
|
+
const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
|
|
1146
|
+
throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
1097
1147
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
this.$type = {
|
|
1101
|
-
__is_atscript_annotated_type: true,
|
|
1102
|
-
type: newBase.type,
|
|
1103
|
-
metadata,
|
|
1104
|
-
id: newBase.id,
|
|
1105
|
-
validator(opts) {
|
|
1106
|
-
return new Validator(this, opts);
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
} else throw new Error(`${type$1} is not annotated type`);
|
|
1148
|
+
}
|
|
1149
|
+
this.$type = createAnnotatedTypeNode(newBase.type, metadata, { id: newBase.id });
|
|
1110
1150
|
return this;
|
|
1111
1151
|
},
|
|
1112
1152
|
annotate(key, value, asArray) {
|
|
@@ -1156,10 +1196,10 @@ function forAnnotatedType(def, handlers) {
|
|
|
1156
1196
|
const firstObj = items[0].type;
|
|
1157
1197
|
const candidates = [];
|
|
1158
1198
|
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
1159
|
-
|
|
1199
|
+
let result = null;
|
|
1160
1200
|
for (const candidate of candidates) {
|
|
1161
1201
|
const values = new Set();
|
|
1162
|
-
const
|
|
1202
|
+
const indexMapping = {};
|
|
1163
1203
|
let valid = true;
|
|
1164
1204
|
for (let i = 0; i < items.length; i++) {
|
|
1165
1205
|
const obj = items[i].type;
|
|
@@ -1174,19 +1214,21 @@ function forAnnotatedType(def, handlers) {
|
|
|
1174
1214
|
break;
|
|
1175
1215
|
}
|
|
1176
1216
|
values.add(val);
|
|
1177
|
-
|
|
1217
|
+
indexMapping[String(val)] = i;
|
|
1218
|
+
}
|
|
1219
|
+
if (valid) {
|
|
1220
|
+
if (result) return null;
|
|
1221
|
+
result = {
|
|
1222
|
+
propertyName: candidate,
|
|
1223
|
+
indexMapping
|
|
1224
|
+
};
|
|
1178
1225
|
}
|
|
1179
|
-
if (valid) validCandidates.push({
|
|
1180
|
-
propertyName: candidate,
|
|
1181
|
-
mapping
|
|
1182
|
-
});
|
|
1183
1226
|
}
|
|
1184
|
-
|
|
1185
|
-
return null;
|
|
1227
|
+
return result;
|
|
1186
1228
|
}
|
|
1187
1229
|
function buildJsonSchema(type) {
|
|
1188
1230
|
const defs = {};
|
|
1189
|
-
let
|
|
1231
|
+
let hasDefs = false;
|
|
1190
1232
|
const buildObject = (d) => {
|
|
1191
1233
|
const properties = {};
|
|
1192
1234
|
const required = [];
|
|
@@ -1203,15 +1245,15 @@ function buildJsonSchema(type) {
|
|
|
1203
1245
|
return schema$1;
|
|
1204
1246
|
};
|
|
1205
1247
|
const build$1 = (def) => {
|
|
1206
|
-
if (def.id && def.type.kind === "object" &&
|
|
1248
|
+
if (def.id && def.type.kind === "object" && def !== type) {
|
|
1207
1249
|
const name = def.id;
|
|
1208
1250
|
if (!defs[name]) {
|
|
1251
|
+
hasDefs = true;
|
|
1209
1252
|
defs[name] = {};
|
|
1210
1253
|
defs[name] = buildObject(def);
|
|
1211
1254
|
}
|
|
1212
1255
|
return { $ref: `#/$defs/${name}` };
|
|
1213
1256
|
}
|
|
1214
|
-
isRoot = false;
|
|
1215
1257
|
const meta = def.metadata;
|
|
1216
1258
|
return forAnnotatedType(def, {
|
|
1217
1259
|
phantom() {
|
|
@@ -1236,11 +1278,9 @@ function buildJsonSchema(type) {
|
|
|
1236
1278
|
if (disc) {
|
|
1237
1279
|
const oneOf = d.type.items.map(build$1);
|
|
1238
1280
|
const mapping = {};
|
|
1239
|
-
for (const [val,
|
|
1240
|
-
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
1281
|
+
for (const [val, idx] of Object.entries(disc.indexMapping)) {
|
|
1241
1282
|
const item = d.type.items[idx];
|
|
1242
|
-
|
|
1243
|
-
else mapping[val] = origPath;
|
|
1283
|
+
mapping[val] = item.id && defs[item.id] ? `#/$defs/${item.id}` : `#/oneOf/${idx}`;
|
|
1244
1284
|
}
|
|
1245
1285
|
return {
|
|
1246
1286
|
oneOf,
|
|
@@ -1290,7 +1330,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
|
|
|
1290
1330
|
});
|
|
1291
1331
|
};
|
|
1292
1332
|
const schema = build$1(type);
|
|
1293
|
-
if (
|
|
1333
|
+
if (hasDefs) return {
|
|
1294
1334
|
...schema,
|
|
1295
1335
|
$defs: defs
|
|
1296
1336
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -480,28 +480,72 @@ else {
|
|
|
480
480
|
*
|
|
481
481
|
* - **Single PK** (one `@meta.id`) → `static __pk: <scalar type>`
|
|
482
482
|
* - **Compound PK** (multiple `@meta.id`) → `static __pk: { field1: Type1; field2: Type2 }`
|
|
483
|
-
* - **No PK** → no `__pk` emitted
|
|
483
|
+
* - **No PK** → no `__pk` emitted (unless unique indexes exist)
|
|
484
|
+
* - **Unique indexes** (`@db.index.unique`) → appended as union members
|
|
485
|
+
* - **Mongo collection** → always includes `string` (ObjectId) in the union;
|
|
486
|
+
* if no `@meta.id` fields, `__pk` is just `string`
|
|
484
487
|
*/ renderPk(node) {
|
|
488
|
+
const isMongoCollection = !!node.annotations?.some((a) => a.name === "db.mongo.collection");
|
|
485
489
|
let struct;
|
|
486
490
|
if (node.hasExtends) struct = this.doc.resolveInterfaceExtends(node);
|
|
487
491
|
if (!struct) struct = node.getDefinition();
|
|
488
492
|
if (!struct || !(0, __atscript_core.isStructure)(struct)) return;
|
|
493
|
+
const structNode = struct;
|
|
489
494
|
const pkProps = [];
|
|
490
|
-
|
|
495
|
+
const uniqueByIndex = new Map();
|
|
496
|
+
for (const [name, prop] of structNode.props) {
|
|
491
497
|
if (prop.token("identifier")?.pattern) continue;
|
|
498
|
+
if (isMongoCollection && name === "_id") continue;
|
|
492
499
|
if (prop.countAnnotations("meta.id") > 0) pkProps.push({
|
|
493
500
|
name,
|
|
494
501
|
prop
|
|
495
502
|
});
|
|
503
|
+
if (prop.annotations) {
|
|
504
|
+
for (const ann of prop.annotations) if (ann.name === "db.index.unique") {
|
|
505
|
+
const indexName = ann.args[0]?.text ?? name;
|
|
506
|
+
let group = uniqueByIndex.get(indexName);
|
|
507
|
+
if (!group) {
|
|
508
|
+
group = [];
|
|
509
|
+
uniqueByIndex.set(indexName, group);
|
|
510
|
+
}
|
|
511
|
+
group.push({
|
|
512
|
+
name,
|
|
513
|
+
prop
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
const uniqueProps = [];
|
|
519
|
+
const pkNames = new Set(pkProps.map((p) => p.name));
|
|
520
|
+
for (const fields of uniqueByIndex.values()) if (fields.length === 1 && !pkNames.has(fields[0].name)) uniqueProps.push(fields[0]);
|
|
521
|
+
if (pkProps.length === 0 && uniqueProps.length === 0 && !isMongoCollection) return;
|
|
522
|
+
let mongoIdType;
|
|
523
|
+
if (isMongoCollection) {
|
|
524
|
+
const idProp = structNode.props.get("_id");
|
|
525
|
+
if (idProp) mongoIdType = this.renderTypeDefString(idProp.getDefinition()).trim();
|
|
526
|
+
mongoIdType ?? (mongoIdType = "string");
|
|
527
|
+
}
|
|
528
|
+
const uniqueTypes = [];
|
|
529
|
+
const seenTypes = new Set();
|
|
530
|
+
for (const { prop } of uniqueProps) {
|
|
531
|
+
const rendered = this.renderTypeDefString(prop.getDefinition()).trim();
|
|
532
|
+
if (!seenTypes.has(rendered)) {
|
|
533
|
+
seenTypes.add(rendered);
|
|
534
|
+
uniqueTypes.push(rendered);
|
|
535
|
+
}
|
|
496
536
|
}
|
|
497
|
-
if (pkProps.length === 0) return;
|
|
498
537
|
this.writeln();
|
|
499
|
-
|
|
538
|
+
const uniqueSuffix = uniqueTypes.length > 0 ? ` | ${uniqueTypes.join(" | ")}` : "";
|
|
539
|
+
if (pkProps.length === 0 && !isMongoCollection) this.writeln(`static __pk: ${uniqueTypes.join(" | ")}`);
|
|
540
|
+
else if (pkProps.length === 0) this.writeln(`static __pk: ${mongoIdType}${uniqueSuffix}`);
|
|
541
|
+
else if (pkProps.length === 1) {
|
|
500
542
|
this.write("static __pk: ");
|
|
501
|
-
|
|
502
|
-
renderedDef.
|
|
543
|
+
if (isMongoCollection) this.write(`${mongoIdType} | `);
|
|
544
|
+
const renderedDef = this.renderTypeDefString(pkProps[0].prop.getDefinition()).trim();
|
|
545
|
+
this.writeln(`${renderedDef}${uniqueSuffix}`);
|
|
503
546
|
} else {
|
|
504
547
|
this.write("static __pk: ");
|
|
548
|
+
if (isMongoCollection) this.write(`${mongoIdType} | `);
|
|
505
549
|
this.blockln("{}");
|
|
506
550
|
for (const { name, prop } of pkProps) {
|
|
507
551
|
this.write(wrapProp(name), ": ");
|
|
@@ -509,6 +553,7 @@ else {
|
|
|
509
553
|
renderedDef.split("\n").forEach((l) => this.writeln(l));
|
|
510
554
|
}
|
|
511
555
|
this.pop();
|
|
556
|
+
this.writeln(uniqueSuffix);
|
|
512
557
|
}
|
|
513
558
|
}
|
|
514
559
|
phantomPropType(def) {
|
|
@@ -996,6 +1041,24 @@ var ValidatorError = class extends Error {
|
|
|
996
1041
|
|
|
997
1042
|
//#endregion
|
|
998
1043
|
//#region packages/typescript/src/annotated-type.ts
|
|
1044
|
+
const COMPLEX_KINDS = new Set([
|
|
1045
|
+
"union",
|
|
1046
|
+
"intersection",
|
|
1047
|
+
"tuple"
|
|
1048
|
+
]);
|
|
1049
|
+
/** Shared validator method reused by all annotated type nodes. */ function validatorMethod(opts) {
|
|
1050
|
+
return new Validator(this, opts);
|
|
1051
|
+
}
|
|
1052
|
+
function createAnnotatedTypeNode(type, metadata, opts) {
|
|
1053
|
+
return {
|
|
1054
|
+
__is_atscript_annotated_type: true,
|
|
1055
|
+
type,
|
|
1056
|
+
metadata,
|
|
1057
|
+
validator: validatorMethod,
|
|
1058
|
+
id: opts?.id,
|
|
1059
|
+
optional: opts?.optional
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
999
1062
|
function isAnnotatedType(type) {
|
|
1000
1063
|
return type && type.__is_atscript_annotated_type;
|
|
1001
1064
|
}
|
|
@@ -1012,38 +1075,24 @@ function defineAnnotatedType(_kind, base) {
|
|
|
1012
1075
|
const kind = _kind || "";
|
|
1013
1076
|
const type = base?.type || {};
|
|
1014
1077
|
type.kind = kind;
|
|
1015
|
-
if ([
|
|
1016
|
-
"union",
|
|
1017
|
-
"intersection",
|
|
1018
|
-
"tuple"
|
|
1019
|
-
].includes(kind)) type.items = [];
|
|
1078
|
+
if (COMPLEX_KINDS.has(kind)) type.items = [];
|
|
1020
1079
|
if (kind === "object") {
|
|
1021
1080
|
type.props = new Map();
|
|
1022
1081
|
type.propsPatterns = [];
|
|
1023
1082
|
}
|
|
1024
1083
|
type.tags = new Set();
|
|
1025
1084
|
const metadata = base?.metadata || new Map();
|
|
1026
|
-
|
|
1085
|
+
const payload = {
|
|
1027
1086
|
__is_atscript_annotated_type: true,
|
|
1028
1087
|
metadata,
|
|
1029
1088
|
type,
|
|
1030
|
-
validator
|
|
1031
|
-
return new Validator(this, opts);
|
|
1032
|
-
}
|
|
1033
|
-
});
|
|
1034
|
-
else base = {
|
|
1035
|
-
__is_atscript_annotated_type: true,
|
|
1036
|
-
metadata,
|
|
1037
|
-
type,
|
|
1038
|
-
validator(opts) {
|
|
1039
|
-
return new Validator(this, opts);
|
|
1040
|
-
}
|
|
1089
|
+
validator: validatorMethod
|
|
1041
1090
|
};
|
|
1091
|
+
base = base ? Object.assign(base, payload) : payload;
|
|
1042
1092
|
const handle = {
|
|
1043
1093
|
$type: base,
|
|
1044
1094
|
$def: type,
|
|
1045
1095
|
$metadata: metadata,
|
|
1046
|
-
_existingObject: undefined,
|
|
1047
1096
|
tags(...tags) {
|
|
1048
1097
|
for (const tag of tags) this.$def.tags.add(tag);
|
|
1049
1098
|
return this;
|
|
@@ -1084,27 +1133,18 @@ else base = {
|
|
|
1084
1133
|
return this;
|
|
1085
1134
|
},
|
|
1086
1135
|
refTo(type$1, chain) {
|
|
1136
|
+
if (!isAnnotatedType(type$1)) throw new Error(`${type$1} is not annotated type`);
|
|
1087
1137
|
let newBase = type$1;
|
|
1088
1138
|
const typeName = type$1.name || "Unknown";
|
|
1089
|
-
if (
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1139
|
+
if (chain) for (let i = 0; i < chain.length; i++) {
|
|
1140
|
+
const c = chain[i];
|
|
1141
|
+
if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
|
|
1142
|
+
else {
|
|
1143
|
+
const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
|
|
1144
|
+
throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
1095
1145
|
}
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
this.$type = {
|
|
1099
|
-
__is_atscript_annotated_type: true,
|
|
1100
|
-
type: newBase.type,
|
|
1101
|
-
metadata,
|
|
1102
|
-
id: newBase.id,
|
|
1103
|
-
validator(opts) {
|
|
1104
|
-
return new Validator(this, opts);
|
|
1105
|
-
}
|
|
1106
|
-
};
|
|
1107
|
-
} else throw new Error(`${type$1} is not annotated type`);
|
|
1146
|
+
}
|
|
1147
|
+
this.$type = createAnnotatedTypeNode(newBase.type, metadata, { id: newBase.id });
|
|
1108
1148
|
return this;
|
|
1109
1149
|
},
|
|
1110
1150
|
annotate(key, value, asArray) {
|
|
@@ -1154,10 +1194,10 @@ function forAnnotatedType(def, handlers) {
|
|
|
1154
1194
|
const firstObj = items[0].type;
|
|
1155
1195
|
const candidates = [];
|
|
1156
1196
|
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
1157
|
-
|
|
1197
|
+
let result = null;
|
|
1158
1198
|
for (const candidate of candidates) {
|
|
1159
1199
|
const values = new Set();
|
|
1160
|
-
const
|
|
1200
|
+
const indexMapping = {};
|
|
1161
1201
|
let valid = true;
|
|
1162
1202
|
for (let i = 0; i < items.length; i++) {
|
|
1163
1203
|
const obj = items[i].type;
|
|
@@ -1172,19 +1212,21 @@ function forAnnotatedType(def, handlers) {
|
|
|
1172
1212
|
break;
|
|
1173
1213
|
}
|
|
1174
1214
|
values.add(val);
|
|
1175
|
-
|
|
1215
|
+
indexMapping[String(val)] = i;
|
|
1216
|
+
}
|
|
1217
|
+
if (valid) {
|
|
1218
|
+
if (result) return null;
|
|
1219
|
+
result = {
|
|
1220
|
+
propertyName: candidate,
|
|
1221
|
+
indexMapping
|
|
1222
|
+
};
|
|
1176
1223
|
}
|
|
1177
|
-
if (valid) validCandidates.push({
|
|
1178
|
-
propertyName: candidate,
|
|
1179
|
-
mapping
|
|
1180
|
-
});
|
|
1181
1224
|
}
|
|
1182
|
-
|
|
1183
|
-
return null;
|
|
1225
|
+
return result;
|
|
1184
1226
|
}
|
|
1185
1227
|
function buildJsonSchema(type) {
|
|
1186
1228
|
const defs = {};
|
|
1187
|
-
let
|
|
1229
|
+
let hasDefs = false;
|
|
1188
1230
|
const buildObject = (d) => {
|
|
1189
1231
|
const properties = {};
|
|
1190
1232
|
const required = [];
|
|
@@ -1201,15 +1243,15 @@ function buildJsonSchema(type) {
|
|
|
1201
1243
|
return schema$1;
|
|
1202
1244
|
};
|
|
1203
1245
|
const build = (def) => {
|
|
1204
|
-
if (def.id && def.type.kind === "object" &&
|
|
1246
|
+
if (def.id && def.type.kind === "object" && def !== type) {
|
|
1205
1247
|
const name = def.id;
|
|
1206
1248
|
if (!defs[name]) {
|
|
1249
|
+
hasDefs = true;
|
|
1207
1250
|
defs[name] = {};
|
|
1208
1251
|
defs[name] = buildObject(def);
|
|
1209
1252
|
}
|
|
1210
1253
|
return { $ref: `#/$defs/${name}` };
|
|
1211
1254
|
}
|
|
1212
|
-
isRoot = false;
|
|
1213
1255
|
const meta = def.metadata;
|
|
1214
1256
|
return forAnnotatedType(def, {
|
|
1215
1257
|
phantom() {
|
|
@@ -1234,11 +1276,9 @@ function buildJsonSchema(type) {
|
|
|
1234
1276
|
if (disc) {
|
|
1235
1277
|
const oneOf = d.type.items.map(build);
|
|
1236
1278
|
const mapping = {};
|
|
1237
|
-
for (const [val,
|
|
1238
|
-
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
1279
|
+
for (const [val, idx] of Object.entries(disc.indexMapping)) {
|
|
1239
1280
|
const item = d.type.items[idx];
|
|
1240
|
-
|
|
1241
|
-
else mapping[val] = origPath;
|
|
1281
|
+
mapping[val] = item.id && defs[item.id] ? `#/$defs/${item.id}` : `#/oneOf/${idx}`;
|
|
1242
1282
|
}
|
|
1243
1283
|
return {
|
|
1244
1284
|
oneOf,
|
|
@@ -1288,7 +1328,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
|
|
|
1288
1328
|
});
|
|
1289
1329
|
};
|
|
1290
1330
|
const schema = build(type);
|
|
1291
|
-
if (
|
|
1331
|
+
if (hasDefs) return {
|
|
1292
1332
|
...schema,
|
|
1293
1333
|
$defs: defs
|
|
1294
1334
|
};
|