@tsed/schema 8.20.0 → 8.21.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.
@@ -303,6 +303,7 @@ export class JsonSchema extends Map {
303
303
  enumerable: false,
304
304
  configurable: false
305
305
  });
306
+ return this;
306
307
  }
307
308
  /**
308
309
  * Check if the schema has a property.
@@ -871,6 +872,65 @@ export class JsonSchema extends Map {
871
872
  super.set("properties", this.mapProperties(properties));
872
873
  return this;
873
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
+ }
874
934
  addProperty(key, schema) {
875
935
  const properties = this.get("properties") || {};
876
936
  properties[key] = schema;
@@ -1209,7 +1269,24 @@ export class JsonSchema extends Map {
1209
1269
  }
1210
1270
  assign(obj) {
1211
1271
  const entries = obj instanceof JsonSchema ? [...obj.entries()] : Object.entries(obj);
1272
+ const clone = (value) => (value instanceof JsonSchema ? value.clone() : value);
1212
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
+ }
1213
1290
  this.set(key, value);
1214
1291
  });
1215
1292
  if (obj instanceof JsonSchema) {
@@ -1225,6 +1302,9 @@ export class JsonSchema extends Map {
1225
1302
  this.#target = obj.#target;
1226
1303
  this.#isCollection = obj.#isCollection;
1227
1304
  this.#isLocalSchema = obj.#isLocalSchema;
1305
+ if (obj.#isLocalSchema && obj.#itemSchema) {
1306
+ this.#itemSchema = obj.#itemSchema.clone();
1307
+ }
1228
1308
  super.set("type", obj.get("type"));
1229
1309
  }
1230
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
  *
@@ -238,7 +238,7 @@ export declare class JsonSchema<T = JSONSchema7Type> extends Map<string, any> {
238
238
  * @returns A JsonSchema instance representing the input
239
239
  */
240
240
  static from(item: Partial<JsonSchemaObject> | Type<any> | JsonSchema | undefined): JsonSchema<JSONSchema7Type>;
241
- static add<Keys extends keyof JsonSchema>(property: Keys, method: JsonSchema[Keys]): void;
241
+ static add<Keys extends keyof JsonSchema>(property: Keys, method: JsonSchema[Keys]): typeof JsonSchema;
242
242
  /**
243
243
  * Check if the schema has a property.
244
244
  *
@@ -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.0",
5
+ "version": "8.21.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.0",
37
+ "@tsed/openspec": "8.21.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.0",
47
- "@tsed/core": "8.20.0",
48
- "@tsed/hooks": "8.20.0",
49
- "@tsed/openspec": "8.20.0",
50
- "@tsed/typescript": "8.20.0",
46
+ "@tsed/barrels": "8.21.0",
47
+ "@tsed/core": "8.21.0",
48
+ "@tsed/hooks": "8.21.0",
49
+ "@tsed/openspec": "8.21.0",
50
+ "@tsed/typescript": "8.21.0",
51
51
  "@types/fs-extra": "11.0.4",
52
52
  "@types/json-schema": "7.0.15",
53
53
  "@types/picomatch": "3.0.2",