@empathyco/x-adapter 8.0.0-alpha.17 → 8.0.0-alpha.19

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/README.md CHANGED
@@ -74,7 +74,7 @@ passed.
74
74
  ###### Types definition
75
75
 
76
76
  ```ts
77
- // API data models
77
+ // API models
78
78
  interface ApiRequest {
79
79
  q?: string;
80
80
  id?: number;
@@ -89,7 +89,7 @@ interface ApiProduct {
89
89
  price: number;
90
90
  }
91
91
 
92
- // App's data models
92
+ // App models
93
93
  interface AppSearchRequest {
94
94
  query: string;
95
95
  }
@@ -243,7 +243,7 @@ the value somehow.
243
243
  ###### Types definition
244
244
 
245
245
  ```ts
246
- // API data models
246
+ // API models
247
247
  interface ApiUserRequest {
248
248
  q: string;
249
249
  }
@@ -256,7 +256,7 @@ interface ApiUser {
256
256
  firstName: string;
257
257
  }
258
258
 
259
- // App's data models
259
+ // App models
260
260
  interface AppUserRequest {
261
261
  query: string;
262
262
  }
@@ -307,7 +307,7 @@ them you just have to provide with the `Path` of the data to map, and the `Schem
307
307
  ###### Types definition
308
308
 
309
309
  ```ts
310
- // API data models
310
+ // API models
311
311
  interface ApiRequest {
312
312
  q: string;
313
313
  }
@@ -328,7 +328,7 @@ interface ApiAddress {
328
328
  postalCode: string;
329
329
  }
330
330
 
331
- // APP data models
331
+ // App models
332
332
  interface AppRequest {
333
333
  query: string;
334
334
  }
@@ -408,34 +408,262 @@ export const searchUsersWithContactInfo = endpointAdapterFactory({
408
408
 
409
409
  #### Using a mutable schema
410
410
 
411
- This feature lets you have some default mappers, and modify or extend them for some concrete
412
- implementations. To do so, you should use the `createMutableSchema` helper function, and pass as a
413
- parameter the schema you want to make mutable.
411
+ This feature lets you have some default schemas, and modify or extend them for some concrete
412
+ implementations. To do so, you can use the `createMutableSchema` function, passing a `Source` and
413
+ `Target` type parameters to map your models. This function will return a `MutableSchema` that apart
414
+ from the mapping information will also contain some methods to create new schemas or modify the
415
+ current one.
416
+
417
+ In the example below we will create a `MutableSchema` to have a default object that will be reused
418
+ for different endpoint calls.
419
+
420
+ ###### Types definition and MutableSchema
421
+
422
+ ```ts
423
+ // API models
424
+ export interface ApiBaseObject {
425
+ id: number;
426
+ body: string;
427
+ }
428
+
429
+ // APP models
430
+ export interface AppBaseObject {
431
+ id: string;
432
+ text: string;
433
+ }
434
+
435
+ // Mutable Schema
436
+ export const baseObjectSchema = createMutableSchema<ApiBaseObject, AppBaseObject>({
437
+ id: ({ id }) => id.toString(),
438
+ text: 'body'
439
+ });
440
+ ```
441
+
442
+ Once we have the `MutableSchema`, we can use the following methods to fit our different APIs needs:
443
+
444
+ - `$extends`: Creates a new `MutableSchema` based on the original one. The original remains
445
+ unchanged. This can be useful if we need to create a new `EndpointAdapter` with models based on
446
+ another API.
447
+ - `$override`: Merges/modifies the original `MutableSchema` partially, so the change will affect to
448
+ all the `EndpointAdapter`(s) that are using it. It can be used to change the structure of our
449
+ request/response mappers, or to add them new fields. Useful for clients with few differences in
450
+ their APIs. For example, you can create a library with a default adapter and use this library from
451
+ the customer projects overriding only the needed field (e.g. retrieve the images from `pictures`
452
+ instead of `images` in a products API).
453
+ - `$replace`: Replaces completely the original `MutableSchema` by a new one, it won't exist anymore.
454
+ The change will affect to all the `EndpointAdapter`(s) that were using it. Useful for clients with
455
+ a completely different API/response to the standard you have been working with.
456
+
457
+ ###### Extend a MutableSchema to reuse it in two different endpoints with more fields
458
+
459
+ ```ts
460
+ import { ApiBaseObject, AppBaseObject, baseObjectSchema } from '@/base-types';
461
+
462
+ // Api models
463
+ interface ApiPost extends ApiBaseObject {
464
+ title: string;
465
+ }
466
+ interface ApiPostsResponse {
467
+ posts: ApiPost[];
468
+ }
469
+
470
+ interface ApiComment extends ApiBaseObject {
471
+ postId: number;
472
+ }
473
+ interface ApiCommentsResponse {
474
+ comments: ApiComment[];
475
+ }
476
+
477
+ // App models
478
+ interface AppPost extends AppBaseObject {
479
+ postTitle: string;
480
+ }
481
+ interface AppPostsResponse {
482
+ posts: AppPost[];
483
+ }
484
+
485
+ interface AppComment extends AppBaseObject {
486
+ postId: number;
487
+ }
488
+ interface AppCommentsResponse {
489
+ comments: AppComment[];
490
+ }
491
+
492
+ // Extend for posts endpoint
493
+ const postSchema = baseObjectSchema.$extends<ApiPost, AppPost>({
494
+ postTitle: 'title'
495
+ });
496
+
497
+ const postsResponse = schemaMapperFactory<ApiPostsResponse, AppPostsResponse>({
498
+ posts: {
499
+ $subSchema: postSchema,
500
+ $path: 'posts'
501
+ }
502
+ });
503
+
504
+ export const searchPosts = endpointAdapterFactory({
505
+ endpoint: 'https://dummyjson.com/posts',
506
+ responseMapper: postsResponse
507
+ });
508
+
509
+ // Extend for comments endpoint
510
+ const commentSchema = baseObjectSchema.$extends<ApiComment, AppComment>({
511
+ postId: 'postId'
512
+ });
513
+
514
+ const commentsResponse = schemaMapperFactory<ApiCommentsResponse, AppCommentsResponse>({
515
+ comments: {
516
+ $subSchema: commentSchema,
517
+ $path: 'comments'
518
+ }
519
+ });
520
+
521
+ export const searchComments = endpointAdapterFactory({
522
+ endpoint: 'https://dummyjson.com/comments',
523
+ responseMapper: commentsResponse
524
+ });
525
+ ```
526
+
527
+ ###### Override a MutableSchema to add more fields
528
+
529
+ As said above, the suitable context for using the `override` method would be a project with an API
530
+ that doesn't differ too much against the one used in our "base project". That means we can reuse
531
+ most of the types and schemas definitions, so we would only add a few new fields from the new API.
414
532
 
415
533
  ```ts
416
- // TODO: Creating a mutable schema
534
+ import { ApiBaseObject, AppBaseObject, baseObjectSchema } from '@/base-types';
535
+
536
+ // Api models
537
+ interface ApiTodo {
538
+ completed: boolean;
539
+ todo: string;
540
+ userId: number;
541
+ }
542
+
543
+ interface ApiTodosResponse {
544
+ todos: ApiBaseObject[];
545
+ }
546
+
547
+ // App models
548
+ interface AppTodo {
549
+ completed: boolean;
550
+ text: string;
551
+ userId: string;
552
+ }
553
+
554
+ interface AppTodosResponse {
555
+ todos: AppBaseObject[];
556
+ }
557
+
558
+ // Response mapper
559
+ const todosResponse = schemaMapperFactory<ApiTodosResponse, AppTodosResponse>({
560
+ todos: {
561
+ $subSchema: baseObjectSchema,
562
+ $path: 'todos'
563
+ }
564
+ });
565
+
566
+ // Endpoint Adapter
567
+ export const searchTodos = endpointAdapterFactory({
568
+ endpoint: 'https://dummyjson.com/todos',
569
+ responseMapper: todosResponse
570
+ });
571
+
572
+ // Override the original Schema. The Schema changes to map: 'id', 'completed', 'text' and 'userId''
573
+ baseObjectSchema.$override<ApiTodo, AppTodo>({
574
+ completed: 'completed',
575
+ text: 'todo',
576
+ userId: ({ userId }) => userId.toString()
577
+ });
417
578
  ```
418
579
 
419
- Once you have your mutable schema, you can use its available methods to obtain a new schema based on
420
- it:
580
+ ###### Replace a MutableSchema to completely change it
421
581
 
422
- - `replace`: Replaces completely the original Schema.
423
- - `override`: Merges the original schema with the new one.
424
- - `extends`: Creates a new Schema based on the original one. The original remains unchanged.
582
+ In this case we are facing too many differences between API responses. We don't need to write a
583
+ whole adapter from scratch, as there are other parts of the API that aren't changing so much, but we
584
+ should replace some `endpointAdapter`'s schemas.
425
585
 
426
586
  ```ts
427
- // TODO: Mutable schema's methods: '$replace', '$override', '$extends'
587
+ import { ApiBaseObject, AppBaseObject, baseObjectSchema } from '@/base-types';
588
+
589
+ // Api models
590
+ interface ApiQuote {
591
+ id: number;
592
+ quote: string;
593
+ author: string;
594
+ }
595
+
596
+ interface ApiQuotesResponse {
597
+ quotes: ApiBaseObject[];
598
+ }
599
+
600
+ // App models
601
+ interface AppQuote {
602
+ quoteId: string;
603
+ quote: string;
604
+ author: string;
605
+ }
606
+
607
+ interface AppQuotesResponse {
608
+ quotes: AppBaseObject[];
609
+ }
610
+
611
+ // Response mapper
612
+ const quotesResponse = schemaMapperFactory<ApiQuotesResponse, AppQuotesResponse>({
613
+ quotes: {
614
+ $subSchema: baseObjectSchema,
615
+ $path: 'quotes'
616
+ }
617
+ });
618
+
619
+ // Endpoint Adapter
620
+ export const searchQuotes = endpointAdapterFactory({
621
+ endpoint: 'https://dummyjson.com/quotes',
622
+ responseMapper: quotesResponse
623
+ });
624
+
625
+ // Replace the original Schema
626
+ baseObjectSchema.$replace<ApiQuote, AppQuote>({
627
+ quoteId: ({ id }) => id.toString(),
628
+ quote: 'quote',
629
+ author: 'author'
630
+ });
428
631
  ```
429
632
 
430
633
  <br>
431
634
 
432
635
  ### Extend an adapter that uses schemas
433
636
 
434
- You can check the
435
- [x-platform-adapter](https://github.com/empathyco/x/tree/main/packages/x-adapter-platform) library.
436
- You will find a sample implementation of the `x-adapter` library based on the
437
- [Search Platform API](https://docs.empathy.co/develop-empathy-platform/api-reference/search-api.html),
438
- and also some guidance on how to extend it for your needs.
637
+ Imagine you have a new setup and that you can reuse most of the stuff you have developed. Probably
638
+ you have built an adapter instance as a configuration object that contains all of your
639
+ `EndpointAdapter` calls, so you only need to extend the endpoint you need to change.
640
+
641
+ ```ts
642
+ export const adapter = {
643
+ searchItem: getItemById,
644
+ searchList: searchComments
645
+ // Any endpoint adapter you are using to communicate with your API
646
+ };
647
+
648
+ adapter.searchList = searchComments.extends({
649
+ endpoint: 'https://dummyjson.com/comments/',
650
+ defaultRequestOptions: {
651
+ // If you need to send an id, a header...
652
+ },
653
+ defaultRequestOptions: {
654
+ parameters: {
655
+ limit: 10,
656
+ skip: 10
657
+ }
658
+ }
659
+ });
660
+ ```
661
+
662
+ For further detail, you can check the
663
+ [x-platform-adapter](https://github.com/empathyco/x/tree/main/packages/x-adapter-platform) package.
664
+ It is a whole adapter implementation using this `x-adapter` library to suit the
665
+ [Search Platform API](https://docs.empathy.co/develop-empathy-platform/api-reference/search-api.html)
666
+ needs.
439
667
 
440
668
  ## Test
441
669
 
@@ -452,9 +680,9 @@ npm test
452
680
 
453
681
  ## Contributing
454
682
 
455
- To start contributing to the project, please take a look to
456
- our **[Contributing Guide](https://github.com/empathyco/x/blob/main/.github/CONTRIBUTING.md).** Take
457
- in account that `x-adapter` is developed using [Typescript](https://www.typescriptlang.org/), so we
683
+ To start contributing to the project, please take a look to our
684
+ **[Contributing Guide](https://github.com/empathyco/x/blob/main/.github/CONTRIBUTING.md).** Take in
685
+ account that `x-adapter` is developed using [Typescript](https://www.typescriptlang.org/), so we
458
686
  recommend you check it out.
459
687
 
460
688
  ## License
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/schemas/types.ts"],"names":[],"mappings":"","sourcesContent":["import {\n AnyFunction,\n DeepPartial,\n ExtractPath,\n ExtractPathByType,\n ExtractType,\n Primitive\n} from '@empathyco/x-utils';\nimport { MapperContext } from '../mappers/types';\n\n// TODO: EX-5830 - Enhance Schema type to support optional properties in the Source object\n/**\n * Template object to transform a source object to a target object.\n *\n * @remarks The source object must not have optional properties, as it could cause infinite\n * type instantiations.\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * price: {\n * max: number;\n * min: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * maxPrice: number;\n * minPrice: number;\n * img: string[]\n * }\n *\n * const schema: Schema<Source, Target> = {\n * identifier: 'id',\n * maxPrice: 'price.max',\n * minPrice: ({ price }) => Math.min(0, price.min),\n * img: 'images'\n * };\n * ```\n * @public\n */\nexport type Schema<Source = any, Target = any> = {\n [TargetKey in keyof Target]: SchemaTransformer<Source, Target, TargetKey>;\n};\n\n/**\n * A {@link Schema | schema} with extended functionality to: completely replace\n * the original schema, partially override it or create a new one.\n *\n * @param OriginalSchema - The {@link Schema | schema} that will be mutable.\n * @public\n */\nexport type MutableSchema<Source, Target> = Schema<Source, Target> & {\n /**\n * Replaces all usages of the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use instead of the original one.\n * @returns The new {@link Schema | schema} that will be used.\n */\n $replace<NewSource, NewTarget>(\n newSchema: Schema<NewSource, NewTarget>\n ): MutableSchema<NewSource, NewTarget>;\n /**\n * Merges the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use to merge with the original one.\n * @returns The {@link Schema | schema} returned by the merge.\n */\n // eslint-disable-next-line @typescript-eslint/ban-types\n $override<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Creates a new {@link Schema | schema} using the original one as starting point.\n * The original {@link Schema | schema} will remain unchanged.\n *\n * @param newSchema - The {@link Schema | schema} to be used to extend the original one.\n * @returns The {@link Schema | schema} created.\n */\n // eslint-disable-next-line @typescript-eslint/ban-types\n $extends<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Returns a string representing of the {@link Schema | schema}.\n *\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @returns The string representation.\n */\n toString(includeInternalMethods?: boolean): string;\n};\n/**\n * The possible transformers to apply to the target key.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param TargetKey - The target key to apply the transformation.\n * @public\n */\nexport type SchemaTransformer<Source, Target, TargetKey extends keyof Target> =\n | PathTransformer<Source, Target[TargetKey]>\n | FunctionTransformer<Source, Target[TargetKey]>\n | SubSchemaTransformer<Source, Target[TargetKey]>\n | Schema<Source, Exclude<Target[TargetKey], AnyFunction | Primitive>>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: 'id',\n * hits: 'count'\n * };\n *\n * const wrongSubSchema: Schema<Source, Target> = {\n * // @ts-expect-error\n * title: 'count', // This raises a TS error\n * hits: 'count'\n * };\n * ```\n * @public\n */\nexport type PathTransformer<Source, Target> = ExtractPathByType<Source, Target>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: source => source.id,\n * hits: (source, context) => context.requestParameters.query === 'example'\n * ? source.count\n * : 0\n * };\n * ```\n * @public\n */\nexport type FunctionTransformer<Source, Target> = (\n source: Source,\n context?: MapperContext\n) => Target;\n\n/**\n * An object containing a schema narrowing its source object based on the given path.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * facets: {\n * name: string;\n * count: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * filters: {\n * id: string;\n * numFound: number;\n * };\n * img: string[]\n * }\n *\n * const subSchema: SubSchemaTransformer<Source, Target['filters']> = {\n * $path: 'facets',\n * $subSchema: {\n * id: 'name',\n * numFound: 'count'\n * }\n * };\n * ```\n * @public\n */\nexport type SubSchemaTransformer<Source, Target> = {\n [Path in ExtractPath<Source>]: {\n $context?: MapperContext;\n $path: Path;\n $subSchema:\n | SubSchema<Source, Target, Path>\n | '$self'\n | ((source: Source) => SubSchema<Source, Target, Path>);\n };\n}[ExtractPath<Source>];\n\n/**\n * A {@link Schema | schema} that will be applied to an inner path of an object.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param Path - The path where the schema will be applied.\n * @public\n */\nexport type SubSchema<Source, Target, Path extends ExtractPath<Source>> = ExtractType<\n Source,\n Path\n> extends (infer SourceArrayType)[]\n ? Target extends (infer TargetArrayType)[]\n ? Schema<SourceArrayType, TargetArrayType>\n : never\n : Target extends []\n ? never\n : Schema<ExtractType<Source, Path>, Target>;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/schemas/types.ts"],"names":[],"mappings":"","sourcesContent":["import {\n AnyFunction,\n DeepPartial,\n ExtractPath,\n ExtractPathByType,\n ExtractType,\n Primitive\n} from '@empathyco/x-utils';\nimport { MapperContext } from '../mappers/types';\n\n// TODO: EX-5830 - Enhance Schema type to support optional properties in the Source object\n/**\n * Template object to transform a source object to a target object.\n *\n * @remarks The source object must not have optional properties, as it could cause infinite\n * type instantiations.\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * price: {\n * max: number;\n * min: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * maxPrice: number;\n * minPrice: number;\n * img: string[]\n * }\n *\n * const schema: Schema<Source, Target> = {\n * identifier: 'id',\n * maxPrice: 'price.max',\n * minPrice: ({ price }) => Math.min(0, price.min),\n * img: 'images'\n * };\n * ```\n * @public\n */\nexport type Schema<Source = any, Target = any> = {\n [TargetKey in keyof Target]: SchemaTransformer<Source, Target, TargetKey>;\n};\n\n/**\n * A {@link Schema | schema} with extended functionality to: completely replace\n * the original schema, partially override it or create a new one.\n *\n * @param OriginalSchema - The {@link Schema | schema} that will be mutable.\n * @public\n */\nexport type MutableSchema<Source, Target> = Schema<Source, Target> & {\n /**\n * Replaces all usages of the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use instead of the original one.\n * @returns The new {@link Schema | schema} that will be used.\n */\n $replace<NewSource, NewTarget>(\n newSchema: Schema<NewSource, NewTarget>\n ): MutableSchema<NewSource, NewTarget>;\n /**\n * Merges the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use to merge with the original one.\n * @returns The {@link Schema | schema} returned by the merge.\n */\n // eslint-disable-next-line @typescript-eslint/ban-types\n $override<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Creates a new {@link Schema | schema} using the original one as starting point.\n * The original {@link Schema | schema} will remain unchanged.\n *\n * @param newSchema - The {@link Schema | schema} to be used to extend the original one.\n * Both schema's Target and Source can be unique or also be extending from another one.\n * @returns The {@link Schema | schema} created.\n */\n $extends<NewSource extends Source, NewTarget extends Target>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, Omit<NewTarget, keyof Target>>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n // eslint-disable-next-line @typescript-eslint/ban-types\n $extends<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Returns a string representing of the {@link Schema | schema}.\n *\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @returns The string representation.\n */\n toString(includeInternalMethods?: boolean): string;\n};\n/**\n * The possible transformers to apply to the target key.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param TargetKey - The target key to apply the transformation.\n * @public\n */\nexport type SchemaTransformer<Source, Target, TargetKey extends keyof Target> =\n | PathTransformer<Source, Target[TargetKey]>\n | FunctionTransformer<Source, Target[TargetKey]>\n | SubSchemaTransformer<Source, Target[TargetKey]>\n | Schema<Source, Exclude<Target[TargetKey], AnyFunction | Primitive>>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: 'id',\n * hits: 'count'\n * };\n *\n * const wrongSubSchema: Schema<Source, Target> = {\n * // @ts-expect-error\n * title: 'count', // This raises a TS error\n * hits: 'count'\n * };\n * ```\n * @public\n */\nexport type PathTransformer<Source, Target> = ExtractPathByType<Source, Target>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: source => source.id,\n * hits: (source, context) => context.requestParameters.query === 'example'\n * ? source.count\n * : 0\n * };\n * ```\n * @public\n */\nexport type FunctionTransformer<Source, Target> = (\n source: Source,\n context?: MapperContext\n) => Target;\n\n/**\n * An object containing a schema narrowing its source object based on the given path.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * facets: {\n * name: string;\n * count: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * filters: {\n * id: string;\n * numFound: number;\n * };\n * img: string[]\n * }\n *\n * const subSchema: SubSchemaTransformer<Source, Target['filters']> = {\n * $path: 'facets',\n * $subSchema: {\n * id: 'name',\n * numFound: 'count'\n * }\n * };\n * ```\n * @public\n */\nexport type SubSchemaTransformer<Source, Target> = {\n [Path in ExtractPath<Source>]: {\n $context?: MapperContext;\n $path: Path;\n $subSchema:\n | SubSchema<Source, Target, Path>\n | '$self'\n | ((source: Source) => SubSchema<Source, Target, Path>);\n };\n}[ExtractPath<Source>];\n\n/**\n * A {@link Schema | schema} that will be applied to an inner path of an object.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param Path - The path where the schema will be applied.\n * @public\n */\nexport type SubSchema<Source, Target, Path extends ExtractPath<Source>> = ExtractType<\n Source,\n Path\n> extends (infer SourceArrayType)[]\n ? Target extends (infer TargetArrayType)[]\n ? Schema<SourceArrayType, TargetArrayType>\n : never\n : Target extends []\n ? never\n : Schema<ExtractType<Source, Path>, Target>;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/schemas/utils.ts"],"names":[],"mappings":";;;AAAA,0DAAoD;AACpD,gDAAmE;AAGnE;;GAEG;AACH,MAAM,6BAA6B,GAAa,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAElG;;;;;;;;GAQG;AACH,SAAgB,mBAAmB,CACjC,MAA8B;IAE9B,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,CAAC,SAAS;YAChB,IAAA,iBAAO,EAAC,IAAI,EAAE,GAAG,CAAC,EAAE;gBAClB,IAAI,gBAAgB,CAAC,GAAa,CAAC,EAAE;oBACnC,OAAO;iBACR;gBACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/B;+EACmE;YACnE,OAAO,IAAW,CAAC;QACrB,CAAC;QACD,SAAS,CAAC,SAAS;YACjB,OAAO,IAAA,wBAAS,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,QAAQ,CAAC,SAAS;YAChB,OAAO,IAAA,wBAAS,EAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,CAAC,sBAAsB,GAAG,KAAK;YACrC,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnD,CAAC;KACF,CAAC;AACJ,CAAC;AA3BD,kDA2BC;AAED;;;;;;;;;GASG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAFD,4CAEC;AAED;;;;;;;;GAQG;AACH,SAAS,SAAS,CAChB,IAA6B,EAC7B,sBAA+B,EAC/B,IAAI,GAAG,CAAC;IAER,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAA,iBAAO,EAAC,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC3B,IAAI,IAAA,kBAAQ,EAAC,KAAK,CAAC,EAAE;YACnB,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,QAAQ,SAAS,CAC7C,KAAK,EACL,sBAAsB,EACtB,EAAE,IAAI,CACP,GAAG,WAAW,MAAM,CAAC;SACvB;aAAM,IAAI,CAAC,IAAA,oBAAU,EAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,sBAAsB,EAAE;YACjF,4EAA4E;YAC5E,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,KAAK,KAAK,KAAK,CAAC;SAC/C;IACH,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { deepMerge } from '@empathyco/x-deep-merge';\nimport { forEach, isFunction, isObject } from '@empathyco/x-utils';\nimport { MutableSchema, Schema } from './types';\n\n/**\n * Collection of internal method names for {@link MutableSchema | mutable schemas}.\n */\nconst mutableSchemasInternalMethods: string[] = ['$replace', '$override', '$extends', 'toString'];\n\n/**\n * Creates a {@link MutableSchema | mutable schema } version of a given {@link Schema | schema}.\n *\n * @param schema - The {@link Schema | schema} to make mutable.\n *\n * @returns A {@link MutableSchema | mutable schema} version of the given {@link Schema | schema}.\n *\n * @public\n */\nexport function createMutableSchema<Source, Target>(\n schema: Schema<Source, Target>\n): MutableSchema<Source, Target> {\n return {\n ...schema,\n $replace(newSchema) {\n forEach(this, key => {\n if (isInternalMethod(key as string)) {\n return;\n }\n delete this[key];\n });\n Object.assign(this, newSchema);\n /* We are replacing the schema with a completely new schema , so it makes sense that TS\n complains that the old schema and the new one are not the same. */\n return this as any;\n },\n $override(newSchema) {\n return deepMerge(this, newSchema);\n },\n $extends(newSchema) {\n return deepMerge({}, this, newSchema);\n },\n toString(includeInternalMethods = false) {\n return serialize(this, !!includeInternalMethods);\n }\n };\n}\n\n/**\n * Checks if the given key is a {@link MutableSchema | mutableSchema} method.\n *\n * @param name - The key to check.\n *\n * @returns True if it is a {@link MutableSchema | mutableSchema} method,\n * false otherwise.\n *\n * @public\n */\nexport function isInternalMethod(name: string): boolean {\n return mutableSchemasInternalMethods.includes(name);\n}\n\n/**\n * Returns a string representing of the given object.\n *\n * @param data - The object to get the string representation from.\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @param deep - The level of indentation.\n * @returns The string representation.\n */\nfunction serialize(\n data: Record<string, unknown>,\n includeInternalMethods: boolean,\n deep = 0\n): string {\n const indentation = ' '.repeat(deep);\n let output = '';\n forEach(data, (key, value) => {\n if (isObject(value)) {\n output += `${indentation}${key}: {\\n${serialize(\n value,\n includeInternalMethods,\n ++deep\n )}${indentation}},\\n`;\n } else if (!isFunction(value) || !isInternalMethod(key) || includeInternalMethods) {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n output += `${indentation}${key}: ${value},\\n`;\n }\n });\n return output;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/schemas/utils.ts"],"names":[],"mappings":";;;AAAA,0DAAoD;AACpD,gDAAmE;AAGnE;;GAEG;AACH,MAAM,6BAA6B,GAAa,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAElG;;;;;;;;GAQG;AACH,SAAgB,mBAAmB,CACjC,MAA8B;IAE9B,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,CAAC,SAAS;YAChB,IAAA,iBAAO,EAAC,IAAI,EAAE,GAAG,CAAC,EAAE;gBAClB,IAAI,gBAAgB,CAAC,GAAa,CAAC,EAAE;oBACnC,OAAO;iBACR;gBACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/B;+EACmE;YACnE,OAAO,IAAW,CAAC;QACrB,CAAC;QACD,SAAS,CAAC,SAAS;YACjB,OAAO,IAAA,wBAAS,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,QAAQ,CAAC,SAAkB;YACzB,OAAO,IAAA,wBAAS,EAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,CAAC,sBAAsB,GAAG,KAAK;YACrC,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnD,CAAC;KACF,CAAC;AACJ,CAAC;AA3BD,kDA2BC;AAED;;;;;;;;;GASG;AACH,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAFD,4CAEC;AAED;;;;;;;;GAQG;AACH,SAAS,SAAS,CAChB,IAA6B,EAC7B,sBAA+B,EAC/B,IAAI,GAAG,CAAC;IAER,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAA,iBAAO,EAAC,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC3B,IAAI,IAAA,kBAAQ,EAAC,KAAK,CAAC,EAAE;YACnB,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,QAAQ,SAAS,CAC7C,KAAK,EACL,sBAAsB,EACtB,EAAE,IAAI,CACP,GAAG,WAAW,MAAM,CAAC;SACvB;aAAM,IAAI,CAAC,IAAA,oBAAU,EAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,sBAAsB,EAAE;YACjF,4EAA4E;YAC5E,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,KAAK,KAAK,KAAK,CAAC;SAC/C;IACH,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { deepMerge } from '@empathyco/x-deep-merge';\nimport { forEach, isFunction, isObject } from '@empathyco/x-utils';\nimport { MutableSchema, Schema } from './types';\n\n/**\n * Collection of internal method names for {@link MutableSchema | mutable schemas}.\n */\nconst mutableSchemasInternalMethods: string[] = ['$replace', '$override', '$extends', 'toString'];\n\n/**\n * Creates a {@link MutableSchema | mutable schema } version of a given {@link Schema | schema}.\n *\n * @param schema - The {@link Schema | schema} to make mutable.\n *\n * @returns A {@link MutableSchema | mutable schema} version of the given {@link Schema | schema}.\n *\n * @public\n */\nexport function createMutableSchema<Source, Target>(\n schema: Schema<Source, Target>\n): MutableSchema<Source, Target> {\n return {\n ...schema,\n $replace(newSchema) {\n forEach(this, key => {\n if (isInternalMethod(key as string)) {\n return;\n }\n delete this[key];\n });\n Object.assign(this, newSchema);\n /* We are replacing the schema with a completely new schema , so it makes sense that TS\n complains that the old schema and the new one are not the same. */\n return this as any;\n },\n $override(newSchema) {\n return deepMerge(this, newSchema);\n },\n $extends(newSchema: unknown) {\n return deepMerge({}, this, newSchema);\n },\n toString(includeInternalMethods = false) {\n return serialize(this, !!includeInternalMethods);\n }\n };\n}\n\n/**\n * Checks if the given key is a {@link MutableSchema | mutableSchema} method.\n *\n * @param name - The key to check.\n *\n * @returns True if it is a {@link MutableSchema | mutableSchema} method,\n * false otherwise.\n *\n * @public\n */\nexport function isInternalMethod(name: string): boolean {\n return mutableSchemasInternalMethods.includes(name);\n}\n\n/**\n * Returns a string representing of the given object.\n *\n * @param data - The object to get the string representation from.\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @param deep - The level of indentation.\n * @returns The string representation.\n */\nfunction serialize(\n data: Record<string, unknown>,\n includeInternalMethods: boolean,\n deep = 0\n): string {\n const indentation = ' '.repeat(deep);\n let output = '';\n forEach(data, (key, value) => {\n if (isObject(value)) {\n output += `${indentation}${key}: {\\n${serialize(\n value,\n includeInternalMethods,\n ++deep\n )}${indentation}},\\n`;\n } else if (!isFunction(value) || !isInternalMethod(key) || includeInternalMethods) {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n output += `${indentation}${key}: ${value},\\n`;\n }\n });\n return output;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/schemas/types.ts"],"names":[],"mappings":"","sourcesContent":["import {\n AnyFunction,\n DeepPartial,\n ExtractPath,\n ExtractPathByType,\n ExtractType,\n Primitive\n} from '@empathyco/x-utils';\nimport { MapperContext } from '../mappers/types';\n\n// TODO: EX-5830 - Enhance Schema type to support optional properties in the Source object\n/**\n * Template object to transform a source object to a target object.\n *\n * @remarks The source object must not have optional properties, as it could cause infinite\n * type instantiations.\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * price: {\n * max: number;\n * min: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * maxPrice: number;\n * minPrice: number;\n * img: string[]\n * }\n *\n * const schema: Schema<Source, Target> = {\n * identifier: 'id',\n * maxPrice: 'price.max',\n * minPrice: ({ price }) => Math.min(0, price.min),\n * img: 'images'\n * };\n * ```\n * @public\n */\nexport type Schema<Source = any, Target = any> = {\n [TargetKey in keyof Target]: SchemaTransformer<Source, Target, TargetKey>;\n};\n\n/**\n * A {@link Schema | schema} with extended functionality to: completely replace\n * the original schema, partially override it or create a new one.\n *\n * @param OriginalSchema - The {@link Schema | schema} that will be mutable.\n * @public\n */\nexport type MutableSchema<Source, Target> = Schema<Source, Target> & {\n /**\n * Replaces all usages of the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use instead of the original one.\n * @returns The new {@link Schema | schema} that will be used.\n */\n $replace<NewSource, NewTarget>(\n newSchema: Schema<NewSource, NewTarget>\n ): MutableSchema<NewSource, NewTarget>;\n /**\n * Merges the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use to merge with the original one.\n * @returns The {@link Schema | schema} returned by the merge.\n */\n // eslint-disable-next-line @typescript-eslint/ban-types\n $override<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Creates a new {@link Schema | schema} using the original one as starting point.\n * The original {@link Schema | schema} will remain unchanged.\n *\n * @param newSchema - The {@link Schema | schema} to be used to extend the original one.\n * @returns The {@link Schema | schema} created.\n */\n // eslint-disable-next-line @typescript-eslint/ban-types\n $extends<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Returns a string representing of the {@link Schema | schema}.\n *\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @returns The string representation.\n */\n toString(includeInternalMethods?: boolean): string;\n};\n/**\n * The possible transformers to apply to the target key.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param TargetKey - The target key to apply the transformation.\n * @public\n */\nexport type SchemaTransformer<Source, Target, TargetKey extends keyof Target> =\n | PathTransformer<Source, Target[TargetKey]>\n | FunctionTransformer<Source, Target[TargetKey]>\n | SubSchemaTransformer<Source, Target[TargetKey]>\n | Schema<Source, Exclude<Target[TargetKey], AnyFunction | Primitive>>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: 'id',\n * hits: 'count'\n * };\n *\n * const wrongSubSchema: Schema<Source, Target> = {\n * // @ts-expect-error\n * title: 'count', // This raises a TS error\n * hits: 'count'\n * };\n * ```\n * @public\n */\nexport type PathTransformer<Source, Target> = ExtractPathByType<Source, Target>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: source => source.id,\n * hits: (source, context) => context.requestParameters.query === 'example'\n * ? source.count\n * : 0\n * };\n * ```\n * @public\n */\nexport type FunctionTransformer<Source, Target> = (\n source: Source,\n context?: MapperContext\n) => Target;\n\n/**\n * An object containing a schema narrowing its source object based on the given path.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * facets: {\n * name: string;\n * count: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * filters: {\n * id: string;\n * numFound: number;\n * };\n * img: string[]\n * }\n *\n * const subSchema: SubSchemaTransformer<Source, Target['filters']> = {\n * $path: 'facets',\n * $subSchema: {\n * id: 'name',\n * numFound: 'count'\n * }\n * };\n * ```\n * @public\n */\nexport type SubSchemaTransformer<Source, Target> = {\n [Path in ExtractPath<Source>]: {\n $context?: MapperContext;\n $path: Path;\n $subSchema:\n | SubSchema<Source, Target, Path>\n | '$self'\n | ((source: Source) => SubSchema<Source, Target, Path>);\n };\n}[ExtractPath<Source>];\n\n/**\n * A {@link Schema | schema} that will be applied to an inner path of an object.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param Path - The path where the schema will be applied.\n * @public\n */\nexport type SubSchema<Source, Target, Path extends ExtractPath<Source>> = ExtractType<\n Source,\n Path\n> extends (infer SourceArrayType)[]\n ? Target extends (infer TargetArrayType)[]\n ? Schema<SourceArrayType, TargetArrayType>\n : never\n : Target extends []\n ? never\n : Schema<ExtractType<Source, Path>, Target>;\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/schemas/types.ts"],"names":[],"mappings":"","sourcesContent":["import {\n AnyFunction,\n DeepPartial,\n ExtractPath,\n ExtractPathByType,\n ExtractType,\n Primitive\n} from '@empathyco/x-utils';\nimport { MapperContext } from '../mappers/types';\n\n// TODO: EX-5830 - Enhance Schema type to support optional properties in the Source object\n/**\n * Template object to transform a source object to a target object.\n *\n * @remarks The source object must not have optional properties, as it could cause infinite\n * type instantiations.\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * price: {\n * max: number;\n * min: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * maxPrice: number;\n * minPrice: number;\n * img: string[]\n * }\n *\n * const schema: Schema<Source, Target> = {\n * identifier: 'id',\n * maxPrice: 'price.max',\n * minPrice: ({ price }) => Math.min(0, price.min),\n * img: 'images'\n * };\n * ```\n * @public\n */\nexport type Schema<Source = any, Target = any> = {\n [TargetKey in keyof Target]: SchemaTransformer<Source, Target, TargetKey>;\n};\n\n/**\n * A {@link Schema | schema} with extended functionality to: completely replace\n * the original schema, partially override it or create a new one.\n *\n * @param OriginalSchema - The {@link Schema | schema} that will be mutable.\n * @public\n */\nexport type MutableSchema<Source, Target> = Schema<Source, Target> & {\n /**\n * Replaces all usages of the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use instead of the original one.\n * @returns The new {@link Schema | schema} that will be used.\n */\n $replace<NewSource, NewTarget>(\n newSchema: Schema<NewSource, NewTarget>\n ): MutableSchema<NewSource, NewTarget>;\n /**\n * Merges the original {@link Schema | schema} with the given one.\n *\n * @param newSchema - The {@link Schema | schema} to use to merge with the original one.\n * @returns The {@link Schema | schema} returned by the merge.\n */\n // eslint-disable-next-line @typescript-eslint/ban-types\n $override<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Creates a new {@link Schema | schema} using the original one as starting point.\n * The original {@link Schema | schema} will remain unchanged.\n *\n * @param newSchema - The {@link Schema | schema} to be used to extend the original one.\n * Both schema's Target and Source can be unique or also be extending from another one.\n * @returns The {@link Schema | schema} created.\n */\n $extends<NewSource extends Source, NewTarget extends Target>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, Omit<NewTarget, keyof Target>>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n // eslint-disable-next-line @typescript-eslint/ban-types\n $extends<NewSource, NewTarget = {}>(\n newSchema: DeepPartial<Schema<Source & NewSource, Target>> &\n Schema<Source & NewSource, NewTarget>\n ): MutableSchema<Source & NewSource, Target & NewTarget>;\n /**\n * Returns a string representing of the {@link Schema | schema}.\n *\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @returns The string representation.\n */\n toString(includeInternalMethods?: boolean): string;\n};\n/**\n * The possible transformers to apply to the target key.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param TargetKey - The target key to apply the transformation.\n * @public\n */\nexport type SchemaTransformer<Source, Target, TargetKey extends keyof Target> =\n | PathTransformer<Source, Target[TargetKey]>\n | FunctionTransformer<Source, Target[TargetKey]>\n | SubSchemaTransformer<Source, Target[TargetKey]>\n | Schema<Source, Exclude<Target[TargetKey], AnyFunction | Primitive>>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: 'id',\n * hits: 'count'\n * };\n *\n * const wrongSubSchema: Schema<Source, Target> = {\n * // @ts-expect-error\n * title: 'count', // This raises a TS error\n * hits: 'count'\n * };\n * ```\n * @public\n */\nexport type PathTransformer<Source, Target> = ExtractPathByType<Source, Target>;\n\n/**\n * A function with the source object and mapper context as parameters that returns the value of a\n * target's property.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * count: number;\n * }\n *\n * interface Target {\n * title: string;\n * hits: number;\n * }\n *\n * const subSchema: Schema<Source, Target> = {\n * title: source => source.id,\n * hits: (source, context) => context.requestParameters.query === 'example'\n * ? source.count\n * : 0\n * };\n * ```\n * @public\n */\nexport type FunctionTransformer<Source, Target> = (\n source: Source,\n context?: MapperContext\n) => Target;\n\n/**\n * An object containing a schema narrowing its source object based on the given path.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @example\n * ```typescript\n * interface Source {\n * id: string;\n * facets: {\n * name: string;\n * count: number;\n * };\n * images: string[];\n * }\n *\n * interface Target {\n * identifier: string;\n * filters: {\n * id: string;\n * numFound: number;\n * };\n * img: string[]\n * }\n *\n * const subSchema: SubSchemaTransformer<Source, Target['filters']> = {\n * $path: 'facets',\n * $subSchema: {\n * id: 'name',\n * numFound: 'count'\n * }\n * };\n * ```\n * @public\n */\nexport type SubSchemaTransformer<Source, Target> = {\n [Path in ExtractPath<Source>]: {\n $context?: MapperContext;\n $path: Path;\n $subSchema:\n | SubSchema<Source, Target, Path>\n | '$self'\n | ((source: Source) => SubSchema<Source, Target, Path>);\n };\n}[ExtractPath<Source>];\n\n/**\n * A {@link Schema | schema} that will be applied to an inner path of an object.\n *\n * @param Source - The source object.\n * @param Target - The target object.\n * @param Path - The path where the schema will be applied.\n * @public\n */\nexport type SubSchema<Source, Target, Path extends ExtractPath<Source>> = ExtractType<\n Source,\n Path\n> extends (infer SourceArrayType)[]\n ? Target extends (infer TargetArrayType)[]\n ? Schema<SourceArrayType, TargetArrayType>\n : never\n : Target extends []\n ? never\n : Schema<ExtractType<Source, Path>, Target>;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/schemas/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnE;;GAEG;AACH,MAAM,6BAA6B,GAAa,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAElG;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA8B;IAE9B,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,CAAC,SAAS;YAChB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;gBAClB,IAAI,gBAAgB,CAAC,GAAa,CAAC,EAAE;oBACnC,OAAO;iBACR;gBACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/B;+EACmE;YACnE,OAAO,IAAW,CAAC;QACrB,CAAC;QACD,SAAS,CAAC,SAAS;YACjB,OAAO,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,QAAQ,CAAC,SAAS;YAChB,OAAO,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,CAAC,sBAAsB,GAAG,KAAK;YACrC,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,SAAS,CAChB,IAA6B,EAC7B,sBAA+B,EAC/B,IAAI,GAAG,CAAC;IAER,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC3B,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE;YACnB,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,QAAQ,SAAS,CAC7C,KAAK,EACL,sBAAsB,EACtB,EAAE,IAAI,CACP,GAAG,WAAW,MAAM,CAAC;SACvB;aAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,sBAAsB,EAAE;YACjF,4EAA4E;YAC5E,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,KAAK,KAAK,KAAK,CAAC;SAC/C;IACH,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { deepMerge } from '@empathyco/x-deep-merge';\nimport { forEach, isFunction, isObject } from '@empathyco/x-utils';\nimport { MutableSchema, Schema } from './types';\n\n/**\n * Collection of internal method names for {@link MutableSchema | mutable schemas}.\n */\nconst mutableSchemasInternalMethods: string[] = ['$replace', '$override', '$extends', 'toString'];\n\n/**\n * Creates a {@link MutableSchema | mutable schema } version of a given {@link Schema | schema}.\n *\n * @param schema - The {@link Schema | schema} to make mutable.\n *\n * @returns A {@link MutableSchema | mutable schema} version of the given {@link Schema | schema}.\n *\n * @public\n */\nexport function createMutableSchema<Source, Target>(\n schema: Schema<Source, Target>\n): MutableSchema<Source, Target> {\n return {\n ...schema,\n $replace(newSchema) {\n forEach(this, key => {\n if (isInternalMethod(key as string)) {\n return;\n }\n delete this[key];\n });\n Object.assign(this, newSchema);\n /* We are replacing the schema with a completely new schema , so it makes sense that TS\n complains that the old schema and the new one are not the same. */\n return this as any;\n },\n $override(newSchema) {\n return deepMerge(this, newSchema);\n },\n $extends(newSchema) {\n return deepMerge({}, this, newSchema);\n },\n toString(includeInternalMethods = false) {\n return serialize(this, !!includeInternalMethods);\n }\n };\n}\n\n/**\n * Checks if the given key is a {@link MutableSchema | mutableSchema} method.\n *\n * @param name - The key to check.\n *\n * @returns True if it is a {@link MutableSchema | mutableSchema} method,\n * false otherwise.\n *\n * @public\n */\nexport function isInternalMethod(name: string): boolean {\n return mutableSchemasInternalMethods.includes(name);\n}\n\n/**\n * Returns a string representing of the given object.\n *\n * @param data - The object to get the string representation from.\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @param deep - The level of indentation.\n * @returns The string representation.\n */\nfunction serialize(\n data: Record<string, unknown>,\n includeInternalMethods: boolean,\n deep = 0\n): string {\n const indentation = ' '.repeat(deep);\n let output = '';\n forEach(data, (key, value) => {\n if (isObject(value)) {\n output += `${indentation}${key}: {\\n${serialize(\n value,\n includeInternalMethods,\n ++deep\n )}${indentation}},\\n`;\n } else if (!isFunction(value) || !isInternalMethod(key) || includeInternalMethods) {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n output += `${indentation}${key}: ${value},\\n`;\n }\n });\n return output;\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/schemas/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAGnE;;GAEG;AACH,MAAM,6BAA6B,GAAa,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAElG;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA8B;IAE9B,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,CAAC,SAAS;YAChB,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE;gBAClB,IAAI,gBAAgB,CAAC,GAAa,CAAC,EAAE;oBACnC,OAAO;iBACR;gBACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;YACnB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC/B;+EACmE;YACnE,OAAO,IAAW,CAAC;QACrB,CAAC;QACD,SAAS,CAAC,SAAS;YACjB,OAAO,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACpC,CAAC;QACD,QAAQ,CAAC,SAAkB;YACzB,OAAO,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QACxC,CAAC;QACD,QAAQ,CAAC,sBAAsB,GAAG,KAAK;YACrC,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC;QACnD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,6BAA6B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,SAAS,CAChB,IAA6B,EAC7B,sBAA+B,EAC/B,IAAI,GAAG,CAAC;IAER,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC3B,IAAI,QAAQ,CAAC,KAAK,CAAC,EAAE;YACnB,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,QAAQ,SAAS,CAC7C,KAAK,EACL,sBAAsB,EACtB,EAAE,IAAI,CACP,GAAG,WAAW,MAAM,CAAC;SACvB;aAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,sBAAsB,EAAE;YACjF,4EAA4E;YAC5E,MAAM,IAAI,GAAG,WAAW,GAAG,GAAG,KAAK,KAAK,KAAK,CAAC;SAC/C;IACH,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { deepMerge } from '@empathyco/x-deep-merge';\nimport { forEach, isFunction, isObject } from '@empathyco/x-utils';\nimport { MutableSchema, Schema } from './types';\n\n/**\n * Collection of internal method names for {@link MutableSchema | mutable schemas}.\n */\nconst mutableSchemasInternalMethods: string[] = ['$replace', '$override', '$extends', 'toString'];\n\n/**\n * Creates a {@link MutableSchema | mutable schema } version of a given {@link Schema | schema}.\n *\n * @param schema - The {@link Schema | schema} to make mutable.\n *\n * @returns A {@link MutableSchema | mutable schema} version of the given {@link Schema | schema}.\n *\n * @public\n */\nexport function createMutableSchema<Source, Target>(\n schema: Schema<Source, Target>\n): MutableSchema<Source, Target> {\n return {\n ...schema,\n $replace(newSchema) {\n forEach(this, key => {\n if (isInternalMethod(key as string)) {\n return;\n }\n delete this[key];\n });\n Object.assign(this, newSchema);\n /* We are replacing the schema with a completely new schema , so it makes sense that TS\n complains that the old schema and the new one are not the same. */\n return this as any;\n },\n $override(newSchema) {\n return deepMerge(this, newSchema);\n },\n $extends(newSchema: unknown) {\n return deepMerge({}, this, newSchema);\n },\n toString(includeInternalMethods = false) {\n return serialize(this, !!includeInternalMethods);\n }\n };\n}\n\n/**\n * Checks if the given key is a {@link MutableSchema | mutableSchema} method.\n *\n * @param name - The key to check.\n *\n * @returns True if it is a {@link MutableSchema | mutableSchema} method,\n * false otherwise.\n *\n * @public\n */\nexport function isInternalMethod(name: string): boolean {\n return mutableSchemasInternalMethods.includes(name);\n}\n\n/**\n * Returns a string representing of the given object.\n *\n * @param data - The object to get the string representation from.\n * @param includeInternalMethods - Flag to include in the string representation\n * the internal methods. Disabled by default.\n * @param deep - The level of indentation.\n * @returns The string representation.\n */\nfunction serialize(\n data: Record<string, unknown>,\n includeInternalMethods: boolean,\n deep = 0\n): string {\n const indentation = ' '.repeat(deep);\n let output = '';\n forEach(data, (key, value) => {\n if (isObject(value)) {\n output += `${indentation}${key}: {\\n${serialize(\n value,\n includeInternalMethods,\n ++deep\n )}${indentation}},\\n`;\n } else if (!isFunction(value) || !isInternalMethod(key) || includeInternalMethods) {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n output += `${indentation}${key}: ${value},\\n`;\n }\n });\n return output;\n}\n"]}
@@ -64,8 +64,10 @@ export declare type MutableSchema<Source, Target> = Schema<Source, Target> & {
64
64
  * The original {@link Schema | schema} will remain unchanged.
65
65
  *
66
66
  * @param newSchema - The {@link Schema | schema} to be used to extend the original one.
67
+ * Both schema's Target and Source can be unique or also be extending from another one.
67
68
  * @returns The {@link Schema | schema} created.
68
69
  */
70
+ $extends<NewSource extends Source, NewTarget extends Target>(newSchema: DeepPartial<Schema<Source & NewSource, Target>> & Schema<Source & NewSource, Omit<NewTarget, keyof Target>>): MutableSchema<Source & NewSource, Target & NewTarget>;
69
71
  $extends<NewSource, NewTarget = {}>(newSchema: DeepPartial<Schema<Source & NewSource, Target>> & Schema<Source & NewSource, NewTarget>): MutableSchema<Source & NewSource, Target & NewTarget>;
70
72
  /**
71
73
  * Returns a string representing of the {@link Schema | schema}.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@empathyco/x-adapter",
3
- "version": "8.0.0-alpha.17",
3
+ "version": "8.0.0-alpha.19",
4
4
  "description": "A utils library to create a client for any API",
5
5
  "author": "Empathy Systems Corporation S.L.",
6
6
  "license": "Apache-2.0",
@@ -35,9 +35,9 @@
35
35
  "prepublishOnly": "npm run build"
36
36
  },
37
37
  "dependencies": {
38
- "@empathyco/x-deep-merge": "^1.3.0-alpha.26",
39
- "@empathyco/x-utils": "^1.0.0-alpha.12",
40
- "tslib": "~2.3.0"
38
+ "@empathyco/x-deep-merge": "^1.3.0-alpha.27",
39
+ "@empathyco/x-utils": "^1.0.0-alpha.13",
40
+ "tslib": "~2.4.1"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/jest": "~27.0.3",
@@ -50,5 +50,5 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "d691003af599189d0b6b993178e337acb4900e9e"
53
+ "gitHead": "b5640ccccd296584a4775a8db625f9039b6025e9"
54
54
  }