@pristine-ts/data-mapping-common 2.0.10 → 2.0.11

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.
Files changed (54) hide show
  1. package/dist/lib/cjs/builders/data-mapping.builder.js +8 -35
  2. package/dist/lib/cjs/builders/data-mapping.builder.js.map +1 -1
  3. package/dist/lib/cjs/data-mapping-common.js +1 -0
  4. package/dist/lib/cjs/data-mapping-common.js.map +1 -1
  5. package/dist/lib/cjs/interfaces/fluent-array-of-objects-options.interface.js +3 -0
  6. package/dist/lib/cjs/interfaces/fluent-array-of-objects-options.interface.js.map +1 -0
  7. package/dist/lib/cjs/interfaces/fluent-leaf-options.interface.js +3 -0
  8. package/dist/lib/cjs/interfaces/fluent-leaf-options.interface.js.map +1 -0
  9. package/dist/lib/cjs/interfaces/fluent-nested-options.interface.js +3 -0
  10. package/dist/lib/cjs/interfaces/fluent-nested-options.interface.js.map +1 -0
  11. package/dist/lib/cjs/interfaces/interfaces.js +3 -0
  12. package/dist/lib/cjs/interfaces/interfaces.js.map +1 -1
  13. package/dist/lib/cjs/nodes/base-data-mapping.node.js +94 -4
  14. package/dist/lib/cjs/nodes/base-data-mapping.node.js.map +1 -1
  15. package/dist/lib/cjs/nodes/data-mapping.node.js +12 -40
  16. package/dist/lib/cjs/nodes/data-mapping.node.js.map +1 -1
  17. package/dist/lib/cjs/serializers/data-mapping.serializer.js +81 -0
  18. package/dist/lib/cjs/serializers/data-mapping.serializer.js.map +1 -0
  19. package/dist/lib/cjs/serializers/serializers.js +18 -0
  20. package/dist/lib/cjs/serializers/serializers.js.map +1 -0
  21. package/dist/lib/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  22. package/dist/lib/esm/builders/data-mapping.builder.js +8 -35
  23. package/dist/lib/esm/builders/data-mapping.builder.js.map +1 -1
  24. package/dist/lib/esm/data-mapping-common.js +1 -0
  25. package/dist/lib/esm/data-mapping-common.js.map +1 -1
  26. package/dist/lib/esm/interfaces/fluent-array-of-objects-options.interface.js +2 -0
  27. package/dist/lib/esm/interfaces/fluent-array-of-objects-options.interface.js.map +1 -0
  28. package/dist/lib/esm/interfaces/fluent-leaf-options.interface.js +2 -0
  29. package/dist/lib/esm/interfaces/fluent-leaf-options.interface.js.map +1 -0
  30. package/dist/lib/esm/interfaces/fluent-nested-options.interface.js +2 -0
  31. package/dist/lib/esm/interfaces/fluent-nested-options.interface.js.map +1 -0
  32. package/dist/lib/esm/interfaces/interfaces.js +3 -0
  33. package/dist/lib/esm/interfaces/interfaces.js.map +1 -1
  34. package/dist/lib/esm/nodes/base-data-mapping.node.js +94 -4
  35. package/dist/lib/esm/nodes/base-data-mapping.node.js.map +1 -1
  36. package/dist/lib/esm/nodes/data-mapping.node.js +12 -40
  37. package/dist/lib/esm/nodes/data-mapping.node.js.map +1 -1
  38. package/dist/lib/esm/serializers/data-mapping.serializer.js +77 -0
  39. package/dist/lib/esm/serializers/data-mapping.serializer.js.map +1 -0
  40. package/dist/lib/esm/serializers/serializers.js +2 -0
  41. package/dist/lib/esm/serializers/serializers.js.map +1 -0
  42. package/dist/lib/esm/tsconfig.tsbuildinfo +1 -1
  43. package/dist/types/builders/data-mapping.builder.d.ts +5 -5
  44. package/dist/types/data-mapping-common.d.ts +1 -0
  45. package/dist/types/interfaces/fluent-array-of-objects-options.interface.d.ts +21 -0
  46. package/dist/types/interfaces/fluent-leaf-options.interface.d.ts +27 -0
  47. package/dist/types/interfaces/fluent-nested-options.interface.d.ts +19 -0
  48. package/dist/types/interfaces/interfaces.d.ts +3 -0
  49. package/dist/types/nodes/base-data-mapping.node.d.ts +39 -4
  50. package/dist/types/nodes/data-mapping.node.d.ts +9 -9
  51. package/dist/types/serializers/data-mapping.serializer.d.ts +46 -0
  52. package/dist/types/serializers/serializers.d.ts +1 -0
  53. package/package.json +3 -3
  54. package/readme.md +43 -1
@@ -82,14 +82,14 @@ export declare class DataMappingBuilder extends BaseDataMappingNode {
82
82
  */
83
83
  end(): DataMappingBuilder;
84
84
  /**
85
- * This method imports a schema.
86
- *
87
- * @param schema
85
+ * Rehydrate this builder from a previously-exported schema. Replaces every field this
86
+ * class owns; child nodes are rebuilt via `DataMappingSerializer.importChildren`, which is
87
+ * the same helper `DataMappingNode.import` uses (so the two stay consistent).
88
88
  */
89
89
  import(schema: any): void;
90
90
  /**
91
- * This method exports the schema as a plain object. The export does not mutate the live tree —
92
- * the builder remains usable for mapping after this call returns.
91
+ * Export the schema as a plain object. The export does not mutate the live tree — the
92
+ * builder remains usable for mapping after this call returns.
93
93
  */
94
94
  export(): {
95
95
  nodes: {
@@ -9,4 +9,5 @@ export * from "./normalizer-options/normalizer-options";
9
9
  export * from "./normalizers/normalizers";
10
10
  export * from "./options/options";
11
11
  export * from "./reporters/reporters";
12
+ export * from "./serializers/serializers";
12
13
  export * from "./types/types";
@@ -0,0 +1,21 @@
1
+ import { ClassConstructor } from "class-transformer";
2
+ import { ArrayMemberTypeFactoryCallbackType } from "../types/array-member-type-factory-callback.type";
3
+ /**
4
+ * Options for a fluent array-of-objects field (`arrayOfObjects()` on `BaseDataMappingNode`).
5
+ *
6
+ * Unlike `FluentNestedOptions`, `destinationType` here also accepts a factory callback for
7
+ * polymorphic arrays — where each element of the array maps to a different concrete class
8
+ * (e.g. an `items` array containing both `Cat` and `Dog`, discriminated by a `kind` field).
9
+ */
10
+ export interface FluentArrayOfObjectsOptions {
11
+ /**
12
+ * When true, the array node is skipped silently if the source property is missing.
13
+ */
14
+ isOptional?: boolean;
15
+ /**
16
+ * Either a class constructor (uniform array — every element maps to the same class) or a
17
+ * factory callback `(source, sourceProperty, index) => instance` that picks the concrete
18
+ * class per element.
19
+ */
20
+ destinationType?: ClassConstructor<any> | ArrayMemberTypeFactoryCallbackType;
21
+ }
@@ -0,0 +1,27 @@
1
+ import { DataNormalizerUniqueKey } from "../types/data-normalizer-unique-key.type";
2
+ /**
3
+ * Options for a fluent leaf field — used by both `field()` and `arrayOfScalars()` on
4
+ * `BaseDataMappingNode`. Both expose the same per-leaf knobs (normalizers, optional flag,
5
+ * excluded inherited normalizers), so they share this options shape.
6
+ */
7
+ export interface FluentLeafOptions {
8
+ /**
9
+ * Normalizers to apply to the value as it flows from source to destination. Each entry is
10
+ * either a unique key (shorthand) or `{key, options}` to pass normalizer-specific options.
11
+ */
12
+ normalizers?: Array<DataNormalizerUniqueKey | {
13
+ key: DataNormalizerUniqueKey;
14
+ options?: any;
15
+ }>;
16
+ /**
17
+ * Normalizers added at the builder root that should NOT apply to this leaf. Useful when a
18
+ * global normalizer (e.g. lowercase everything) needs to be skipped for one specific field
19
+ * (e.g. an API key that's case-sensitive).
20
+ */
21
+ excludeNormalizers?: DataNormalizerUniqueKey[];
22
+ /**
23
+ * When true, the leaf is skipped silently if the source property is missing. When false /
24
+ * undefined, a missing source property throws `DataMappingSourcePropertyNotFoundError`.
25
+ */
26
+ isOptional?: boolean;
27
+ }
@@ -0,0 +1,19 @@
1
+ import { ClassConstructor } from "class-transformer";
2
+ /**
3
+ * Options for a fluent single-nested-object field (`nested()` on `BaseDataMappingNode`).
4
+ *
5
+ * Single-object case: `destinationType` is strictly a class constructor. The
6
+ * polymorphic-array case (where the destination class is chosen per element) has its own
7
+ * options interface — see `FluentArrayOfObjectsOptions`.
8
+ */
9
+ export interface FluentNestedOptions {
10
+ /**
11
+ * When true, the nested node is skipped silently if the source property is missing.
12
+ */
13
+ isOptional?: boolean;
14
+ /**
15
+ * If set, the destination property is instantiated as this class (via `plainToInstance`).
16
+ * Without it, the destination is a plain object.
17
+ */
18
+ destinationType?: ClassConstructor<any>;
19
+ }
@@ -1,2 +1,5 @@
1
1
  export * from "./data-normalizer.interface";
2
2
  export * from "./data-mapping-interceptor.interface";
3
+ export * from "./fluent-array-of-objects-options.interface";
4
+ export * from "./fluent-leaf-options.interface";
5
+ export * from "./fluent-nested-options.interface";
@@ -1,15 +1,50 @@
1
1
  import { DataMappingNode } from "./data-mapping.node";
2
2
  import { DataMappingLeaf } from "./data-mapping.leaf";
3
+ import { FluentLeafOptions } from "../interfaces/fluent-leaf-options.interface";
4
+ import { FluentNestedOptions } from "../interfaces/fluent-nested-options.interface";
5
+ import { FluentArrayOfObjectsOptions } from "../interfaces/fluent-array-of-objects-options.interface";
3
6
  export declare abstract class BaseDataMappingNode {
4
7
  nodes: {
5
8
  [sourceProperty in string]: DataMappingNode | DataMappingLeaf;
6
9
  };
10
+ abstract add(): DataMappingLeaf;
11
+ abstract addNestingLevel(): DataMappingNode;
12
+ abstract addArrayOfObjects(): DataMappingNode;
13
+ abstract addArrayOfScalar(): DataMappingLeaf;
7
14
  /**
8
- * This method is called by the node itself to tell its parent that it has been build and is ready to be added.
9
- * We use this mechanism to force the `end()` method on the leaf to be called so we can do some validations before
10
- * adding it to the tree.
15
+ * Add a leaf mapping. `field(src)` is shorthand for `field(src, src)` (no rename).
11
16
  *
12
- * @param node
17
+ * Equivalent to `.add().setSourceProperty(src).setDestinationProperty(dst).end()`, plus
18
+ * applying normalizer / optional / excludeNormalizers options.
19
+ */
20
+ field(source: string, destination?: string, options?: FluentLeafOptions): this;
21
+ /**
22
+ * Add a nested object mapping. The build callback receives the new node and configures its
23
+ * children — no explicit `.end()` needed; this method calls it for you when the callback
24
+ * returns.
25
+ */
26
+ nested(source: string, destination: string, build: (node: DataMappingNode) => void, options?: FluentNestedOptions): this;
27
+ /**
28
+ * Add an array-of-objects mapping. The build callback configures the per-element schema —
29
+ * every element in the source array is mapped through it. `destinationType` can be a class
30
+ * (uniform array) or a factory callback (polymorphic array).
31
+ */
32
+ arrayOfObjects(source: string, destination: string, build: (node: DataMappingNode) => void, options?: FluentArrayOfObjectsOptions): this;
33
+ /**
34
+ * Add an array-of-scalars mapping. Normalizers in `options` apply to every element of the
35
+ * array, not to the array itself. `arrayOfScalars(src)` is shorthand for same-name source
36
+ * and destination.
37
+ */
38
+ arrayOfScalars(source: string, destination?: string, options?: FluentLeafOptions): this;
39
+ /**
40
+ * Called by the node itself to tell its parent that it has been built and is ready to be
41
+ * added. We use this mechanism to force the `end()` method on the leaf to be called so we
42
+ * can do some validations before adding it to the tree.
13
43
  */
14
44
  addNode(node: DataMappingLeaf | DataMappingNode): void;
45
+ /**
46
+ * Shared between `field()` and `arrayOfScalars()` — both take the same options shape.
47
+ * Static helper so it can be called against either a freshly-built leaf or any leaf type.
48
+ */
49
+ private static applyLeafOptions;
15
50
  }
@@ -132,19 +132,19 @@ export declare class DataMappingNode extends BaseDataMappingNode {
132
132
  */
133
133
  private runSubNodes;
134
134
  /**
135
- * This method imports a schema.
136
- *
137
- * @param schema
135
+ * Rehydrate this node from a previously-exported sub-schema. Children are rebuilt via
136
+ * `DataMappingSerializer.importChildren`, the same helper `DataMappingBuilder.import` uses
137
+ * (so the two stay consistent).
138
138
  */
139
139
  import(schema: any): void;
140
140
  /**
141
- * This method exports this node. The exported representation is a plain object it does not mutate
142
- * the live tree, so the same builder can continue to be used for mapping after `export()` is called.
141
+ * Export this node as a plain object. Does not mutate the live treethe builder remains
142
+ * usable for mapping after this call returns.
143
143
  *
144
- * `destinationType` is intentionally not serialized: class constructors aren't transferable, and
145
- * factory callbacks (`ArrayMemberTypeFactoryCallbackType`) hold closures. To rehydrate a schema with
146
- * the same destination instantiation behavior, decorate the destination class with class-transformer's
147
- * `@Type()` and pass the destination class to `DataMapper.map()`.
144
+ * `destinationType` is intentionally not serialized: class constructors aren't transferable,
145
+ * and factory callbacks (`ArrayMemberTypeFactoryCallbackType`) hold closures. To rehydrate a
146
+ * schema with the same destination instantiation behavior, decorate the destination class
147
+ * with class-transformer's `@Type()` and pass the destination class to `DataMapper.map()`.
148
148
  */
149
149
  export(): {
150
150
  _type: DataMappingNodeTypeEnum;
@@ -0,0 +1,46 @@
1
+ import { DataMappingNode } from "../nodes/data-mapping.node";
2
+ import { DataMappingLeaf } from "../nodes/data-mapping.leaf";
3
+ import { DataMappingBuilder } from "../builders/data-mapping.builder";
4
+ /**
5
+ * Pure helpers for serializing / deserializing the children-map shared between
6
+ * `DataMappingBuilder` and `DataMappingNode`.
7
+ *
8
+ * Both classes hold the same `{ [sourceProperty]: DataMappingNode | DataMappingLeaf }` shape
9
+ * and both need to walk it the same way during `import()` / `export()`. Keeping that walk in
10
+ * one place avoids the two implementations drifting apart (which they already had — see the
11
+ * old destination-property-leak bug).
12
+ *
13
+ * Stateless class-as-namespace per the project convention (no constructor dependencies, no
14
+ * instance state, so static methods make the call site read straight: `DataMappingSerializer.
15
+ * importChildren(...)`).
16
+ *
17
+ * Note on imports: this module is in a small cycle with `data-mapping.node.ts` — the
18
+ * serializer references Node and Leaf so it can instantiate them, and Node references the
19
+ * serializer so its `import()` / `export()` can delegate. The cycle resolves cleanly because
20
+ * the references are used only inside method bodies (not at module top level), so by the
21
+ * time anything runs both modules are fully evaluated.
22
+ */
23
+ export declare class DataMappingSerializer {
24
+ /**
25
+ * Rebuild a populated children map from the `nodes` field of a serialized schema.
26
+ *
27
+ * Dispatches on the `_type` discriminator: ScalarArray + Leaf hydrate as `DataMappingLeaf`,
28
+ * Node + ObjectArray hydrate as `DataMappingNode`. The created child's own `import()` is
29
+ * called to fill in its fields and (for nodes) recurse into its own children.
30
+ */
31
+ static importChildren(root: DataMappingBuilder, parent: DataMappingBuilder | DataMappingNode, schemaNodes: {
32
+ [key: string]: any;
33
+ } | undefined): {
34
+ [sourceProperty: string]: DataMappingNode | DataMappingLeaf;
35
+ };
36
+ /**
37
+ * Serialize a children map back into a plain `nodes` object suitable for embedding in a
38
+ * schema export. Returns a fresh object — does not mutate the input, so callers can safely
39
+ * continue to use the live tree after exporting.
40
+ */
41
+ static exportChildren(nodes: {
42
+ [sourceProperty: string]: DataMappingNode | DataMappingLeaf;
43
+ }): {
44
+ [key: string]: any;
45
+ };
46
+ }
@@ -0,0 +1 @@
1
+ export * from "./data-mapping.serializer";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pristine-ts/data-mapping-common",
3
- "version": "2.0.10",
3
+ "version": "2.0.11",
4
4
  "description": "",
5
5
  "module": "dist/lib/esm/data-mapping-common.js",
6
6
  "main": "dist/lib/cjs/data-mapping-common.js",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@pristine-ts/class-validator": "^2.0.4",
24
- "@pristine-ts/common": "^2.0.10",
24
+ "@pristine-ts/common": "^2.0.11",
25
25
  "@pristine-ts/metadata": "^1.0.16",
26
26
  "class-transformer": "^0.5.1",
27
27
  "date-fns": "^3.3.1"
@@ -63,7 +63,7 @@
63
63
  "jest-extended/all"
64
64
  ]
65
65
  },
66
- "gitHead": "3d0126d73d7a0dec99fcda3824981d893d1d0662",
66
+ "gitHead": "1e2fa6067d9eb4915a34400d03f2f3b896f03b2f",
67
67
  "repository": {
68
68
  "type": "git",
69
69
  "url": "https://github.com/magieno/pristine-ts.git",
package/readme.md CHANGED
@@ -1 +1,43 @@
1
- # Data Mapping module.
1
+ # @pristine-ts/data-mapping-common
2
+
3
+ Framework-agnostic core for [`@pristine-ts/data-mapping`](../data-mapping). No DI container,
4
+ no logging dependency — usable directly in Angular / browser bundles.
5
+
6
+ ## What's here
7
+
8
+ - `DataMapper` — `autoMap`, `map`, `mapAll`
9
+ - `AutoDataMappingBuilder` — schema inference from `@property` / `@array` decorators (with a `WeakMap` cache)
10
+ - `DataMappingBuilder` — fluent schema construction (`field`, `nested`, `arrayOfObjects`, `arrayOfScalars`)
11
+ - Built-in normalizers: `StringNormalizer`, `NumberNormalizer`, `BooleanNormalizer`, `DateNormalizer`, `LowercaseNormalizer`
12
+ - `ConsoleErrorReporter` — default error sink that writes to `console.error`
13
+
14
+ ## Standalone usage
15
+
16
+ ```sh
17
+ npm install @pristine-ts/data-mapping-common class-transformer
18
+ ```
19
+
20
+ ```ts
21
+ import {
22
+ DataMapper, AutoDataMappingBuilder,
23
+ StringNormalizer, NumberNormalizer, BooleanNormalizer, DateNormalizer, LowercaseNormalizer,
24
+ } from "@pristine-ts/data-mapping-common";
25
+
26
+ const dataMapper = new DataMapper(
27
+ new AutoDataMappingBuilder(),
28
+ [new StringNormalizer(), new NumberNormalizer(), new BooleanNormalizer(), new DateNormalizer(), new LowercaseNormalizer()],
29
+ [],
30
+ );
31
+
32
+ const user = await dataMapper.autoMap(payload, User);
33
+ ```
34
+
35
+ Errors go to `console.error` by default. Pass a custom `DataMapperErrorReporter` to the
36
+ constructor to redirect them.
37
+
38
+ ## Backend / DI usage
39
+
40
+ If you're inside a Pristine app, import [`@pristine-ts/data-mapping`](../data-mapping)
41
+ instead — it wires `DataMapper` into the DI container, registers the built-in normalizers,
42
+ and routes errors through `LogHandlerInterface`. **See [`@pristine-ts/data-mapping`](../data-mapping)
43
+ for the full API reference** — everything documented there is also exported from this package.