@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/index.mjs
CHANGED
|
@@ -455,28 +455,72 @@ else {
|
|
|
455
455
|
*
|
|
456
456
|
* - **Single PK** (one `@meta.id`) → `static __pk: <scalar type>`
|
|
457
457
|
* - **Compound PK** (multiple `@meta.id`) → `static __pk: { field1: Type1; field2: Type2 }`
|
|
458
|
-
* - **No PK** → no `__pk` emitted
|
|
458
|
+
* - **No PK** → no `__pk` emitted (unless unique indexes exist)
|
|
459
|
+
* - **Unique indexes** (`@db.index.unique`) → appended as union members
|
|
460
|
+
* - **Mongo collection** → always includes `string` (ObjectId) in the union;
|
|
461
|
+
* if no `@meta.id` fields, `__pk` is just `string`
|
|
459
462
|
*/ renderPk(node) {
|
|
463
|
+
const isMongoCollection = !!node.annotations?.some((a) => a.name === "db.mongo.collection");
|
|
460
464
|
let struct;
|
|
461
465
|
if (node.hasExtends) struct = this.doc.resolveInterfaceExtends(node);
|
|
462
466
|
if (!struct) struct = node.getDefinition();
|
|
463
467
|
if (!struct || !isStructure(struct)) return;
|
|
468
|
+
const structNode = struct;
|
|
464
469
|
const pkProps = [];
|
|
465
|
-
|
|
470
|
+
const uniqueByIndex = new Map();
|
|
471
|
+
for (const [name, prop] of structNode.props) {
|
|
466
472
|
if (prop.token("identifier")?.pattern) continue;
|
|
473
|
+
if (isMongoCollection && name === "_id") continue;
|
|
467
474
|
if (prop.countAnnotations("meta.id") > 0) pkProps.push({
|
|
468
475
|
name,
|
|
469
476
|
prop
|
|
470
477
|
});
|
|
478
|
+
if (prop.annotations) {
|
|
479
|
+
for (const ann of prop.annotations) if (ann.name === "db.index.unique") {
|
|
480
|
+
const indexName = ann.args[0]?.text ?? name;
|
|
481
|
+
let group = uniqueByIndex.get(indexName);
|
|
482
|
+
if (!group) {
|
|
483
|
+
group = [];
|
|
484
|
+
uniqueByIndex.set(indexName, group);
|
|
485
|
+
}
|
|
486
|
+
group.push({
|
|
487
|
+
name,
|
|
488
|
+
prop
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
const uniqueProps = [];
|
|
494
|
+
const pkNames = new Set(pkProps.map((p) => p.name));
|
|
495
|
+
for (const fields of uniqueByIndex.values()) if (fields.length === 1 && !pkNames.has(fields[0].name)) uniqueProps.push(fields[0]);
|
|
496
|
+
if (pkProps.length === 0 && uniqueProps.length === 0 && !isMongoCollection) return;
|
|
497
|
+
let mongoIdType;
|
|
498
|
+
if (isMongoCollection) {
|
|
499
|
+
const idProp = structNode.props.get("_id");
|
|
500
|
+
if (idProp) mongoIdType = this.renderTypeDefString(idProp.getDefinition()).trim();
|
|
501
|
+
mongoIdType ?? (mongoIdType = "string");
|
|
502
|
+
}
|
|
503
|
+
const uniqueTypes = [];
|
|
504
|
+
const seenTypes = new Set();
|
|
505
|
+
for (const { prop } of uniqueProps) {
|
|
506
|
+
const rendered = this.renderTypeDefString(prop.getDefinition()).trim();
|
|
507
|
+
if (!seenTypes.has(rendered)) {
|
|
508
|
+
seenTypes.add(rendered);
|
|
509
|
+
uniqueTypes.push(rendered);
|
|
510
|
+
}
|
|
471
511
|
}
|
|
472
|
-
if (pkProps.length === 0) return;
|
|
473
512
|
this.writeln();
|
|
474
|
-
|
|
513
|
+
const uniqueSuffix = uniqueTypes.length > 0 ? ` | ${uniqueTypes.join(" | ")}` : "";
|
|
514
|
+
if (pkProps.length === 0 && !isMongoCollection) this.writeln(`static __pk: ${uniqueTypes.join(" | ")}`);
|
|
515
|
+
else if (pkProps.length === 0) this.writeln(`static __pk: ${mongoIdType}${uniqueSuffix}`);
|
|
516
|
+
else if (pkProps.length === 1) {
|
|
475
517
|
this.write("static __pk: ");
|
|
476
|
-
|
|
477
|
-
renderedDef.
|
|
518
|
+
if (isMongoCollection) this.write(`${mongoIdType} | `);
|
|
519
|
+
const renderedDef = this.renderTypeDefString(pkProps[0].prop.getDefinition()).trim();
|
|
520
|
+
this.writeln(`${renderedDef}${uniqueSuffix}`);
|
|
478
521
|
} else {
|
|
479
522
|
this.write("static __pk: ");
|
|
523
|
+
if (isMongoCollection) this.write(`${mongoIdType} | `);
|
|
480
524
|
this.blockln("{}");
|
|
481
525
|
for (const { name, prop } of pkProps) {
|
|
482
526
|
this.write(wrapProp(name), ": ");
|
|
@@ -484,6 +528,7 @@ else {
|
|
|
484
528
|
renderedDef.split("\n").forEach((l) => this.writeln(l));
|
|
485
529
|
}
|
|
486
530
|
this.pop();
|
|
531
|
+
this.writeln(uniqueSuffix);
|
|
487
532
|
}
|
|
488
533
|
}
|
|
489
534
|
phantomPropType(def) {
|
|
@@ -971,6 +1016,24 @@ var ValidatorError = class extends Error {
|
|
|
971
1016
|
|
|
972
1017
|
//#endregion
|
|
973
1018
|
//#region packages/typescript/src/annotated-type.ts
|
|
1019
|
+
const COMPLEX_KINDS = new Set([
|
|
1020
|
+
"union",
|
|
1021
|
+
"intersection",
|
|
1022
|
+
"tuple"
|
|
1023
|
+
]);
|
|
1024
|
+
/** Shared validator method reused by all annotated type nodes. */ function validatorMethod(opts) {
|
|
1025
|
+
return new Validator(this, opts);
|
|
1026
|
+
}
|
|
1027
|
+
function createAnnotatedTypeNode(type, metadata, opts) {
|
|
1028
|
+
return {
|
|
1029
|
+
__is_atscript_annotated_type: true,
|
|
1030
|
+
type,
|
|
1031
|
+
metadata,
|
|
1032
|
+
validator: validatorMethod,
|
|
1033
|
+
id: opts?.id,
|
|
1034
|
+
optional: opts?.optional
|
|
1035
|
+
};
|
|
1036
|
+
}
|
|
974
1037
|
function isAnnotatedType(type) {
|
|
975
1038
|
return type && type.__is_atscript_annotated_type;
|
|
976
1039
|
}
|
|
@@ -987,38 +1050,24 @@ function defineAnnotatedType(_kind, base) {
|
|
|
987
1050
|
const kind = _kind || "";
|
|
988
1051
|
const type = base?.type || {};
|
|
989
1052
|
type.kind = kind;
|
|
990
|
-
if ([
|
|
991
|
-
"union",
|
|
992
|
-
"intersection",
|
|
993
|
-
"tuple"
|
|
994
|
-
].includes(kind)) type.items = [];
|
|
1053
|
+
if (COMPLEX_KINDS.has(kind)) type.items = [];
|
|
995
1054
|
if (kind === "object") {
|
|
996
1055
|
type.props = new Map();
|
|
997
1056
|
type.propsPatterns = [];
|
|
998
1057
|
}
|
|
999
1058
|
type.tags = new Set();
|
|
1000
1059
|
const metadata = base?.metadata || new Map();
|
|
1001
|
-
|
|
1060
|
+
const payload = {
|
|
1002
1061
|
__is_atscript_annotated_type: true,
|
|
1003
1062
|
metadata,
|
|
1004
1063
|
type,
|
|
1005
|
-
validator
|
|
1006
|
-
return new Validator(this, opts);
|
|
1007
|
-
}
|
|
1008
|
-
});
|
|
1009
|
-
else base = {
|
|
1010
|
-
__is_atscript_annotated_type: true,
|
|
1011
|
-
metadata,
|
|
1012
|
-
type,
|
|
1013
|
-
validator(opts) {
|
|
1014
|
-
return new Validator(this, opts);
|
|
1015
|
-
}
|
|
1064
|
+
validator: validatorMethod
|
|
1016
1065
|
};
|
|
1066
|
+
base = base ? Object.assign(base, payload) : payload;
|
|
1017
1067
|
const handle = {
|
|
1018
1068
|
$type: base,
|
|
1019
1069
|
$def: type,
|
|
1020
1070
|
$metadata: metadata,
|
|
1021
|
-
_existingObject: undefined,
|
|
1022
1071
|
tags(...tags) {
|
|
1023
1072
|
for (const tag of tags) this.$def.tags.add(tag);
|
|
1024
1073
|
return this;
|
|
@@ -1059,27 +1108,18 @@ else base = {
|
|
|
1059
1108
|
return this;
|
|
1060
1109
|
},
|
|
1061
1110
|
refTo(type$1, chain) {
|
|
1111
|
+
if (!isAnnotatedType(type$1)) throw new Error(`${type$1} is not annotated type`);
|
|
1062
1112
|
let newBase = type$1;
|
|
1063
1113
|
const typeName = type$1.name || "Unknown";
|
|
1064
|
-
if (
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1114
|
+
if (chain) for (let i = 0; i < chain.length; i++) {
|
|
1115
|
+
const c = chain[i];
|
|
1116
|
+
if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
|
|
1117
|
+
else {
|
|
1118
|
+
const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
|
|
1119
|
+
throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
1070
1120
|
}
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
this.$type = {
|
|
1074
|
-
__is_atscript_annotated_type: true,
|
|
1075
|
-
type: newBase.type,
|
|
1076
|
-
metadata,
|
|
1077
|
-
id: newBase.id,
|
|
1078
|
-
validator(opts) {
|
|
1079
|
-
return new Validator(this, opts);
|
|
1080
|
-
}
|
|
1081
|
-
};
|
|
1082
|
-
} else throw new Error(`${type$1} is not annotated type`);
|
|
1121
|
+
}
|
|
1122
|
+
this.$type = createAnnotatedTypeNode(newBase.type, metadata, { id: newBase.id });
|
|
1083
1123
|
return this;
|
|
1084
1124
|
},
|
|
1085
1125
|
annotate(key, value, asArray) {
|
|
@@ -1129,10 +1169,10 @@ function forAnnotatedType(def, handlers) {
|
|
|
1129
1169
|
const firstObj = items[0].type;
|
|
1130
1170
|
const candidates = [];
|
|
1131
1171
|
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
1132
|
-
|
|
1172
|
+
let result = null;
|
|
1133
1173
|
for (const candidate of candidates) {
|
|
1134
1174
|
const values = new Set();
|
|
1135
|
-
const
|
|
1175
|
+
const indexMapping = {};
|
|
1136
1176
|
let valid = true;
|
|
1137
1177
|
for (let i = 0; i < items.length; i++) {
|
|
1138
1178
|
const obj = items[i].type;
|
|
@@ -1147,19 +1187,21 @@ function forAnnotatedType(def, handlers) {
|
|
|
1147
1187
|
break;
|
|
1148
1188
|
}
|
|
1149
1189
|
values.add(val);
|
|
1150
|
-
|
|
1190
|
+
indexMapping[String(val)] = i;
|
|
1191
|
+
}
|
|
1192
|
+
if (valid) {
|
|
1193
|
+
if (result) return null;
|
|
1194
|
+
result = {
|
|
1195
|
+
propertyName: candidate,
|
|
1196
|
+
indexMapping
|
|
1197
|
+
};
|
|
1151
1198
|
}
|
|
1152
|
-
if (valid) validCandidates.push({
|
|
1153
|
-
propertyName: candidate,
|
|
1154
|
-
mapping
|
|
1155
|
-
});
|
|
1156
1199
|
}
|
|
1157
|
-
|
|
1158
|
-
return null;
|
|
1200
|
+
return result;
|
|
1159
1201
|
}
|
|
1160
1202
|
function buildJsonSchema(type) {
|
|
1161
1203
|
const defs = {};
|
|
1162
|
-
let
|
|
1204
|
+
let hasDefs = false;
|
|
1163
1205
|
const buildObject = (d) => {
|
|
1164
1206
|
const properties = {};
|
|
1165
1207
|
const required = [];
|
|
@@ -1176,15 +1218,15 @@ function buildJsonSchema(type) {
|
|
|
1176
1218
|
return schema$1;
|
|
1177
1219
|
};
|
|
1178
1220
|
const build = (def) => {
|
|
1179
|
-
if (def.id && def.type.kind === "object" &&
|
|
1221
|
+
if (def.id && def.type.kind === "object" && def !== type) {
|
|
1180
1222
|
const name = def.id;
|
|
1181
1223
|
if (!defs[name]) {
|
|
1224
|
+
hasDefs = true;
|
|
1182
1225
|
defs[name] = {};
|
|
1183
1226
|
defs[name] = buildObject(def);
|
|
1184
1227
|
}
|
|
1185
1228
|
return { $ref: `#/$defs/${name}` };
|
|
1186
1229
|
}
|
|
1187
|
-
isRoot = false;
|
|
1188
1230
|
const meta = def.metadata;
|
|
1189
1231
|
return forAnnotatedType(def, {
|
|
1190
1232
|
phantom() {
|
|
@@ -1209,11 +1251,9 @@ function buildJsonSchema(type) {
|
|
|
1209
1251
|
if (disc) {
|
|
1210
1252
|
const oneOf = d.type.items.map(build);
|
|
1211
1253
|
const mapping = {};
|
|
1212
|
-
for (const [val,
|
|
1213
|
-
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
1254
|
+
for (const [val, idx] of Object.entries(disc.indexMapping)) {
|
|
1214
1255
|
const item = d.type.items[idx];
|
|
1215
|
-
|
|
1216
|
-
else mapping[val] = origPath;
|
|
1256
|
+
mapping[val] = item.id && defs[item.id] ? `#/$defs/${item.id}` : `#/oneOf/${idx}`;
|
|
1217
1257
|
}
|
|
1218
1258
|
return {
|
|
1219
1259
|
oneOf,
|
|
@@ -1263,7 +1303,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
|
|
|
1263
1303
|
});
|
|
1264
1304
|
};
|
|
1265
1305
|
const schema = build(type);
|
|
1266
|
-
if (
|
|
1306
|
+
if (hasDefs) return {
|
|
1267
1307
|
...schema,
|
|
1268
1308
|
$defs: defs
|
|
1269
1309
|
};
|
package/dist/utils.cjs
CHANGED
|
@@ -436,6 +436,25 @@ var ValidatorError = class extends Error {
|
|
|
436
436
|
|
|
437
437
|
//#endregion
|
|
438
438
|
//#region packages/typescript/src/annotated-type.ts
|
|
439
|
+
const COMPLEX_KINDS = new Set([
|
|
440
|
+
"union",
|
|
441
|
+
"intersection",
|
|
442
|
+
"tuple"
|
|
443
|
+
]);
|
|
444
|
+
const NON_PRIMITIVE_KINDS = new Set(["array", "object"]);
|
|
445
|
+
/** Shared validator method reused by all annotated type nodes. */ function validatorMethod(opts) {
|
|
446
|
+
return new Validator(this, opts);
|
|
447
|
+
}
|
|
448
|
+
function createAnnotatedTypeNode(type, metadata, opts) {
|
|
449
|
+
return {
|
|
450
|
+
__is_atscript_annotated_type: true,
|
|
451
|
+
type,
|
|
452
|
+
metadata,
|
|
453
|
+
validator: validatorMethod,
|
|
454
|
+
id: opts?.id,
|
|
455
|
+
optional: opts?.optional
|
|
456
|
+
};
|
|
457
|
+
}
|
|
439
458
|
function isAnnotatedType(type) {
|
|
440
459
|
return type && type.__is_atscript_annotated_type;
|
|
441
460
|
}
|
|
@@ -454,32 +473,22 @@ function cloneRefProp(parentType, propName) {
|
|
|
454
473
|
const existing = objType.props.get(propName);
|
|
455
474
|
if (!existing) return;
|
|
456
475
|
const clonedType = cloneTypeDef(existing.type);
|
|
457
|
-
objType.props.set(propName, {
|
|
458
|
-
__is_atscript_annotated_type: true,
|
|
459
|
-
type: clonedType,
|
|
460
|
-
metadata: new Map(existing.metadata),
|
|
476
|
+
objType.props.set(propName, createAnnotatedTypeNode(clonedType, new Map(existing.metadata), {
|
|
461
477
|
id: existing.id,
|
|
462
|
-
optional: existing.optional
|
|
463
|
-
|
|
464
|
-
return new Validator(this, opts);
|
|
465
|
-
}
|
|
466
|
-
});
|
|
478
|
+
optional: existing.optional
|
|
479
|
+
}));
|
|
467
480
|
}
|
|
468
481
|
function cloneTypeDef(type) {
|
|
469
482
|
if (type.kind === "object") {
|
|
470
483
|
const obj = type;
|
|
484
|
+
const props = new Map();
|
|
485
|
+
for (const [k, v] of obj.props) props.set(k, createAnnotatedTypeNode(v.type, new Map(v.metadata), {
|
|
486
|
+
id: v.id,
|
|
487
|
+
optional: v.optional
|
|
488
|
+
}));
|
|
471
489
|
return {
|
|
472
490
|
kind: "object",
|
|
473
|
-
props
|
|
474
|
-
__is_atscript_annotated_type: true,
|
|
475
|
-
type: v.type,
|
|
476
|
-
metadata: new Map(v.metadata),
|
|
477
|
-
id: v.id,
|
|
478
|
-
optional: v.optional,
|
|
479
|
-
validator(opts) {
|
|
480
|
-
return new Validator(this, opts);
|
|
481
|
-
}
|
|
482
|
-
}])),
|
|
491
|
+
props,
|
|
483
492
|
propsPatterns: [...obj.propsPatterns],
|
|
484
493
|
tags: new Set(obj.tags)
|
|
485
494
|
};
|
|
@@ -509,38 +518,24 @@ function defineAnnotatedType(_kind, base) {
|
|
|
509
518
|
const kind = _kind || "";
|
|
510
519
|
const type = base?.type || {};
|
|
511
520
|
type.kind = kind;
|
|
512
|
-
if ([
|
|
513
|
-
"union",
|
|
514
|
-
"intersection",
|
|
515
|
-
"tuple"
|
|
516
|
-
].includes(kind)) type.items = [];
|
|
521
|
+
if (COMPLEX_KINDS.has(kind)) type.items = [];
|
|
517
522
|
if (kind === "object") {
|
|
518
523
|
type.props = new Map();
|
|
519
524
|
type.propsPatterns = [];
|
|
520
525
|
}
|
|
521
526
|
type.tags = new Set();
|
|
522
527
|
const metadata = base?.metadata || new Map();
|
|
523
|
-
|
|
524
|
-
__is_atscript_annotated_type: true,
|
|
525
|
-
metadata,
|
|
526
|
-
type,
|
|
527
|
-
validator(opts) {
|
|
528
|
-
return new Validator(this, opts);
|
|
529
|
-
}
|
|
530
|
-
});
|
|
531
|
-
else base = {
|
|
528
|
+
const payload = {
|
|
532
529
|
__is_atscript_annotated_type: true,
|
|
533
530
|
metadata,
|
|
534
531
|
type,
|
|
535
|
-
validator
|
|
536
|
-
return new Validator(this, opts);
|
|
537
|
-
}
|
|
532
|
+
validator: validatorMethod
|
|
538
533
|
};
|
|
534
|
+
base = base ? Object.assign(base, payload) : payload;
|
|
539
535
|
const handle = {
|
|
540
536
|
$type: base,
|
|
541
537
|
$def: type,
|
|
542
538
|
$metadata: metadata,
|
|
543
|
-
_existingObject: undefined,
|
|
544
539
|
tags(...tags) {
|
|
545
540
|
for (const tag of tags) this.$def.tags.add(tag);
|
|
546
541
|
return this;
|
|
@@ -581,27 +576,18 @@ else base = {
|
|
|
581
576
|
return this;
|
|
582
577
|
},
|
|
583
578
|
refTo(type$1, chain) {
|
|
579
|
+
if (!isAnnotatedType(type$1)) throw new Error(`${type$1} is not annotated type`);
|
|
584
580
|
let newBase = type$1;
|
|
585
581
|
const typeName = type$1.name || "Unknown";
|
|
586
|
-
if (
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
582
|
+
if (chain) for (let i = 0; i < chain.length; i++) {
|
|
583
|
+
const c = chain[i];
|
|
584
|
+
if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
|
|
585
|
+
else {
|
|
586
|
+
const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
|
|
587
|
+
throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
592
588
|
}
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
this.$type = {
|
|
596
|
-
__is_atscript_annotated_type: true,
|
|
597
|
-
type: newBase.type,
|
|
598
|
-
metadata,
|
|
599
|
-
id: newBase.id,
|
|
600
|
-
validator(opts) {
|
|
601
|
-
return new Validator(this, opts);
|
|
602
|
-
}
|
|
603
|
-
};
|
|
604
|
-
} else throw new Error(`${type$1} is not annotated type`);
|
|
589
|
+
}
|
|
590
|
+
this.$type = createAnnotatedTypeNode(newBase.type, metadata, { id: newBase.id });
|
|
605
591
|
return this;
|
|
606
592
|
},
|
|
607
593
|
annotate(key, value, asArray) {
|
|
@@ -619,13 +605,9 @@ function isPhantomType(def) {
|
|
|
619
605
|
return def.type.kind === "" && def.type.designType === "phantom";
|
|
620
606
|
}
|
|
621
607
|
function isAnnotatedTypeOfPrimitive(t) {
|
|
622
|
-
if (
|
|
608
|
+
if (NON_PRIMITIVE_KINDS.has(t.type.kind)) return false;
|
|
623
609
|
if (!t.type.kind) return true;
|
|
624
|
-
if (
|
|
625
|
-
"union",
|
|
626
|
-
"tuple",
|
|
627
|
-
"intersection"
|
|
628
|
-
].includes(t.type.kind)) {
|
|
610
|
+
if (COMPLEX_KINDS.has(t.type.kind)) {
|
|
629
611
|
for (const item of t.type.items) if (!isAnnotatedTypeOfPrimitive(item)) return false;
|
|
630
612
|
return true;
|
|
631
613
|
}
|
|
@@ -664,10 +646,10 @@ function forAnnotatedType(def, handlers) {
|
|
|
664
646
|
const firstObj = items[0].type;
|
|
665
647
|
const candidates = [];
|
|
666
648
|
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
667
|
-
|
|
649
|
+
let result = null;
|
|
668
650
|
for (const candidate of candidates) {
|
|
669
651
|
const values = new Set();
|
|
670
|
-
const
|
|
652
|
+
const indexMapping = {};
|
|
671
653
|
let valid = true;
|
|
672
654
|
for (let i = 0; i < items.length; i++) {
|
|
673
655
|
const obj = items[i].type;
|
|
@@ -682,19 +664,21 @@ function forAnnotatedType(def, handlers) {
|
|
|
682
664
|
break;
|
|
683
665
|
}
|
|
684
666
|
values.add(val);
|
|
685
|
-
|
|
667
|
+
indexMapping[String(val)] = i;
|
|
668
|
+
}
|
|
669
|
+
if (valid) {
|
|
670
|
+
if (result) return null;
|
|
671
|
+
result = {
|
|
672
|
+
propertyName: candidate,
|
|
673
|
+
indexMapping
|
|
674
|
+
};
|
|
686
675
|
}
|
|
687
|
-
if (valid) validCandidates.push({
|
|
688
|
-
propertyName: candidate,
|
|
689
|
-
mapping
|
|
690
|
-
});
|
|
691
676
|
}
|
|
692
|
-
|
|
693
|
-
return null;
|
|
677
|
+
return result;
|
|
694
678
|
}
|
|
695
679
|
function buildJsonSchema(type) {
|
|
696
680
|
const defs = {};
|
|
697
|
-
let
|
|
681
|
+
let hasDefs = false;
|
|
698
682
|
const buildObject = (d) => {
|
|
699
683
|
const properties = {};
|
|
700
684
|
const required = [];
|
|
@@ -711,15 +695,15 @@ function buildJsonSchema(type) {
|
|
|
711
695
|
return schema$1;
|
|
712
696
|
};
|
|
713
697
|
const build$1 = (def) => {
|
|
714
|
-
if (def.id && def.type.kind === "object" &&
|
|
698
|
+
if (def.id && def.type.kind === "object" && def !== type) {
|
|
715
699
|
const name = def.id;
|
|
716
700
|
if (!defs[name]) {
|
|
701
|
+
hasDefs = true;
|
|
717
702
|
defs[name] = {};
|
|
718
703
|
defs[name] = buildObject(def);
|
|
719
704
|
}
|
|
720
705
|
return { $ref: `#/$defs/${name}` };
|
|
721
706
|
}
|
|
722
|
-
isRoot = false;
|
|
723
707
|
const meta = def.metadata;
|
|
724
708
|
return forAnnotatedType(def, {
|
|
725
709
|
phantom() {
|
|
@@ -744,11 +728,9 @@ function buildJsonSchema(type) {
|
|
|
744
728
|
if (disc) {
|
|
745
729
|
const oneOf = d.type.items.map(build$1);
|
|
746
730
|
const mapping = {};
|
|
747
|
-
for (const [val,
|
|
748
|
-
const idx = Number.parseInt(origPath.split("/").pop(), 10);
|
|
731
|
+
for (const [val, idx] of Object.entries(disc.indexMapping)) {
|
|
749
732
|
const item = d.type.items[idx];
|
|
750
|
-
|
|
751
|
-
else mapping[val] = origPath;
|
|
733
|
+
mapping[val] = item.id && defs[item.id] ? `#/$defs/${item.id}` : `#/oneOf/${idx}`;
|
|
752
734
|
}
|
|
753
735
|
return {
|
|
754
736
|
oneOf,
|
|
@@ -798,7 +780,7 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
|
|
|
798
780
|
});
|
|
799
781
|
};
|
|
800
782
|
const schema = build$1(type);
|
|
801
|
-
if (
|
|
783
|
+
if (hasDefs) return {
|
|
802
784
|
...schema,
|
|
803
785
|
$defs: defs
|
|
804
786
|
};
|
|
@@ -813,6 +795,8 @@ function fromJsonSchema(schema) {
|
|
|
813
795
|
const refName = s.$ref.replace(/^#\/(\$defs|definitions)\//, "");
|
|
814
796
|
if (resolved.has(refName)) return resolved.get(refName);
|
|
815
797
|
if (defsSource[refName]) {
|
|
798
|
+
const placeholder = defineAnnotatedType().designType("any").$type;
|
|
799
|
+
resolved.set(refName, placeholder);
|
|
816
800
|
const type = convert(defsSource[refName]);
|
|
817
801
|
resolved.set(refName, type);
|
|
818
802
|
return type;
|
|
@@ -1223,16 +1207,10 @@ function deserializeAnnotatedType(data) {
|
|
|
1223
1207
|
function deserializeNode(data) {
|
|
1224
1208
|
const metadata = new Map(Object.entries(data.metadata));
|
|
1225
1209
|
const type = deserializeTypeDef(data.type);
|
|
1226
|
-
const result = {
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
validator(opts) {
|
|
1231
|
-
return new Validator(this, opts);
|
|
1232
|
-
}
|
|
1233
|
-
};
|
|
1234
|
-
if (data.optional) result.optional = true;
|
|
1235
|
-
if (data.id) result.id = data.id;
|
|
1210
|
+
const result = createAnnotatedTypeNode(type, metadata, {
|
|
1211
|
+
optional: data.optional || undefined,
|
|
1212
|
+
id: data.id || undefined
|
|
1213
|
+
});
|
|
1236
1214
|
return result;
|
|
1237
1215
|
}
|
|
1238
1216
|
function deserializeTypeDef(t) {
|
|
@@ -1284,6 +1262,7 @@ exports.ValidatorError = ValidatorError
|
|
|
1284
1262
|
exports.annotate = annotate
|
|
1285
1263
|
exports.buildJsonSchema = buildJsonSchema
|
|
1286
1264
|
exports.cloneRefProp = cloneRefProp
|
|
1265
|
+
exports.createAnnotatedTypeNode = createAnnotatedTypeNode
|
|
1287
1266
|
exports.createDataFromAnnotatedType = createDataFromAnnotatedType
|
|
1288
1267
|
exports.defineAnnotatedType = defineAnnotatedType
|
|
1289
1268
|
exports.deserializeAnnotatedType = deserializeAnnotatedType
|
package/dist/utils.d.ts
CHANGED
|
@@ -96,6 +96,14 @@ declare class ValidatorError extends Error {
|
|
|
96
96
|
constructor(errors: TError[]);
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* Creates a minimal annotated type node from a type def and metadata map.
|
|
101
|
+
* Centralises the shape so callers never duplicate the boilerplate.
|
|
102
|
+
*/
|
|
103
|
+
declare function createAnnotatedTypeNode(type: TAtscriptTypeDef, metadata: TMetadataMap<AtscriptMetadata>, opts?: {
|
|
104
|
+
id?: string;
|
|
105
|
+
optional?: boolean;
|
|
106
|
+
}): TAtscriptAnnotatedType;
|
|
99
107
|
/** Type definition for union, intersection, or tuple types. */
|
|
100
108
|
interface TAtscriptTypeComplex<DataType = unknown> {
|
|
101
109
|
kind: 'union' | 'intersection' | 'tuple';
|
|
@@ -235,7 +243,6 @@ interface TAnnotatedTypeHandle {
|
|
|
235
243
|
kind: TKind;
|
|
236
244
|
} & Omit<TAtscriptTypeComplex, 'kind'> & Omit<TAtscriptTypeFinal, 'kind'> & Omit<TAtscriptTypeArray, 'kind'> & Omit<TAtscriptTypeObject<string>, 'kind'>;
|
|
237
245
|
$metadata: TMetadataMap<AtscriptMetadata>;
|
|
238
|
-
_existingObject: TAtscriptAnnotatedType | undefined;
|
|
239
246
|
tags(...tags: string[]): TAnnotatedTypeHandle;
|
|
240
247
|
designType(value: TAtscriptTypeFinal['designType']): TAnnotatedTypeHandle;
|
|
241
248
|
value(value: string | number | boolean): TAnnotatedTypeHandle;
|
|
@@ -559,5 +566,5 @@ type PrimaryKeyOf<T> = T extends {
|
|
|
559
566
|
__pk: infer PK;
|
|
560
567
|
} ? PK : unknown;
|
|
561
568
|
|
|
562
|
-
export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, cloneRefProp, createDataFromAnnotatedType, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, mergeJsonSchemas, serializeAnnotatedType, throwFeatureDisabled };
|
|
569
|
+
export { SERIALIZE_VERSION, Validator, ValidatorError, annotate, buildJsonSchema, cloneRefProp, createAnnotatedTypeNode, createDataFromAnnotatedType, defineAnnotatedType, deserializeAnnotatedType, flattenAnnotatedType, forAnnotatedType, fromJsonSchema, isAnnotatedType, isAnnotatedTypeOfPrimitive, isPhantomType, mergeJsonSchemas, serializeAnnotatedType, throwFeatureDisabled };
|
|
563
570
|
export type { FlatOf, InferDataType, PrimaryKeyOf, TAnnotatedTypeHandle, TAtscriptAnnotatedType, TAtscriptAnnotatedTypeConstructor, TAtscriptDataType, TAtscriptTypeArray, TAtscriptTypeComplex, TAtscriptTypeDef, TAtscriptTypeFinal, TAtscriptTypeObject, TCreateDataOptions, TFlattenOptions, TJsonSchema, TMetadataMap, TProcessAnnotationContext, TSerializeOptions, TSerializedAnnotatedType, TSerializedAnnotatedTypeInner, TSerializedTypeArray, TSerializedTypeComplex, TSerializedTypeDef, TSerializedTypeFinal, TSerializedTypeObject, TValidatorOptions, TValidatorPlugin, TValidatorPluginContext, TValueResolver };
|