@tsed/schema 8.20.1 → 8.22.0

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.
@@ -872,6 +872,65 @@ export class JsonSchema extends Map {
872
872
  super.set("properties", this.mapProperties(properties));
873
873
  return this;
874
874
  }
875
+ pick(...keys) {
876
+ const keySet = new Set(keys.map((key) => toJsonRegex(key)));
877
+ const schema = this.clone();
878
+ const properties = Object.entries(schema.get("properties")).reduce((properties, [key, value]) => {
879
+ if (keySet.has(key)) {
880
+ return {
881
+ ...properties,
882
+ [key]: value
883
+ };
884
+ }
885
+ return properties;
886
+ }, {});
887
+ schema.set("properties", properties);
888
+ schema.#required = new Set([...schema.#required].filter((key) => keySet.has(key)));
889
+ return schema;
890
+ }
891
+ omit(...keys) {
892
+ const keySet = new Set(keys.map((key) => toJsonRegex(key)));
893
+ const schema = this.clone();
894
+ const properties = Object.entries(schema.get("properties")).reduce((properties, [key, value]) => {
895
+ if (!keySet.has(key)) {
896
+ return {
897
+ ...properties,
898
+ [key]: value
899
+ };
900
+ }
901
+ return properties;
902
+ }, {});
903
+ schema.set("properties", properties);
904
+ keySet.forEach((key) => schema.#required.delete(key));
905
+ return schema;
906
+ }
907
+ partial() {
908
+ const schema = this.clone();
909
+ const properties = schema.get("properties");
910
+ if (properties) {
911
+ const partialProps = Object.entries(properties).reduce((acc, [key, value]) => {
912
+ if (value instanceof JsonSchema && value.$selfRequired) {
913
+ acc[key] = value.required(false);
914
+ }
915
+ else {
916
+ acc[key] = value;
917
+ }
918
+ return acc;
919
+ }, {});
920
+ schema.set("properties", partialProps);
921
+ }
922
+ schema.#required.clear();
923
+ return schema;
924
+ }
925
+ merge(schema) {
926
+ const cloned = this.clone();
927
+ const currentProperties = { ...(cloned.get("properties") || {}) };
928
+ const incoming = schema.get("properties") || {};
929
+ Object.assign(currentProperties, incoming);
930
+ schema.getRequiredFields().forEach((field) => cloned.#required.add(field));
931
+ cloned.properties(currentProperties);
932
+ return cloned;
933
+ }
875
934
  addProperty(key, schema) {
876
935
  const properties = this.get("properties") || {};
877
936
  properties[key] = schema;
@@ -1210,7 +1269,24 @@ export class JsonSchema extends Map {
1210
1269
  }
1211
1270
  assign(obj) {
1212
1271
  const entries = obj instanceof JsonSchema ? [...obj.entries()] : Object.entries(obj);
1272
+ const clone = (value) => (value instanceof JsonSchema ? value.clone() : value);
1213
1273
  entries.forEach(([key, value]) => {
1274
+ if (obj instanceof JsonSchema) {
1275
+ // deep clone
1276
+ if (key === "properties") {
1277
+ value = Object.fromEntries(Object.entries(value).map(([key, value]) => {
1278
+ return [key, clone(value)];
1279
+ }));
1280
+ }
1281
+ else if (key === "items") {
1282
+ if (!obj.isNullable) {
1283
+ value = clone(value);
1284
+ }
1285
+ }
1286
+ else if (key === "additionalProperties") {
1287
+ value = clone(value);
1288
+ }
1289
+ }
1214
1290
  this.set(key, value);
1215
1291
  });
1216
1292
  if (obj instanceof JsonSchema) {
@@ -1226,6 +1302,9 @@ export class JsonSchema extends Map {
1226
1302
  this.#target = obj.#target;
1227
1303
  this.#isCollection = obj.#isCollection;
1228
1304
  this.#isLocalSchema = obj.#isLocalSchema;
1305
+ if (obj.#isLocalSchema && obj.#itemSchema) {
1306
+ this.#itemSchema = obj.#itemSchema.clone();
1307
+ }
1229
1308
  super.set("type", obj.get("type"));
1230
1309
  }
1231
1310
  return this;
@@ -9,7 +9,7 @@ import { AliasMap, AliasType } from "./JsonAliasMap.js";
9
9
  import { Discriminator } from "./JsonDiscriminator.js";
10
10
  import { JsonFormatTypes } from "./JsonFormatTypes.js";
11
11
  import { JsonLazyRef } from "./JsonLazyRef.js";
12
- import type { Infer, PropsToShape, UnionToIntersection } from "./types.js";
12
+ import type { Infer, PropsToShape, SchemaKey, SchemaMerge, SchemaOmit, SchemaPartial, SchemaPick, UnionToIntersection } from "./types.js";
13
13
  /**
14
14
  * Extended JSON Schema object supporting TypeScript types and Ts.ED enhancements.
15
15
  *
@@ -624,6 +624,10 @@ export declare class JsonSchema<T = JSONSchema7Type> extends Map<string, any> {
624
624
  * @see https://tools.ietf.org/html/draft-wright-json-schema-validation-01#section-6.18
625
625
  */
626
626
  properties<P extends Record<string, JsonSchema<any>> = Record<string, JsonSchema<any>>>(properties: P): JsonSchema<PropsToShape<P>>;
627
+ pick<K extends SchemaKey<T>>(...keys: K[]): JsonSchema<SchemaPick<T, K>>;
628
+ omit<K extends SchemaKey<T>>(...keys: K[]): JsonSchema<SchemaOmit<T, K>>;
629
+ partial(): JsonSchema<SchemaPartial<T>>;
630
+ merge<S extends JsonSchema<any>>(schema: S): JsonSchema<SchemaMerge<T, Infer<S>>>;
627
631
  addProperty(key: string, schema: AnyJsonSchema): this;
628
632
  /**
629
633
  * This attribute is an object that defines the schema for a set of property names of an object instance.
@@ -43,6 +43,21 @@ export type Infer<S> = S extends JsonSchema<infer T> ? T : never;
43
43
  export type PropsToShape<P extends Record<string, JsonSchema<any>>> = {
44
44
  [K in keyof P]: Infer<P[K]>;
45
45
  };
46
+ type JsonLikeObject = Record<string, any>;
47
+ type ObjectPortion<T> = Extract<T, JsonLikeObject>;
48
+ type NonObjectPortion<T> = Exclude<T, JsonLikeObject>;
49
+ type ObjectPick<T, K extends PropertyKey> = Pick<ObjectPortion<T>, Extract<K, keyof ObjectPortion<T>>>;
50
+ type ObjectOmit<T, K extends PropertyKey> = Omit<ObjectPortion<T>, Extract<K, keyof ObjectPortion<T>>>;
51
+ type ObjectPartial<T> = {
52
+ [K in keyof ObjectPortion<T>]?: ObjectPortion<T>[K] | undefined;
53
+ };
54
+ type MergedObjectPortion<T, U> = [ObjectPortion<T>] extends [never] ? ObjectPortion<U> : [ObjectPortion<U>] extends [never] ? ObjectPortion<T> : ObjectPortion<T> & ObjectPortion<U>;
55
+ export type SchemaPick<T, K extends PropertyKey> = [ObjectPortion<T>] extends [never] ? T : NonObjectPortion<T> extends never ? ObjectPick<T, K> : ObjectPick<T, K> | NonObjectPortion<T>;
56
+ export type SchemaOmit<T, K extends PropertyKey> = [ObjectPortion<T>] extends [never] ? T : NonObjectPortion<T> extends never ? ObjectOmit<T, K> : ObjectOmit<T, K> | NonObjectPortion<T>;
57
+ export type SchemaPartial<T> = [ObjectPortion<T>] extends [never] ? T : NonObjectPortion<T> extends never ? ObjectPartial<T> : ObjectPartial<T> | NonObjectPortion<T>;
58
+ export type SchemaMerge<T, U> = [MergedObjectPortion<T, U>] extends [never] ? NonObjectPortion<T> | NonObjectPortion<U> : NonObjectPortion<T> extends never ? NonObjectPortion<U> extends never ? MergedObjectPortion<T, U> : MergedObjectPortion<T, U> | NonObjectPortion<U> : MergedObjectPortion<T, U> | NonObjectPortion<T> | NonObjectPortion<U>;
59
+ type ObjectKeys<T> = ObjectPortion<T> extends never ? never : keyof ObjectPortion<T>;
60
+ export type SchemaKey<T> = ObjectKeys<T> extends never ? string : Extract<ObjectKeys<T>, string>;
46
61
  /**
47
62
  * Maps common JavaScript constructors to their corresponding TypeScript types.
48
63
  *
@@ -95,3 +110,4 @@ export type CtorToType<C> = C extends StringConstructor ? string : C extends Num
95
110
  * @public
96
111
  */
97
112
  export type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
113
+ export {};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tsed/schema",
3
3
  "description": "JsonSchema module for Ts.ED Framework",
4
4
  "type": "module",
5
- "version": "8.20.1",
5
+ "version": "8.22.0",
6
6
  "source": "./src/index.ts",
7
7
  "main": "./lib/esm/index.js",
8
8
  "module": "./lib/esm/index.js",
@@ -34,7 +34,7 @@
34
34
  "tsed"
35
35
  ],
36
36
  "dependencies": {
37
- "@tsed/openspec": "8.20.1",
37
+ "@tsed/openspec": "8.22.0",
38
38
  "change-case": "^5.4.4",
39
39
  "json-schema": "0.4.0",
40
40
  "picomatch": "4.0.2",
@@ -43,11 +43,11 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@apidevtools/swagger-parser": "10.1.0",
46
- "@tsed/barrels": "8.20.1",
47
- "@tsed/core": "8.20.1",
48
- "@tsed/hooks": "8.20.1",
49
- "@tsed/openspec": "8.20.1",
50
- "@tsed/typescript": "8.20.1",
46
+ "@tsed/barrels": "8.22.0",
47
+ "@tsed/core": "8.22.0",
48
+ "@tsed/hooks": "8.22.0",
49
+ "@tsed/openspec": "8.22.0",
50
+ "@tsed/typescript": "8.22.0",
51
51
  "@types/fs-extra": "11.0.4",
52
52
  "@types/json-schema": "7.0.15",
53
53
  "@types/picomatch": "3.0.2",