@atscript/typescript 0.1.23 → 0.1.25
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 +48 -0
- package/dist/index.cjs +48 -0
- package/dist/index.mjs +48 -0
- package/dist/utils.cjs +60 -3
- package/dist/utils.d.ts +2 -2
- package/dist/utils.mjs +60 -3
- package/package.json +2 -2
- package/skills/atscript-typescript/SKILL.md +1 -1
- package/skills/atscript-typescript/utilities.md +8 -3
package/dist/cli.cjs
CHANGED
|
@@ -991,6 +991,46 @@ function isPhantomType(def) {
|
|
|
991
991
|
|
|
992
992
|
//#endregion
|
|
993
993
|
//#region packages/typescript/src/json-schema.ts
|
|
994
|
+
/**
|
|
995
|
+
* Detects a discriminator property across union items.
|
|
996
|
+
*
|
|
997
|
+
* Scans all items for object-typed members that share a common property
|
|
998
|
+
* with distinct const/literal values. If exactly one such property exists,
|
|
999
|
+
* it is returned as the discriminator.
|
|
1000
|
+
*/ function detectDiscriminator(items) {
|
|
1001
|
+
if (items.length < 2) return null;
|
|
1002
|
+
for (const item of items) if (item.type.kind !== "object") return null;
|
|
1003
|
+
const firstObj = items[0].type;
|
|
1004
|
+
const candidates = [];
|
|
1005
|
+
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
1006
|
+
const validCandidates = [];
|
|
1007
|
+
for (const candidate of candidates) {
|
|
1008
|
+
const values = new Set();
|
|
1009
|
+
const mapping = {};
|
|
1010
|
+
let valid = true;
|
|
1011
|
+
for (let i = 0; i < items.length; i++) {
|
|
1012
|
+
const obj = items[i].type;
|
|
1013
|
+
const prop = obj.props.get(candidate);
|
|
1014
|
+
if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
|
|
1015
|
+
valid = false;
|
|
1016
|
+
break;
|
|
1017
|
+
}
|
|
1018
|
+
const val = prop.type.value;
|
|
1019
|
+
if (values.has(val)) {
|
|
1020
|
+
valid = false;
|
|
1021
|
+
break;
|
|
1022
|
+
}
|
|
1023
|
+
values.add(val);
|
|
1024
|
+
mapping[String(val)] = `#/oneOf/${i}`;
|
|
1025
|
+
}
|
|
1026
|
+
if (valid) validCandidates.push({
|
|
1027
|
+
propertyName: candidate,
|
|
1028
|
+
mapping
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
if (validCandidates.length === 1) return validCandidates[0];
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
994
1034
|
function buildJsonSchema(type) {
|
|
995
1035
|
const build$1 = (def) => {
|
|
996
1036
|
const meta = def.metadata;
|
|
@@ -1025,6 +1065,14 @@ function buildJsonSchema(type) {
|
|
|
1025
1065
|
return schema;
|
|
1026
1066
|
},
|
|
1027
1067
|
union(d) {
|
|
1068
|
+
const disc = detectDiscriminator(d.type.items);
|
|
1069
|
+
if (disc) return {
|
|
1070
|
+
oneOf: d.type.items.map(build$1),
|
|
1071
|
+
discriminator: {
|
|
1072
|
+
propertyName: disc.propertyName,
|
|
1073
|
+
mapping: disc.mapping
|
|
1074
|
+
}
|
|
1075
|
+
};
|
|
1028
1076
|
return { anyOf: d.type.items.map(build$1) };
|
|
1029
1077
|
},
|
|
1030
1078
|
intersection(d) {
|
package/dist/index.cjs
CHANGED
|
@@ -988,6 +988,46 @@ function isPhantomType(def) {
|
|
|
988
988
|
|
|
989
989
|
//#endregion
|
|
990
990
|
//#region packages/typescript/src/json-schema.ts
|
|
991
|
+
/**
|
|
992
|
+
* Detects a discriminator property across union items.
|
|
993
|
+
*
|
|
994
|
+
* Scans all items for object-typed members that share a common property
|
|
995
|
+
* with distinct const/literal values. If exactly one such property exists,
|
|
996
|
+
* it is returned as the discriminator.
|
|
997
|
+
*/ function detectDiscriminator(items) {
|
|
998
|
+
if (items.length < 2) return null;
|
|
999
|
+
for (const item of items) if (item.type.kind !== "object") return null;
|
|
1000
|
+
const firstObj = items[0].type;
|
|
1001
|
+
const candidates = [];
|
|
1002
|
+
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
1003
|
+
const validCandidates = [];
|
|
1004
|
+
for (const candidate of candidates) {
|
|
1005
|
+
const values = new Set();
|
|
1006
|
+
const mapping = {};
|
|
1007
|
+
let valid = true;
|
|
1008
|
+
for (let i = 0; i < items.length; i++) {
|
|
1009
|
+
const obj = items[i].type;
|
|
1010
|
+
const prop = obj.props.get(candidate);
|
|
1011
|
+
if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
|
|
1012
|
+
valid = false;
|
|
1013
|
+
break;
|
|
1014
|
+
}
|
|
1015
|
+
const val = prop.type.value;
|
|
1016
|
+
if (values.has(val)) {
|
|
1017
|
+
valid = false;
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
1020
|
+
values.add(val);
|
|
1021
|
+
mapping[String(val)] = `#/oneOf/${i}`;
|
|
1022
|
+
}
|
|
1023
|
+
if (valid) validCandidates.push({
|
|
1024
|
+
propertyName: candidate,
|
|
1025
|
+
mapping
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
if (validCandidates.length === 1) return validCandidates[0];
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
991
1031
|
function buildJsonSchema(type) {
|
|
992
1032
|
const build = (def) => {
|
|
993
1033
|
const meta = def.metadata;
|
|
@@ -1022,6 +1062,14 @@ function buildJsonSchema(type) {
|
|
|
1022
1062
|
return schema;
|
|
1023
1063
|
},
|
|
1024
1064
|
union(d) {
|
|
1065
|
+
const disc = detectDiscriminator(d.type.items);
|
|
1066
|
+
if (disc) return {
|
|
1067
|
+
oneOf: d.type.items.map(build),
|
|
1068
|
+
discriminator: {
|
|
1069
|
+
propertyName: disc.propertyName,
|
|
1070
|
+
mapping: disc.mapping
|
|
1071
|
+
}
|
|
1072
|
+
};
|
|
1025
1073
|
return { anyOf: d.type.items.map(build) };
|
|
1026
1074
|
},
|
|
1027
1075
|
intersection(d) {
|
package/dist/index.mjs
CHANGED
|
@@ -964,6 +964,46 @@ function isPhantomType(def) {
|
|
|
964
964
|
|
|
965
965
|
//#endregion
|
|
966
966
|
//#region packages/typescript/src/json-schema.ts
|
|
967
|
+
/**
|
|
968
|
+
* Detects a discriminator property across union items.
|
|
969
|
+
*
|
|
970
|
+
* Scans all items for object-typed members that share a common property
|
|
971
|
+
* with distinct const/literal values. If exactly one such property exists,
|
|
972
|
+
* it is returned as the discriminator.
|
|
973
|
+
*/ function detectDiscriminator(items) {
|
|
974
|
+
if (items.length < 2) return null;
|
|
975
|
+
for (const item of items) if (item.type.kind !== "object") return null;
|
|
976
|
+
const firstObj = items[0].type;
|
|
977
|
+
const candidates = [];
|
|
978
|
+
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
979
|
+
const validCandidates = [];
|
|
980
|
+
for (const candidate of candidates) {
|
|
981
|
+
const values = new Set();
|
|
982
|
+
const mapping = {};
|
|
983
|
+
let valid = true;
|
|
984
|
+
for (let i = 0; i < items.length; i++) {
|
|
985
|
+
const obj = items[i].type;
|
|
986
|
+
const prop = obj.props.get(candidate);
|
|
987
|
+
if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
|
|
988
|
+
valid = false;
|
|
989
|
+
break;
|
|
990
|
+
}
|
|
991
|
+
const val = prop.type.value;
|
|
992
|
+
if (values.has(val)) {
|
|
993
|
+
valid = false;
|
|
994
|
+
break;
|
|
995
|
+
}
|
|
996
|
+
values.add(val);
|
|
997
|
+
mapping[String(val)] = `#/oneOf/${i}`;
|
|
998
|
+
}
|
|
999
|
+
if (valid) validCandidates.push({
|
|
1000
|
+
propertyName: candidate,
|
|
1001
|
+
mapping
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
if (validCandidates.length === 1) return validCandidates[0];
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
967
1007
|
function buildJsonSchema(type) {
|
|
968
1008
|
const build = (def) => {
|
|
969
1009
|
const meta = def.metadata;
|
|
@@ -998,6 +1038,14 @@ function buildJsonSchema(type) {
|
|
|
998
1038
|
return schema;
|
|
999
1039
|
},
|
|
1000
1040
|
union(d) {
|
|
1041
|
+
const disc = detectDiscriminator(d.type.items);
|
|
1042
|
+
if (disc) return {
|
|
1043
|
+
oneOf: d.type.items.map(build),
|
|
1044
|
+
discriminator: {
|
|
1045
|
+
propertyName: disc.propertyName,
|
|
1046
|
+
mapping: disc.mapping
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1001
1049
|
return { anyOf: d.type.items.map(build) };
|
|
1002
1050
|
},
|
|
1003
1051
|
intersection(d) {
|
package/dist/utils.cjs
CHANGED
|
@@ -552,6 +552,46 @@ function isAnnotatedTypeOfPrimitive(t) {
|
|
|
552
552
|
|
|
553
553
|
//#endregion
|
|
554
554
|
//#region packages/typescript/src/json-schema.ts
|
|
555
|
+
/**
|
|
556
|
+
* Detects a discriminator property across union items.
|
|
557
|
+
*
|
|
558
|
+
* Scans all items for object-typed members that share a common property
|
|
559
|
+
* with distinct const/literal values. If exactly one such property exists,
|
|
560
|
+
* it is returned as the discriminator.
|
|
561
|
+
*/ function detectDiscriminator(items) {
|
|
562
|
+
if (items.length < 2) return null;
|
|
563
|
+
for (const item of items) if (item.type.kind !== "object") return null;
|
|
564
|
+
const firstObj = items[0].type;
|
|
565
|
+
const candidates = [];
|
|
566
|
+
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
567
|
+
const validCandidates = [];
|
|
568
|
+
for (const candidate of candidates) {
|
|
569
|
+
const values = new Set();
|
|
570
|
+
const mapping = {};
|
|
571
|
+
let valid = true;
|
|
572
|
+
for (let i = 0; i < items.length; i++) {
|
|
573
|
+
const obj = items[i].type;
|
|
574
|
+
const prop = obj.props.get(candidate);
|
|
575
|
+
if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
|
|
576
|
+
valid = false;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
const val = prop.type.value;
|
|
580
|
+
if (values.has(val)) {
|
|
581
|
+
valid = false;
|
|
582
|
+
break;
|
|
583
|
+
}
|
|
584
|
+
values.add(val);
|
|
585
|
+
mapping[String(val)] = `#/oneOf/${i}`;
|
|
586
|
+
}
|
|
587
|
+
if (valid) validCandidates.push({
|
|
588
|
+
propertyName: candidate,
|
|
589
|
+
mapping
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
if (validCandidates.length === 1) return validCandidates[0];
|
|
593
|
+
return null;
|
|
594
|
+
}
|
|
555
595
|
function buildJsonSchema(type) {
|
|
556
596
|
const build$1 = (def) => {
|
|
557
597
|
const meta = def.metadata;
|
|
@@ -586,6 +626,14 @@ function buildJsonSchema(type) {
|
|
|
586
626
|
return schema;
|
|
587
627
|
},
|
|
588
628
|
union(d) {
|
|
629
|
+
const disc = detectDiscriminator(d.type.items);
|
|
630
|
+
if (disc) return {
|
|
631
|
+
oneOf: d.type.items.map(build$1),
|
|
632
|
+
discriminator: {
|
|
633
|
+
propertyName: disc.propertyName,
|
|
634
|
+
mapping: disc.mapping
|
|
635
|
+
}
|
|
636
|
+
};
|
|
589
637
|
return { anyOf: d.type.items.map(build$1) };
|
|
590
638
|
},
|
|
591
639
|
intersection(d) {
|
|
@@ -778,15 +826,24 @@ function build(def, path, mode) {
|
|
|
778
826
|
if (isPhantomType(prop)) continue;
|
|
779
827
|
const childPath = path ? `${path}.${key}` : key;
|
|
780
828
|
if (prop.optional) {
|
|
781
|
-
|
|
782
|
-
|
|
829
|
+
if (mode === "example") data[key] = build(prop, childPath, mode);
|
|
830
|
+
else {
|
|
831
|
+
const childResolved = resolveValue(prop, childPath, mode);
|
|
832
|
+
if (childResolved !== undefined) data[key] = childResolved.value;
|
|
833
|
+
}
|
|
783
834
|
continue;
|
|
784
835
|
}
|
|
785
836
|
data[key] = build(prop, childPath, mode);
|
|
786
837
|
}
|
|
787
838
|
return data;
|
|
788
839
|
},
|
|
789
|
-
array: () =>
|
|
840
|
+
array: (d) => {
|
|
841
|
+
if (mode === "example") {
|
|
842
|
+
const item = build(d.type.of, `${path}.0`, mode);
|
|
843
|
+
return item !== undefined ? [item] : [];
|
|
844
|
+
}
|
|
845
|
+
return [];
|
|
846
|
+
},
|
|
790
847
|
tuple: (d) => d.type.items.map((item, i) => build(item, `${path}.${i}`, mode)),
|
|
791
848
|
union: (d) => {
|
|
792
849
|
const first = d.type.items[0];
|
package/dist/utils.d.ts
CHANGED
|
@@ -332,7 +332,7 @@ interface TCreateDataOptions {
|
|
|
332
332
|
* How to resolve values:
|
|
333
333
|
* - `'empty'` — structural defaults only (`''`, `0`, `false`, `[]`, `{}`); optional props skipped
|
|
334
334
|
* - `'default'` — use `@meta.default` annotations; optional props skipped unless annotated
|
|
335
|
-
* - `'example'` — use `@meta.example` annotations; optional props
|
|
335
|
+
* - `'example'` — use `@meta.example` annotations; optional props always included; arrays get one sample item
|
|
336
336
|
* - `function` — custom resolver per field; optional props skipped unless resolver returns a value
|
|
337
337
|
*
|
|
338
338
|
* @default 'empty'
|
|
@@ -345,7 +345,7 @@ interface TCreateDataOptions {
|
|
|
345
345
|
* Supports four modes:
|
|
346
346
|
* - `'empty'` — structural defaults only; optional props omitted
|
|
347
347
|
* - `'default'` — uses `@meta.default` annotations; optional props omitted unless annotated
|
|
348
|
-
* - `'example'` — uses `@meta.example` annotations; optional props
|
|
348
|
+
* - `'example'` — uses `@meta.example` annotations; optional props always included; arrays get one sample item
|
|
349
349
|
* - `function` — custom resolver; optional props omitted unless resolver returns a value
|
|
350
350
|
*
|
|
351
351
|
* When a `@meta.default` / `@meta.example` value is set on a complex type (object, array)
|
package/dist/utils.mjs
CHANGED
|
@@ -551,6 +551,46 @@ function isAnnotatedTypeOfPrimitive(t) {
|
|
|
551
551
|
|
|
552
552
|
//#endregion
|
|
553
553
|
//#region packages/typescript/src/json-schema.ts
|
|
554
|
+
/**
|
|
555
|
+
* Detects a discriminator property across union items.
|
|
556
|
+
*
|
|
557
|
+
* Scans all items for object-typed members that share a common property
|
|
558
|
+
* with distinct const/literal values. If exactly one such property exists,
|
|
559
|
+
* it is returned as the discriminator.
|
|
560
|
+
*/ function detectDiscriminator(items) {
|
|
561
|
+
if (items.length < 2) return null;
|
|
562
|
+
for (const item of items) if (item.type.kind !== "object") return null;
|
|
563
|
+
const firstObj = items[0].type;
|
|
564
|
+
const candidates = [];
|
|
565
|
+
for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
|
|
566
|
+
const validCandidates = [];
|
|
567
|
+
for (const candidate of candidates) {
|
|
568
|
+
const values = new Set();
|
|
569
|
+
const mapping = {};
|
|
570
|
+
let valid = true;
|
|
571
|
+
for (let i = 0; i < items.length; i++) {
|
|
572
|
+
const obj = items[i].type;
|
|
573
|
+
const prop = obj.props.get(candidate);
|
|
574
|
+
if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
|
|
575
|
+
valid = false;
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
const val = prop.type.value;
|
|
579
|
+
if (values.has(val)) {
|
|
580
|
+
valid = false;
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
values.add(val);
|
|
584
|
+
mapping[String(val)] = `#/oneOf/${i}`;
|
|
585
|
+
}
|
|
586
|
+
if (valid) validCandidates.push({
|
|
587
|
+
propertyName: candidate,
|
|
588
|
+
mapping
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
if (validCandidates.length === 1) return validCandidates[0];
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
554
594
|
function buildJsonSchema(type) {
|
|
555
595
|
const build$1 = (def) => {
|
|
556
596
|
const meta = def.metadata;
|
|
@@ -585,6 +625,14 @@ function buildJsonSchema(type) {
|
|
|
585
625
|
return schema;
|
|
586
626
|
},
|
|
587
627
|
union(d) {
|
|
628
|
+
const disc = detectDiscriminator(d.type.items);
|
|
629
|
+
if (disc) return {
|
|
630
|
+
oneOf: d.type.items.map(build$1),
|
|
631
|
+
discriminator: {
|
|
632
|
+
propertyName: disc.propertyName,
|
|
633
|
+
mapping: disc.mapping
|
|
634
|
+
}
|
|
635
|
+
};
|
|
588
636
|
return { anyOf: d.type.items.map(build$1) };
|
|
589
637
|
},
|
|
590
638
|
intersection(d) {
|
|
@@ -777,15 +825,24 @@ function build(def, path, mode) {
|
|
|
777
825
|
if (isPhantomType(prop)) continue;
|
|
778
826
|
const childPath = path ? `${path}.${key}` : key;
|
|
779
827
|
if (prop.optional) {
|
|
780
|
-
|
|
781
|
-
|
|
828
|
+
if (mode === "example") data[key] = build(prop, childPath, mode);
|
|
829
|
+
else {
|
|
830
|
+
const childResolved = resolveValue(prop, childPath, mode);
|
|
831
|
+
if (childResolved !== undefined) data[key] = childResolved.value;
|
|
832
|
+
}
|
|
782
833
|
continue;
|
|
783
834
|
}
|
|
784
835
|
data[key] = build(prop, childPath, mode);
|
|
785
836
|
}
|
|
786
837
|
return data;
|
|
787
838
|
},
|
|
788
|
-
array: () =>
|
|
839
|
+
array: (d) => {
|
|
840
|
+
if (mode === "example") {
|
|
841
|
+
const item = build(d.type.of, `${path}.0`, mode);
|
|
842
|
+
return item !== undefined ? [item] : [];
|
|
843
|
+
}
|
|
844
|
+
return [];
|
|
845
|
+
},
|
|
789
846
|
tuple: (d) => d.type.items.map((item, i) => build(item, `${path}.${i}`, mode)),
|
|
790
847
|
union: (d) => {
|
|
791
848
|
const first = d.type.items[0];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.25",
|
|
4
4
|
"description": "Atscript: typescript-gen support.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"annotations",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"vitest": "3.2.4"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"@atscript/core": "^0.1.
|
|
67
|
+
"@atscript/core": "^0.1.25"
|
|
68
68
|
},
|
|
69
69
|
"build": [
|
|
70
70
|
{},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: atscript-typescript
|
|
3
|
-
description: Atscript TypeScript
|
|
3
|
+
description: Use when working with Atscript (.as files) in TypeScript projects — writing or editing .as interfaces/types/annotations, configuring atscript.config.ts or tsPlugin, understanding generated .d.ts/.js output, using runtime APIs (TAtscriptAnnotatedType, metadata, validators), generating JSON Schema or example data from types, serializing/deserializing annotated types, or running the asc CLI.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# @atscript/typescript
|
|
@@ -88,11 +88,15 @@ const schema = buildJsonSchema(User)
|
|
|
88
88
|
| `@expect.pattern` (multiple) | `allOf: [{ pattern }, ...]` |
|
|
89
89
|
| `@meta.required` on string | `minLength: 1` |
|
|
90
90
|
| optional property | not in `required` array |
|
|
91
|
-
| union | `anyOf` |
|
|
91
|
+
| union | `anyOf` (or `oneOf` + `discriminator` for discriminated unions) |
|
|
92
92
|
| intersection | `allOf` |
|
|
93
93
|
| tuple | `items` as array |
|
|
94
94
|
| phantom | empty object `{}` (excluded) |
|
|
95
95
|
|
|
96
|
+
### Discriminated Unions
|
|
97
|
+
|
|
98
|
+
When all union items are objects sharing exactly one property with distinct const/literal values, `buildJsonSchema` auto-detects it and emits `oneOf` with a `discriminator` object (including `propertyName` and `mapping`) instead of `anyOf`. No annotations needed — detection is automatic.
|
|
99
|
+
|
|
96
100
|
## `fromJsonSchema(schema)` — JSON Schema → Annotated Type
|
|
97
101
|
|
|
98
102
|
The inverse of `buildJsonSchema`. Creates a fully functional annotated type from a JSON Schema:
|
|
@@ -257,12 +261,13 @@ const custom = createDataFromAnnotatedType(User, {
|
|
|
257
261
|
|------|----------|
|
|
258
262
|
| `'empty'` (default) | Structural defaults: `''`, `0`, `false`, `[]`, `{}`. Optional props omitted |
|
|
259
263
|
| `'default'` | Uses `@meta.default` annotations. Optional props only included if annotated |
|
|
260
|
-
| `'example'` | Uses `@meta.example` annotations. Optional props
|
|
264
|
+
| `'example'` | Uses `@meta.example` annotations. Optional props always included. Arrays get one sample item |
|
|
261
265
|
| `function` | Custom resolver per field. Return `undefined` to fall through |
|
|
262
266
|
|
|
263
267
|
### Behavior Notes
|
|
264
268
|
|
|
265
|
-
- **Optional properties** are omitted unless the mode provides a value for them
|
|
269
|
+
- **Optional properties** are omitted unless the mode provides a value for them (exception: `'example'` mode always includes all optional props)
|
|
270
|
+
- **Arrays** in `'example'` mode generate one sample item from the element type instead of an empty array
|
|
266
271
|
- **Complex types** (object, array): if a `@meta.default`/`@meta.example` annotation is set and passes validation, the entire subtree is replaced (no recursion into inner props)
|
|
267
272
|
- **Annotation values**: strings are used as-is for string types; everything else is parsed via `JSON.parse`
|
|
268
273
|
- **Unions/Intersections**: defaults to first item's value
|