@xcrap/transformer 0.0.1 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,15 +2,21 @@ export * from "./transforming-model";
2
2
  export * from "./transformer";
3
3
  export * from "./transformers";
4
4
  export * from "./validators";
5
+ export type Data = {
6
+ local: Record<string, any>;
7
+ root: Record<string, any>;
8
+ };
5
9
  export type SkipFunction = () => void;
6
10
  export type TransformOptions<T, R> = {
7
11
  key: string;
12
+ scope?: keyof Data;
8
13
  transformer: (value: T) => R | Promise<R>;
9
14
  condition?: (value: T) => boolean | Promise<boolean>;
10
15
  };
11
- export declare function transform<T extends any, R extends any>({ key, transformer, condition }: TransformOptions<T, R>): (data: Record<string, any>, skip: SkipFunction) => Promise<void | R>;
16
+ export declare function transform<T extends any, R extends any>({ key, scope, transformer, condition }: TransformOptions<T, R>): (data: Data, skip: SkipFunction) => Promise<void | R>;
12
17
  export type GetOptions<T> = {
13
18
  key: string;
19
+ scope?: keyof Data;
14
20
  condition?: (value: T) => boolean | Promise<boolean>;
15
21
  };
16
- export declare function get<T extends any>({ key, condition }: GetOptions<T>): (data: Record<string, any>, skip: SkipFunction) => Promise<void | T>;
22
+ export declare function get<T extends any>({ key, scope, condition }: GetOptions<T>): (data: Data, skip: SkipFunction) => Promise<void | T>;
package/dist/index.js CHANGED
@@ -20,9 +20,10 @@ __exportStar(require("./transforming-model"), exports);
20
20
  __exportStar(require("./transformer"), exports);
21
21
  __exportStar(require("./transformers"), exports);
22
22
  __exportStar(require("./validators"), exports);
23
- function transform({ key, transformer, condition }) {
23
+ function transform({ key, scope = "local", transformer, condition }) {
24
24
  return async (data, skip) => {
25
- const value = data[key];
25
+ const scopedData = data[scope];
26
+ const value = scopedData[key];
26
27
  const isValid = condition ? await condition(value) : true;
27
28
  if (!isValid) {
28
29
  return skip();
@@ -31,9 +32,10 @@ function transform({ key, transformer, condition }) {
31
32
  return transformedValue;
32
33
  };
33
34
  }
34
- function get({ key, condition }) {
35
+ function get({ key, scope = "local", condition }) {
35
36
  return async (data, skip) => {
36
- const value = data[key];
37
+ const scopedData = data[scope];
38
+ const value = scopedData[key];
37
39
  const isValid = condition ? await condition(value) : true;
38
40
  if (!isValid) {
39
41
  return skip();
@@ -1,7 +1,8 @@
1
- import { SkipFunction } from ".";
2
- export type TransformerFunction = (data: Record<string, any>, skip: SkipFunction) => any | Promise<any>;
1
+ import { Data, SkipFunction } from ".";
2
+ export type TransformerFunction = (data: Data, skip: SkipFunction) => any | Promise<any>;
3
3
  export type TransformationModelShapeValueBase = TransformerFunction[];
4
4
  export type TransformationModelShapeNestedValue = {
5
+ key: string;
5
6
  multiple?: boolean;
6
7
  model: TransformingModel;
7
8
  };
@@ -17,8 +18,8 @@ export declare class TransformingModel {
17
18
  private readonly fieldsToDelete;
18
19
  private readonly fieldsToAppend;
19
20
  constructor(shape: TransformingModelShape);
20
- transform(data: Record<string, any>): Promise<Record<string, any>>;
21
- transformValueBase(value: TransformationModelShapeValueBase, key: string, data: any): Promise<any>;
22
- transformNestedValue(value: TransformationModelShapeNestedValue, data: any): Promise<any[] | Record<string, any>>;
21
+ transform(data: Record<string, any>, rootData?: Record<string, any>): Promise<Record<string, any>>;
22
+ transformValueBase(value: TransformationModelShapeValueBase, targetKey: string, data: Data): Promise<any>;
23
+ transformNestedValue(value: TransformationModelShapeNestedValue, localData: Record<string, any> | Record<string, any>[], rootData: Record<string, any>): Promise<Record<string, any> | Record<string, any>[]>;
23
24
  after({ delete: delete_, append }: TransformingModelAfterOptions): this;
24
25
  }
@@ -7,48 +7,59 @@ class TransformingModel {
7
7
  this.fieldsToDelete = [];
8
8
  this.fieldsToAppend = {};
9
9
  }
10
- async transform(data) {
11
- const result = { ...data };
10
+ async transform(data, rootData) {
11
+ const internalData = {
12
+ local: { ...data },
13
+ root: rootData || { ...data }
14
+ };
12
15
  for (const key in this.shape) {
13
16
  const value = this.shape[key];
14
17
  if (Array.isArray(value)) {
15
- result[key] = await this.transformValueBase(value, key, result);
18
+ internalData.local[key] = await this.transformValueBase(value, key, internalData);
16
19
  }
17
20
  else {
18
- result[key] = await this.transformNestedValue(value, result);
21
+ internalData.local[key] = await this.transformNestedValue(value, internalData.local, internalData.root);
19
22
  }
20
23
  }
21
24
  for (const field of this.fieldsToDelete) {
22
- delete result[field];
25
+ delete internalData.local[field];
23
26
  }
24
27
  for (const [key, value] of Object.entries(this.fieldsToAppend)) {
25
- result[key] = value;
28
+ internalData.local[key] = value;
26
29
  }
27
- return result;
30
+ return internalData.local;
28
31
  }
29
- async transformValueBase(value, key, data) {
30
- let result = data[key];
32
+ async transformValueBase(value, targetKey, data) {
33
+ let currentTransformedValue = data.local[targetKey];
31
34
  for (const transformer of value) {
32
- let skiped = false;
35
+ let skipped = false;
33
36
  const skip = () => {
34
- skiped = true;
37
+ skipped = true;
35
38
  };
36
- let tempResult = await transformer({
37
- ...data,
38
- [key]: result
39
- }, skip);
40
- if (!skiped) {
41
- result = tempResult;
39
+ const originalValueForThisIteration = currentTransformedValue;
40
+ const inputForTransformer = {
41
+ local: {
42
+ ...data.local,
43
+ [targetKey]: originalValueForThisIteration
44
+ },
45
+ root: data.root
46
+ };
47
+ let tempResult = await transformer(inputForTransformer, skip);
48
+ if (!skipped) {
49
+ currentTransformedValue = tempResult;
42
50
  }
43
51
  }
44
- return result;
52
+ return currentTransformedValue;
45
53
  }
46
- async transformNestedValue(value, data) {
54
+ async transformNestedValue(value, localData, rootData) {
47
55
  if (value.multiple) {
48
- return await Promise.all(data.map(value.model.transform.bind(this)));
56
+ if (!Array.isArray(localData)) {
57
+ throw new Error("Input data for a 'multiple' nested model must be an array.");
58
+ }
59
+ return await Promise.all(localData.map((item) => value.model.transform(item, rootData[value.key])));
49
60
  }
50
61
  else {
51
- return await value.model.transform(data);
62
+ return await value.model.transform({}, rootData[value.key]);
52
63
  }
53
64
  }
54
65
  after({ delete: delete_, append }) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcrap/transformer",
3
- "version": "0.0.1",
3
+ "version": "0.0.5",
4
4
  "description": "Xcrap Transformer is the data transformation package extracted from the Web Scraping framework Xcrap.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",