chain-simple 0.0.4 → 1.0.1

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/built/index.d.ts CHANGED
@@ -1,5 +1,43 @@
1
- declare function wrapObj(item: any, config?: {
1
+ type TFn = (...args: any) => any;
2
+ type TReplaceReturnType<T extends TFn, TNewReturnType> = (...args: Parameters<T>) => TNewReturnType;
3
+ export type TChainable<T extends Record<string, TFn>> = {
4
+ [K in keyof T]: TReplaceReturnType<T[K], ReturnType<T[K]> & TChainable<T>>;
5
+ };
6
+ /**
7
+ * @example
8
+ * const {makePropertiesChainable} = require('chain-simple');
9
+ * const obj = {
10
+ * async method1() {
11
+ * return Promise.resolve(1).then(value => {
12
+ * console.log('method1', value);
13
+ * return value;
14
+ * });
15
+ * },
16
+ * async method2() {
17
+ * return Promise.resolve(2).then(value => {
18
+ * console.log('method2', value);
19
+ * return value;
20
+ * });
21
+ * },
22
+ * async method3() {
23
+ * return Promise.resolve(3).then(value => {
24
+ * console.log('method3', value);
25
+ * return value;
26
+ * });
27
+ * },
28
+ * };
29
+ * const chainableObj = makePropertiesChainable(obj);
30
+ * obj.method1().method3().then((val) => console.log(val))
31
+ *
32
+ *
33
+ * @param {!object} item
34
+ * @param {{getEntity: string}} [config] config to describe how to get original not project object
35
+ * @returns {object} object with chainable properties
36
+ */
37
+ declare function makePropertiesChainable(item: any, config?: {
2
38
  getEntity: string;
3
39
  }): any;
4
- declare function wrapConstruct(constructorFunction: any): any;
5
- export { wrapConstruct, wrapObj };
40
+ declare function makeConstructorInstancePropertiesChainable(constructorFunction: any, config?: {
41
+ getEntity: string;
42
+ }): any;
43
+ export { makePropertiesChainable, makeConstructorInstancePropertiesChainable };
package/built/index.js CHANGED
@@ -1,13 +1,45 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapObj = exports.wrapConstruct = void 0;
3
+ exports.makeConstructorInstancePropertiesChainable = exports.makePropertiesChainable = void 0;
4
4
  const sat_utils_1 = require("sat-utils");
5
- sat_utils_1.logger.setLogLevel(process.env.LOG_LEVEL);
6
- function wrapObj(item, config) {
7
- if (!sat_utils_1.canBeProxed(item)) {
5
+ const logger_1 = require("./logger");
6
+ logger_1.logger.setLogLevel(process.env.CHAIN_SIMPLE_LOG_LEVEL);
7
+ /**
8
+ * @example
9
+ * const {makePropertiesChainable} = require('chain-simple');
10
+ * const obj = {
11
+ * async method1() {
12
+ * return Promise.resolve(1).then(value => {
13
+ * console.log('method1', value);
14
+ * return value;
15
+ * });
16
+ * },
17
+ * async method2() {
18
+ * return Promise.resolve(2).then(value => {
19
+ * console.log('method2', value);
20
+ * return value;
21
+ * });
22
+ * },
23
+ * async method3() {
24
+ * return Promise.resolve(3).then(value => {
25
+ * console.log('method3', value);
26
+ * return value;
27
+ * });
28
+ * },
29
+ * };
30
+ * const chainableObj = makePropertiesChainable(obj);
31
+ * obj.method1().method3().then((val) => console.log(val))
32
+ *
33
+ *
34
+ * @param {!object} item
35
+ * @param {{getEntity: string}} [config] config to describe how to get original not project object
36
+ * @returns {object} object with chainable properties
37
+ */
38
+ function makePropertiesChainable(item, config) {
39
+ if (!(0, sat_utils_1.canBeProxed)(item)) {
8
40
  throw new TypeError('first argument should be an entity that can be proxed');
9
41
  }
10
- if (!sat_utils_1.isUndefined(config) && !sat_utils_1.isObject(config)) {
42
+ if (!(0, sat_utils_1.isUndefined)(config) && !(0, sat_utils_1.isObject)(config)) {
11
43
  throw new TypeError('second argument should be an object');
12
44
  }
13
45
  let proxifiedResult = item;
@@ -16,7 +48,7 @@ function wrapObj(item, config) {
16
48
  if (config && config.getEntity === p) {
17
49
  return item;
18
50
  }
19
- sat_utils_1.logger.info(p);
51
+ logger_1.logger.info(p);
20
52
  if (p === Symbol.toStringTag) {
21
53
  return proxifiedResult[Symbol.toStringTag];
22
54
  }
@@ -26,21 +58,21 @@ function wrapObj(item, config) {
26
58
  };
27
59
  }
28
60
  if (p === 'toJSON') {
29
- sat_utils_1.logger.info('In to JSON');
61
+ logger_1.logger.info('In to JSON');
30
62
  return function () {
31
63
  return proxifiedResult;
32
64
  };
33
65
  }
34
- if (!sat_utils_1.isFunction(item[p]) &&
35
- !sat_utils_1.isAsyncFunction(item[p]) &&
36
- !sat_utils_1.isPromise(proxifiedResult) &&
66
+ if (!(0, sat_utils_1.isFunction)(item[p]) &&
67
+ !(0, sat_utils_1.isAsyncFunction)(item[p]) &&
68
+ !(0, sat_utils_1.isPromise)(proxifiedResult) &&
37
69
  item[p] &&
38
70
  !proxifiedResult[p]) {
39
- sat_utils_1.logger.info('In to not function, not async function, resulter is not a promise and target has prop');
71
+ logger_1.logger.info('In to not function, not async function, resulter is not a promise and target has prop');
40
72
  return item[p];
41
73
  }
42
- else if ((sat_utils_1.isFunction(item[p]) || sat_utils_1.isAsyncFunction(item[p])) && sat_utils_1.isPromise(proxifiedResult)) {
43
- sat_utils_1.logger.info('In to function or async function and resulter is a promise');
74
+ else if (((0, sat_utils_1.isFunction)(item[p]) || (0, sat_utils_1.isAsyncFunction)(item[p])) && (0, sat_utils_1.isPromise)(proxifiedResult)) {
75
+ logger_1.logger.info('In to function or async function and resulter is a promise');
44
76
  return function (...arguments_) {
45
77
  async function handler() {
46
78
  await proxifiedResult;
@@ -50,8 +82,8 @@ function wrapObj(item, config) {
50
82
  return proxed;
51
83
  };
52
84
  }
53
- else if (sat_utils_1.isAsyncFunction(item[p]) && !sat_utils_1.isPromise(proxifiedResult)) {
54
- sat_utils_1.logger.info('In to async function and resulter is a promise');
85
+ else if ((0, sat_utils_1.isAsyncFunction)(item[p]) && !(0, sat_utils_1.isPromise)(proxifiedResult)) {
86
+ logger_1.logger.info('In to async function and resulter is a promise');
55
87
  return function (...arguments_) {
56
88
  async function handler() {
57
89
  return item[p](...arguments_);
@@ -60,36 +92,42 @@ function wrapObj(item, config) {
60
92
  return proxed;
61
93
  };
62
94
  }
63
- else if (sat_utils_1.isFunction(item[p]) && !sat_utils_1.isPromise(proxifiedResult)) {
64
- sat_utils_1.logger.info('In to function and resulter is not a promise');
95
+ else if ((0, sat_utils_1.isFunction)(item[p]) && !(0, sat_utils_1.isPromise)(proxifiedResult)) {
96
+ logger_1.logger.info('In to function and resulter is not a promise');
65
97
  return function (...arguments_) {
66
98
  proxifiedResult = item[p](...arguments_);
67
99
  return proxed;
68
100
  };
69
101
  }
70
- else if ((p === 'then' || p === 'catch') && sat_utils_1.isPromise(proxifiedResult)) {
71
- sat_utils_1.logger.info('In then catch');
102
+ else if ((p === 'then' || p === 'catch') && (0, sat_utils_1.isPromise)(proxifiedResult)) {
103
+ logger_1.logger.info('In then catch');
72
104
  /** @info logging */
73
- sat_utils_1.logger.info('start call promise: ', p);
74
- if (!sat_utils_1.isPromise(proxifiedResult)) {
105
+ logger_1.logger.info('start call promise: ', p);
106
+ if (!(0, sat_utils_1.isPromise)(proxifiedResult)) {
75
107
  return proxifiedResult;
76
108
  }
77
109
  return async function (onRes, onRej) {
78
110
  const catcher = p === 'catch' ? onRes : onRej;
79
- proxifiedResult = await proxifiedResult.catch(error => ({ error, ____proxed____error: true }));
80
- if (proxifiedResult && proxifiedResult.____proxed____error) {
111
+ proxifiedResult = await proxifiedResult.catch(error => {
112
+ return { error, ____proxed____error: true };
113
+ });
114
+ if (proxifiedResult && proxifiedResult.____proxed____error && (0, sat_utils_1.isFunction)(catcher)) {
81
115
  return catcher(proxifiedResult.error);
82
116
  }
117
+ if (proxifiedResult && proxifiedResult.____proxed____error) {
118
+ const promised = Promise.reject(proxifiedResult.error);
119
+ return promised[p].call(promised, onRes, onRej);
120
+ }
83
121
  const promised = Promise.resolve(proxifiedResult);
84
122
  return promised[p].call(promised, onRes, onRej);
85
123
  };
86
124
  }
87
125
  else if (proxifiedResult[p]) {
88
- sat_utils_1.logger.info('In resulter has prop');
126
+ logger_1.logger.info('In resulter has prop');
89
127
  return proxifiedResult[p];
90
128
  }
91
129
  if (!(p in item) && p in proxifiedResult) {
92
- sat_utils_1.logger.info('In target does not have prop but resulter has prop');
130
+ logger_1.logger.info('In target does not have prop but resulter has prop');
93
131
  return proxifiedResult[p];
94
132
  }
95
133
  },
@@ -106,15 +144,17 @@ function wrapObj(item, config) {
106
144
  });
107
145
  return proxed;
108
146
  }
109
- exports.wrapObj = wrapObj;
110
- const handlerConstructor = {
111
- construct(target, args) {
112
- const item = new target(...args);
113
- return wrapObj(item);
114
- },
115
- };
116
- function wrapConstruct(constructorFunction) {
117
- return new Proxy(constructorFunction, handlerConstructor);
147
+ exports.makePropertiesChainable = makePropertiesChainable;
148
+ function handlerConstructor(config) {
149
+ return {
150
+ construct(target, args) {
151
+ const item = new target(...args);
152
+ return makePropertiesChainable(item, config);
153
+ },
154
+ };
155
+ }
156
+ function makeConstructorInstancePropertiesChainable(constructorFunction, config) {
157
+ return new Proxy(constructorFunction, handlerConstructor(config));
118
158
  }
119
- exports.wrapConstruct = wrapConstruct;
159
+ exports.makeConstructorInstancePropertiesChainable = makeConstructorInstancePropertiesChainable;
120
160
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,10 @@
1
+ declare const logger: {
2
+ logLevel: string;
3
+ log(...args: any[]): void;
4
+ info(...args: any[]): void;
5
+ warn(...args: any[]): void;
6
+ error(...args: any[]): void;
7
+ setLogLevel(level: string): void;
8
+ addCustomLevel(loggerDescription: any, logLevel: string, description: string, consoleOutput: string, descriptionColor: string, messageColor: any): void;
9
+ };
10
+ export { logger };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.logger = void 0;
4
+ const sat_utils_1 = require("sat-utils");
5
+ const logger = (0, sat_utils_1.createLogger)();
6
+ exports.logger = logger;
7
+ //# sourceMappingURL=logger.js.map
package/lib/index.ts ADDED
@@ -0,0 +1,176 @@
1
+ import { isObject, isPromise, isFunction, isAsyncFunction, canBeProxed, isUndefined } from 'sat-utils';
2
+
3
+ import { logger } from './logger';
4
+
5
+ logger.setLogLevel(process.env.CHAIN_SIMPLE_LOG_LEVEL);
6
+
7
+ type TFn = (...args: any) => any;
8
+
9
+ type TReplaceReturnType<T extends TFn, TNewReturnType> = (...args: Parameters<T>) => TNewReturnType;
10
+
11
+ export type TChainable<T extends Record<string, TFn>> = {
12
+ [K in keyof T]: TReplaceReturnType<T[K], ReturnType<T[K]> & TChainable<T>>;
13
+ };
14
+
15
+ /**
16
+ * @example
17
+ * const {makePropertiesChainable} = require('chain-simple');
18
+ * const obj = {
19
+ * async method1() {
20
+ * return Promise.resolve(1).then(value => {
21
+ * console.log('method1', value);
22
+ * return value;
23
+ * });
24
+ * },
25
+ * async method2() {
26
+ * return Promise.resolve(2).then(value => {
27
+ * console.log('method2', value);
28
+ * return value;
29
+ * });
30
+ * },
31
+ * async method3() {
32
+ * return Promise.resolve(3).then(value => {
33
+ * console.log('method3', value);
34
+ * return value;
35
+ * });
36
+ * },
37
+ * };
38
+ * const chainableObj = makePropertiesChainable(obj);
39
+ * obj.method1().method3().then((val) => console.log(val))
40
+ *
41
+ *
42
+ * @param {!object} item
43
+ * @param {{getEntity: string}} [config] config to describe how to get original not project object
44
+ * @returns {object} object with chainable properties
45
+ */
46
+ function makePropertiesChainable(item, config?: { getEntity: string }) {
47
+ if (!canBeProxed(item)) {
48
+ throw new TypeError('first argument should be an entity that can be proxed');
49
+ }
50
+
51
+ if (!isUndefined(config) && !isObject(config)) {
52
+ throw new TypeError('second argument should be an object');
53
+ }
54
+
55
+ let proxifiedResult = item;
56
+ const proxed = new Proxy(item, {
57
+ get(_t, p) {
58
+ if (config && config.getEntity === p) {
59
+ return item;
60
+ }
61
+
62
+ logger.info(p);
63
+ if (p === Symbol.toStringTag) {
64
+ return proxifiedResult[Symbol.toStringTag];
65
+ }
66
+
67
+ if (p === 'toString') {
68
+ return function (...args) {
69
+ return proxifiedResult.toString(...args);
70
+ };
71
+ }
72
+
73
+ if (p === 'toJSON') {
74
+ logger.info('In to JSON');
75
+ return function () {
76
+ return proxifiedResult;
77
+ };
78
+ }
79
+ if (
80
+ !isFunction(item[p]) &&
81
+ !isAsyncFunction(item[p]) &&
82
+ !isPromise(proxifiedResult) &&
83
+ item[p] &&
84
+ !proxifiedResult[p]
85
+ ) {
86
+ logger.info('In to not function, not async function, resulter is not a promise and target has prop');
87
+ return item[p];
88
+ } else if ((isFunction(item[p]) || isAsyncFunction(item[p])) && isPromise(proxifiedResult)) {
89
+ logger.info('In to function or async function and resulter is a promise');
90
+ return function (...arguments_) {
91
+ async function handler() {
92
+ await proxifiedResult;
93
+ return item[p](...arguments_);
94
+ }
95
+ proxifiedResult = handler();
96
+ return proxed;
97
+ };
98
+ } else if (isAsyncFunction(item[p]) && !isPromise(proxifiedResult)) {
99
+ logger.info('In to async function and resulter is a promise');
100
+ return function (...arguments_) {
101
+ async function handler() {
102
+ return item[p](...arguments_);
103
+ }
104
+ proxifiedResult = handler();
105
+ return proxed;
106
+ };
107
+ } else if (isFunction(item[p]) && !isPromise(proxifiedResult)) {
108
+ logger.info('In to function and resulter is not a promise');
109
+ return function (...arguments_) {
110
+ proxifiedResult = item[p](...arguments_);
111
+ return proxed;
112
+ };
113
+ } else if ((p === 'then' || p === 'catch') && isPromise(proxifiedResult)) {
114
+ logger.info('In then catch');
115
+ /** @info logging */
116
+ logger.info('start call promise: ', p);
117
+ if (!isPromise(proxifiedResult)) {
118
+ return proxifiedResult;
119
+ }
120
+ return async function (onRes, onRej) {
121
+ const catcher = p === 'catch' ? onRes : onRej;
122
+
123
+ proxifiedResult = await proxifiedResult.catch(error => {
124
+ return { error, ____proxed____error: true };
125
+ });
126
+
127
+ if (proxifiedResult && proxifiedResult.____proxed____error && isFunction(catcher)) {
128
+ return catcher(proxifiedResult.error);
129
+ }
130
+
131
+ if (proxifiedResult && proxifiedResult.____proxed____error) {
132
+ const promised = Promise.reject(proxifiedResult.error);
133
+ return promised[p].call(promised, onRes, onRej);
134
+ }
135
+
136
+ const promised = Promise.resolve(proxifiedResult);
137
+ return promised[p].call(promised, onRes, onRej);
138
+ };
139
+ } else if (proxifiedResult[p]) {
140
+ logger.info('In resulter has prop');
141
+ return proxifiedResult[p];
142
+ }
143
+ if (!(p in item) && p in proxifiedResult) {
144
+ logger.info('In target does not have prop but resulter has prop');
145
+ return proxifiedResult[p];
146
+ }
147
+ },
148
+ /** @info basics */
149
+
150
+ getPrototypeOf(_t) {
151
+ return Object.getPrototypeOf(proxifiedResult);
152
+ },
153
+ ownKeys(_t) {
154
+ return Object.getOwnPropertyNames(proxifiedResult);
155
+ },
156
+ getOwnPropertyDescriptor(_t, p) {
157
+ return Object.getOwnPropertyDescriptor(proxifiedResult, p);
158
+ },
159
+ });
160
+ return proxed;
161
+ }
162
+
163
+ function handlerConstructor(config) {
164
+ return {
165
+ construct(target, args) {
166
+ const item = new target(...args);
167
+ return makePropertiesChainable(item, config);
168
+ },
169
+ };
170
+ }
171
+
172
+ function makeConstructorInstancePropertiesChainable(constructorFunction, config?: { getEntity: string }) {
173
+ return new Proxy(constructorFunction, handlerConstructor(config));
174
+ }
175
+
176
+ export { makePropertiesChainable, makeConstructorInstancePropertiesChainable };
package/lib/logger.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { createLogger } from 'sat-utils';
2
+
3
+ const logger = createLogger();
4
+
5
+ export { logger };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chain-simple",
3
- "version": "0.0.4",
3
+ "version": "1.0.1",
4
4
  "description": "Main purpose of this package is - provide simple way to build chain between any item methods",
5
5
  "main": "built/index.js",
6
6
  "directories": {
@@ -12,8 +12,8 @@
12
12
  "test:verbose": "LOG_LEVEL=VERBOSE mocha ./specs/**/*.spec.ts --require ts-node/register --timeout 30000",
13
13
  "test:watch": "mocha ./specs/**/*.spec.ts --require ts-node/register --timeout 30000 --watch",
14
14
  "lint": "eslint --ext .ts ./",
15
- "build": "rm -rf ./built && tsc",
16
- "build:prepublish": "rm -rf ./built && tsc --sourceMap false"
15
+ "tsc": "rm -rf ./built && tsc",
16
+ "prepublish": "npm run tsc"
17
17
  },
18
18
  "keywords": [
19
19
  "proxy object",
@@ -48,13 +48,13 @@
48
48
  "eslint-plugin-mocha": "^8.0.0",
49
49
  "mocha": "^8.2.1",
50
50
  "prettier": "^2.6.2",
51
- "ts-node": "^9.1.1",
52
- "typescript": "^4.1.3"
51
+ "ts-node": "^10.9.1",
52
+ "typescript": "^4.9.3"
53
53
  },
54
54
  "engines": {
55
55
  "node": ">=12.18.3"
56
56
  },
57
57
  "dependencies": {
58
- "sat-utils": "^0.0.42"
58
+ "sat-utils": "1.5.0"
59
59
  }
60
60
  }
package/readme.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # chain-simple
2
2
 
3
-
4
3
  ![npm downloads](https://img.shields.io/npm/dm/chain-simple.svg?style=flat-square)
5
4
 
6
5
  The purpose of this library is - build simple and flexible chainable call of the object` methods
7
6
 
8
- ```js
9
- const {wrapObj} = require('chain-simple');
7
+ ```ts
8
+ import { makePropertiesChainable } from 'chain-simple';
9
+ import type { TChainable } from 'chain-simple';
10
10
 
11
- const yourObjectWithMethods = {
11
+ const obj = {
12
12
  async method1() {
13
13
  return Promise.resolve(1).then(value => {
14
14
  console.log('method1', value);
@@ -29,12 +29,42 @@ const yourObjectWithMethods = {
29
29
  },
30
30
  };
31
31
 
32
- const wrappedObj = wrapObj(yourObjectWithMethods);
32
+ const chainableObj: TChainable<typeof obj> = makePropertiesChainable(obj);
33
+
34
+ chainableObj
35
+ .method1()
36
+ .method3()
37
+ .then(val => console.log(val)); // method1 1 \n method3 3 \n 3
38
+ ```
39
+
40
+ ```js
41
+ const { makePropertiesChainable } = require('chain-simple');
42
+
43
+ const obj = {
44
+ async method1() {
45
+ return Promise.resolve(1).then(value => {
46
+ console.log('method1', value);
47
+ return value;
48
+ });
49
+ },
50
+ async method2() {
51
+ return Promise.resolve(2).then(value => {
52
+ console.log('method2', value);
53
+ return value;
54
+ });
55
+ },
56
+ async method3() {
57
+ return Promise.resolve(3).then(value => {
58
+ console.log('method3', value);
59
+ return value;
60
+ });
61
+ },
62
+ };
33
63
 
34
- testExample();
35
- async function testExample() {
36
- const result = await wrappedObj.method1().method2().method3().method1();
64
+ const chainableObj: TChainable<typeof obj> = makePropertiesChainable(obj);
37
65
 
38
- console.log(result);
39
- }
40
- ```
66
+ chainableObj
67
+ .method1()
68
+ .method3()
69
+ .then(val => console.log(val)); // method1 1 \n method3 3 \n 3
70
+ ```