typeomatica 0.2.2 → 0.2.7

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.
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env sh
2
+ . "$(dirname -- "$0")/_/husky.sh"
3
+
4
+ npm test
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # typeomatica
1
+ # Type ø matica
2
2
 
3
3
  [![Coverage Status](https://coveralls.io/repos/github/wentout/typeomatica/badge.svg?branch=main)](https://coveralls.io/github/wentout/typeomatica?branch=main)
4
4
 
@@ -41,4 +41,4 @@ typeof something === 'string'
41
41
  to `stringProp` in runtime.
42
42
 
43
43
  As we describe Data Types — please take a peek for tests directory:
44
- [HERE](https://github.com/wentout/typeomatica/blob/main/test/index.ts).
44
+ [HERE](https://github.com/wentout/typeomatica/blob/main/test/index.ts).
package/jest.config.js CHANGED
@@ -4,7 +4,7 @@ module.exports = {
4
4
  testMatch: ['**/test/**/index.ts', '**/test/**/addition.js'],
5
5
  globals: {
6
6
  'ts-jest': {
7
- tsconfig: './tsconfig.spec.json'
7
+ tsconfig: './test/tsconfig.json'
8
8
  }
9
9
  },
10
10
  };
@@ -0,0 +1,6 @@
1
+ export declare const ErrorsNames: {
2
+ TYPE_MISMATCH: string;
3
+ ACCESS_DENIED: string;
4
+ MISSING_PROP: string;
5
+ RIP_FUNCTIONS: string;
6
+ };
package/lib/errors.js ADDED
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ErrorsNames = void 0;
4
+ exports.ErrorsNames = {
5
+ TYPE_MISMATCH: 'Type Mismatch',
6
+ ACCESS_DENIED: 'Value Access Denied',
7
+ MISSING_PROP: 'Attempt to Access to Undefined Prop',
8
+ RIP_FUNCTIONS: 'Functions are Restricted'
9
+ };
@@ -0,0 +1,2 @@
1
+ export declare const SymbolInitialValue: unique symbol;
2
+ export declare const FieldConstructor: ObjectConstructor;
package/lib/fields.js ADDED
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FieldConstructor = exports.SymbolInitialValue = void 0;
4
+ exports.SymbolInitialValue = Symbol('Initial Value');
5
+ exports.FieldConstructor = function (value) {
6
+ this[exports.SymbolInitialValue] = value;
7
+ };
8
+ Object.freeze(exports.FieldConstructor.prototype);
9
+ Object.seal(exports.FieldConstructor.prototype);
package/lib/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export declare type IDEF<T, P = {}, R = {}> = {
2
- new (...args: any[]): T;
3
- (this: T, ...args: any[]): R;
4
- prototype: P;
5
- };
6
1
  declare const BaseConstructor: ObjectConstructor;
7
2
  export declare class BaseClass extends BaseConstructor {
8
3
  }
4
+ export declare type IDEF<T, P = {}, R = {}> = {
5
+ new (...args: unknown[]): T;
6
+ (this: T, ...args: unknown[]): R;
7
+ prototype: P;
8
+ };
9
9
  export {};
package/lib/index.js CHANGED
@@ -1,113 +1,15 @@
1
1
  'use strict';
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BaseClass = void 0;
4
- const ErrorsNames = {
5
- TYPE_MISMATCH: 'Type Mismatch',
6
- ACCESS_DENIED: 'Value Access Denied',
7
- MISSING_PROP: 'Attempt to Access to Undefined Prop',
8
- RIP_FUNCTIONS: 'Functions are Restricted'
9
- };
10
- const PRIMITIVE_TYPES = [
11
- 'string',
12
- 'number',
13
- 'boolean',
14
- ];
15
- const isPrimitive = (value) => {
16
- return PRIMITIVE_TYPES.includes(typeof value);
17
- };
18
- const primitives = (initialValue) => {
19
- let value = Object(initialValue);
20
- const initialType = typeof initialValue;
21
- return {
22
- get() {
23
- const proxyAsValue = new Proxy(value, {
24
- get(_, prop) {
25
- if (prop === Symbol.toPrimitive) {
26
- return function (hint) {
27
- if (hint !== initialType) {
28
- throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
29
- }
30
- return value.valueOf();
31
- };
32
- }
33
- if (prop === 'valueOf') {
34
- return function () {
35
- return value.valueOf();
36
- };
37
- }
38
- if (value[prop] instanceof Function) {
39
- return value[prop].bind(value);
40
- }
41
- return value[prop];
42
- }
43
- });
44
- return proxyAsValue;
45
- },
46
- set(replacementValue) {
47
- if (replacementValue instanceof value.constructor) {
48
- value = replacementValue;
49
- return value;
50
- }
51
- const prevalue = Object(replacementValue);
52
- if (prevalue instanceof value.constructor) {
53
- value = prevalue;
54
- return value;
55
- }
56
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
57
- throw error;
58
- }
59
- };
60
- };
61
- const special = (value) => {
62
- return {
63
- get() {
64
- return value;
65
- },
66
- set(replacementValue) {
67
- if (typeof replacementValue === typeof value) {
68
- value = replacementValue;
69
- return value;
70
- }
71
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
72
- throw error;
73
- }
74
- };
75
- };
76
- const nullish = (value) => {
77
- return {
78
- get() {
79
- return value;
80
- },
81
- set() {
82
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
83
- throw error;
84
- }
85
- };
86
- };
87
- const objects = (value) => {
88
- return {
89
- get() {
90
- return value;
91
- },
92
- set(replacementValue) {
93
- if (replacementValue instanceof Object && replacementValue.constructor === value.constructor) {
94
- value = replacementValue;
95
- return value;
96
- }
97
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
98
- throw error;
99
- }
100
- };
101
- };
102
- const functions = () => {
103
- throw new TypeError(ErrorsNames.RIP_FUNCTIONS);
104
- };
4
+ const errors_1 = require("./errors");
5
+ const types_1 = require("./types");
6
+ const fields_1 = require("./fields");
105
7
  const resolver = Object.entries({
106
- primitives,
107
- special,
108
- nullish,
109
- objects,
110
- functions
8
+ primitives: types_1.primitives,
9
+ special: types_1.special,
10
+ nullish: types_1.nullish,
11
+ objects: types_1.objects,
12
+ functions: types_1.functions
111
13
  }).reduce((obj, [key, _handler]) => {
112
14
  obj[key] = function (initialValue, receiver) {
113
15
  const handler = _handler(initialValue);
@@ -115,14 +17,14 @@ const resolver = Object.entries({
115
17
  get() {
116
18
  const invocationThis = this;
117
19
  if (invocationThis !== receiver) {
118
- throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
20
+ throw new ReferenceError(errors_1.ErrorsNames.ACCESS_DENIED);
119
21
  }
120
22
  return handler.get();
121
23
  },
122
24
  set(replacementValue) {
123
25
  const invocationThis = this;
124
26
  if (invocationThis !== receiver) {
125
- throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
27
+ throw new ReferenceError(errors_1.ErrorsNames.ACCESS_DENIED);
126
28
  }
127
29
  return handler.set(replacementValue);
128
30
  }
@@ -132,15 +34,19 @@ const resolver = Object.entries({
132
34
  }, {});
133
35
  const createProperty = (propName, initialValue, receiver) => {
134
36
  const value = initialValue;
135
- const valueIsPrimitive = isPrimitive(initialValue);
37
+ const valueIsPrimitive = (0, types_1.isPrimitive)(initialValue);
136
38
  const isObject = typeof initialValue === 'object';
137
39
  const isFunction = initialValue instanceof Function;
138
40
  const isNull = initialValue === null;
139
41
  const type = valueIsPrimitive ? 'primitives' : (isObject ? (isNull ? 'nullish' : 'objects') : (isFunction ? 'functions' : 'special'));
140
- const descriptor = resolver[type](value, receiver);
141
- const result = Reflect.defineProperty(receiver, propName, Object.assign(Object.assign({}, descriptor), { enumerable: true }));
42
+ const descriptor = (isObject && (value instanceof fields_1.FieldConstructor)) ?
43
+ value
44
+ : Object.assign({ enumerable: true }, resolver[type](value, receiver));
45
+ const result = Reflect.defineProperty(receiver, propName, descriptor);
142
46
  return result;
143
47
  };
48
+ const util = require('util');
49
+ const props2skip = new Set([util.inspect.custom, Symbol.toStringTag, Symbol.iterator]);
144
50
  const handlers = {
145
51
  get(target, prop, receiver) {
146
52
  const result = Reflect.get(target, prop, receiver);
@@ -155,7 +61,10 @@ const handlers = {
155
61
  }, {}));
156
62
  };
157
63
  }
158
- throw new Error(`${ErrorsNames.MISSING_PROP}: [ ${String(prop).valueOf()} ]`);
64
+ if (props2skip.has(prop)) {
65
+ return undefined;
66
+ }
67
+ throw new Error(`${errors_1.ErrorsNames.MISSING_PROP}: [ ${String(prop).valueOf()} ] of ${receiver.constructor.name}`);
159
68
  },
160
69
  set(_, prop, value, receiver) {
161
70
  const result = createProperty(prop, value, receiver);
@@ -196,3 +105,9 @@ Object.defineProperty(module.exports, 'BaseClass', {
196
105
  },
197
106
  enumerable: true
198
107
  });
108
+ Object.defineProperty(module.exports, 'FieldConstructor', {
109
+ get() {
110
+ return fields_1.FieldConstructor;
111
+ },
112
+ enumerable: true
113
+ });
@@ -0,0 +1 @@
1
+ export declare const functions: () => never;
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.functions = void 0;
4
+ const errors_1 = require("../errors");
5
+ const functions = () => {
6
+ throw new TypeError(errors_1.ErrorsNames.RIP_FUNCTIONS);
7
+ };
8
+ exports.functions = functions;
@@ -0,0 +1,6 @@
1
+ export { functions } from './functions';
2
+ export { nullish } from './nullish';
3
+ export { objects } from './objects';
4
+ export { primitives } from './primitives';
5
+ export { special } from './special';
6
+ export declare const isPrimitive: (value: unknown) => boolean;
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPrimitive = exports.special = exports.primitives = exports.objects = exports.nullish = exports.functions = void 0;
4
+ var functions_1 = require("./functions");
5
+ Object.defineProperty(exports, "functions", { enumerable: true, get: function () { return functions_1.functions; } });
6
+ var nullish_1 = require("./nullish");
7
+ Object.defineProperty(exports, "nullish", { enumerable: true, get: function () { return nullish_1.nullish; } });
8
+ var objects_1 = require("./objects");
9
+ Object.defineProperty(exports, "objects", { enumerable: true, get: function () { return objects_1.objects; } });
10
+ var primitives_1 = require("./primitives");
11
+ Object.defineProperty(exports, "primitives", { enumerable: true, get: function () { return primitives_1.primitives; } });
12
+ var special_1 = require("./special");
13
+ Object.defineProperty(exports, "special", { enumerable: true, get: function () { return special_1.special; } });
14
+ const PRIMITIVE_TYPES = [
15
+ 'string',
16
+ 'number',
17
+ 'boolean',
18
+ ];
19
+ const isPrimitive = (value) => {
20
+ return PRIMITIVE_TYPES.includes(typeof value);
21
+ };
22
+ exports.isPrimitive = isPrimitive;
@@ -0,0 +1,4 @@
1
+ export declare const nullish: (value: object) => {
2
+ get(): object;
3
+ set(): never;
4
+ };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nullish = void 0;
4
+ const errors_1 = require("../errors");
5
+ const nullish = (value) => {
6
+ return {
7
+ get() {
8
+ return value;
9
+ },
10
+ set() {
11
+ const error = new TypeError(errors_1.ErrorsNames.TYPE_MISMATCH);
12
+ throw error;
13
+ }
14
+ };
15
+ };
16
+ exports.nullish = nullish;
@@ -0,0 +1,4 @@
1
+ export declare const objects: (value: object) => {
2
+ get(): object;
3
+ set(replacementValue: unknown): object;
4
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.objects = void 0;
4
+ const errors_1 = require("../errors");
5
+ const objects = (value) => {
6
+ return {
7
+ get() {
8
+ return value;
9
+ },
10
+ set(replacementValue) {
11
+ if (replacementValue instanceof Object && replacementValue.constructor === value.constructor) {
12
+ value = replacementValue;
13
+ return value;
14
+ }
15
+ const error = new TypeError(errors_1.ErrorsNames.TYPE_MISMATCH);
16
+ throw error;
17
+ }
18
+ };
19
+ };
20
+ exports.objects = objects;
@@ -0,0 +1,4 @@
1
+ export declare const primitives: (initialValue: object) => {
2
+ get(): any;
3
+ set(replacementValue: unknown): any;
4
+ };
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.primitives = void 0;
4
+ const errors_1 = require("../errors");
5
+ const primitives = (initialValue) => {
6
+ let value = Object(initialValue);
7
+ const initialType = typeof initialValue;
8
+ return {
9
+ get() {
10
+ const proxyAsValue = new Proxy(value, {
11
+ get(_, prop) {
12
+ if (prop === Symbol.toPrimitive) {
13
+ return function (hint) {
14
+ if (hint !== initialType) {
15
+ throw new ReferenceError(errors_1.ErrorsNames.ACCESS_DENIED);
16
+ }
17
+ return value.valueOf();
18
+ };
19
+ }
20
+ if (prop === 'valueOf') {
21
+ return function () {
22
+ return value.valueOf();
23
+ };
24
+ }
25
+ if (value[prop] instanceof Function) {
26
+ return value[prop].bind(value);
27
+ }
28
+ return value[prop];
29
+ }
30
+ });
31
+ return proxyAsValue;
32
+ },
33
+ set(replacementValue) {
34
+ if (replacementValue instanceof value.constructor) {
35
+ value = replacementValue;
36
+ return value;
37
+ }
38
+ const prevalue = Object(replacementValue);
39
+ if (prevalue instanceof value.constructor) {
40
+ value = prevalue;
41
+ return value;
42
+ }
43
+ const error = new TypeError(errors_1.ErrorsNames.TYPE_MISMATCH);
44
+ throw error;
45
+ }
46
+ };
47
+ };
48
+ exports.primitives = primitives;
@@ -0,0 +1,4 @@
1
+ export declare const special: (value: object) => {
2
+ get(): object;
3
+ set(replacementValue: object): object;
4
+ };
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.special = void 0;
4
+ const errors_1 = require("../errors");
5
+ const special = (value) => {
6
+ return {
7
+ get() {
8
+ return value;
9
+ },
10
+ set(replacementValue) {
11
+ if (typeof replacementValue === typeof value) {
12
+ value = replacementValue;
13
+ return value;
14
+ }
15
+ const error = new TypeError(errors_1.ErrorsNames.TYPE_MISMATCH);
16
+ throw error;
17
+ }
18
+ };
19
+ };
20
+ exports.special = special;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typeomatica",
3
- "version": "0.2.2",
3
+ "version": "0.2.7",
4
4
  "description": "type logic against javascript metaprogramming",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -9,7 +9,9 @@
9
9
  "lint": "npx eslint --fix --ignore-path .gitignore ./lib",
10
10
  "test": "npx jest",
11
11
  "test:cov": "npx jest --collectCoverage",
12
- "debug": "npx --node-arg=--inspect-brk jest"
12
+ "debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
13
+ "debug:old": "npx --node-options=--inspect-brk jest",
14
+ "prepare": "husky install"
13
15
  },
14
16
  "keywords": [
15
17
  "strict",
@@ -23,18 +25,18 @@
23
25
  "repository": {
24
26
  "type": "git",
25
27
  "url": "git+https://github.com/wentout/typeomatica.git"
26
- },
28
+ },
27
29
  "devDependencies": {
28
- "@types/jest": "^26.0.22",
29
- "@types/node": "^14.14.37",
30
- "eslint": "^7.23.0",
31
- "husky": "^3.1.0",
32
- "jest": "^26.6.3",
33
- "ts-jest": "^26.5.4",
34
- "ts-node": "^9.1.1",
30
+ "@types/jest": "^27.0.1",
31
+ "@types/node": "^16.9.2",
32
+ "eslint": "^7.32.0",
33
+ "husky": "^8.0.0",
34
+ "jest": "^27.2.0",
35
+ "lint-staged": "^11.1.2",
36
+ "set-value": "^4.1.0",
37
+ "ts-jest": "^27.0.5",
38
+ "ts-node": "^10.2.1",
35
39
  "tslint": "^6.1.3",
36
- "typescript": "^4.2.3",
37
- "typologica": "0.0.77",
38
- "lint-staged": "^10.5.4"
40
+ "typescript": "^4.4.3"
39
41
  }
40
42
  }
package/src/errors.ts ADDED
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ export const ErrorsNames = {
4
+ TYPE_MISMATCH: 'Type Mismatch',
5
+ ACCESS_DENIED: 'Value Access Denied',
6
+ MISSING_PROP: 'Attempt to Access to Undefined Prop',
7
+ RIP_FUNCTIONS: 'Functions are Restricted'
8
+ };
package/src/fields.ts ADDED
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ export const SymbolInitialValue = Symbol('Initial Value');
4
+
5
+ interface FieldDefinition {
6
+ [SymbolInitialValue]: unknown
7
+ // get?: unknown
8
+ // set?: unknown
9
+ // configurable: boolean,
10
+ // enumerable: boolean,
11
+ // writable: boolean
12
+ }
13
+
14
+ export const FieldConstructor = function (this: FieldDefinition, value: unknown) {
15
+ this[SymbolInitialValue] = value;
16
+ } as ObjectConstructor;
17
+
18
+ // Object.assign(FieldConstructor.prototype, {
19
+ // configurable: false,
20
+ // enumerable: false,
21
+ // // writable: false
22
+ // })
23
+
24
+ // Object.defineProperty(FieldConstructor.prototype, 'get', {
25
+ // get() {
26
+ // return this[symbolValue];
27
+ // },
28
+ // // @ts-ignore
29
+ // set(value: unknown) {
30
+ // throw new Error('broken behaviour: assignment to getter');
31
+ // },
32
+ // configurable: false,
33
+ // enumerable: true,
34
+ // // writable: false
35
+ // });
36
+
37
+ // Object.defineProperty(FieldConstructor.prototype, 'set', {
38
+ // get() {
39
+ // return function (this: FieldDefinition, value: unknown) {
40
+ // this[symbolValue] = value;
41
+ // }
42
+ // },
43
+ // // @ts-ignore
44
+ // set(value: unknown) {
45
+ // throw new Error('broken behaviour: assignment to setter');
46
+ // },
47
+ // configurable: false,
48
+ // enumerable: true,
49
+ // // writable: false
50
+ // });
51
+
52
+ Object.freeze(FieldConstructor.prototype);
53
+ Object.seal(FieldConstructor.prototype);
package/src/index.ts CHANGED
@@ -1,136 +1,17 @@
1
1
  'use strict';
2
2
 
3
- const ErrorsNames = {
4
- TYPE_MISMATCH: 'Type Mismatch',
5
- ACCESS_DENIED: 'Value Access Denied',
6
- MISSING_PROP: 'Attempt to Access to Undefined Prop',
7
- RIP_FUNCTIONS: 'Functions are Restricted'
8
- };
9
-
10
- const PRIMITIVE_TYPES = [
11
- 'string',
12
- 'number',
13
- 'boolean',
14
- ];
15
-
16
- const isPrimitive = (value: unknown) => {
17
- return PRIMITIVE_TYPES.includes(typeof value);
18
- };
19
-
20
- const primitives = (initialValue: object) => {
21
- let value = Object(initialValue);
22
- const initialType = typeof initialValue;
23
-
24
- return {
25
- get() {
26
- const proxyAsValue = new Proxy(value, {
27
- // get(target, prop, receiver) {
28
- get(_, prop) {
29
-
30
- if (prop === Symbol.toPrimitive) {
31
- return function (hint: string) {
32
- if (hint !== initialType) {
33
- throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
34
- }
35
- return value.valueOf();
36
- }
37
- }
38
-
39
- if (prop === 'valueOf') {
40
- return function () {
41
- return value.valueOf();
42
- }
43
- }
44
-
45
- // @ts-ignore
46
- if (value[prop] instanceof Function) {
47
- return value[prop].bind(value);
48
- }
49
-
50
- return value[prop];
51
- }
52
- });
53
- return proxyAsValue;
54
- },
55
- // get() {
56
- // const preparedValue = {
57
- // [Symbol.toPrimitive]() {
58
- // return function () {
59
- // throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
60
- // };
61
- // }
62
- // };
63
- // Reflect.setPrototypeOf(preparedValue, value);
64
- // debugger;
65
- // return preparedValue;
66
- // },
67
- set(replacementValue: unknown) {
68
- if (replacementValue instanceof value.constructor) {
69
- value = replacementValue;
70
- return value;
71
- }
72
-
73
- const prevalue = Object(replacementValue);
74
-
75
- if (prevalue instanceof value.constructor) {
76
- value = prevalue;
77
- return value;
78
- }
79
-
80
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
81
- throw error;
82
- }
83
- };
84
- };
85
-
86
- const special = (value: object) => {
87
- return {
88
- get() {
89
- return value;
90
- },
91
- set(replacementValue: object) {
92
- if (typeof replacementValue === typeof value) {
93
- value = replacementValue;
94
- return value;
95
-
96
- }
97
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
98
- throw error;
99
- }
100
- }
101
- };
102
-
103
- const nullish = (value: object) => {
104
- return {
105
- get() {
106
- return value;
107
- },
108
- set() {
109
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
110
- throw error;
111
- }
112
- }
113
- };
3
+ import { ErrorsNames } from './errors';
114
4
 
115
- const objects = (value: object) => {
116
- return {
117
- get() {
118
- return value;
119
- },
120
- set(replacementValue: unknown) {
121
- if (replacementValue instanceof Object && replacementValue.constructor === value.constructor) {
122
- value = replacementValue;
123
- return value;
124
- }
125
- const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
126
- throw error;
127
- }
128
- }
129
- };
5
+ import {
6
+ functions,
7
+ nullish,
8
+ objects,
9
+ primitives,
10
+ special,
11
+ isPrimitive
12
+ } from './types';
130
13
 
131
- const functions = () => {
132
- throw new TypeError(ErrorsNames.RIP_FUNCTIONS);
133
- };
14
+ import { FieldConstructor } from './fields';
134
15
 
135
16
  const resolver = Object.entries({
136
17
  primitives,
@@ -163,7 +44,8 @@ const resolver = Object.entries({
163
44
  return obj;
164
45
  }, {});
165
46
 
166
- const createProperty = (propName: string, initialValue: any, receiver: object) => {
47
+
48
+ const createProperty = (propName: string, initialValue: unknown, receiver: object) => {
167
49
 
168
50
  const value = initialValue;
169
51
  const valueIsPrimitive = isPrimitive(initialValue);
@@ -171,23 +53,40 @@ const createProperty = (propName: string, initialValue: any, receiver: object) =
171
53
  const isFunction = initialValue instanceof Function;
172
54
  const isNull = initialValue === null;
173
55
 
56
+ /**
57
+ * special: undefined or BigInt or Symbol
58
+ * or other non constructible type
59
+ */
60
+
174
61
  const type = valueIsPrimitive ? 'primitives' : (
175
62
  isObject ? (
176
63
  isNull ? 'nullish' : 'objects'
177
64
  ) : (
178
- isFunction ? 'functions' : 'special'));
179
-
180
- // @ts-ignore
181
- const descriptor = resolver[type](value, receiver);
65
+ isFunction ? 'functions' : 'special'
66
+ )
67
+ );
68
+
69
+ const descriptor = (isObject && (value instanceof FieldConstructor)) ?
70
+ value
71
+ :
72
+ {
73
+ enumerable: true,
74
+ // @ts-ignore
75
+ ...resolver[type](value, receiver),
76
+ };
182
77
 
183
- const result = Reflect.defineProperty(receiver, propName, {
184
- ...descriptor,
185
- enumerable: true
186
- });
78
+ // if (value instanceof FieldConstructor) {
79
+ // descriptor;
80
+ // debugger;
81
+ // }
187
82
 
83
+ const result = Reflect.defineProperty(receiver, propName, descriptor);
188
84
  return result;
85
+
189
86
  };
190
87
 
88
+ const util = require('util');
89
+ const props2skip = new Set([util.inspect.custom, Symbol.toStringTag, Symbol.iterator]);
191
90
 
192
91
  const handlers = {
193
92
  get(target: object, prop: string | symbol, receiver: object) {
@@ -204,7 +103,10 @@ const handlers = {
204
103
  }, {}));
205
104
  }
206
105
  }
207
- throw new Error(`${ErrorsNames.MISSING_PROP}: [ ${String(prop).valueOf()} ]`);
106
+ if (props2skip.has(prop)) {
107
+ return undefined;
108
+ }
109
+ throw new Error(`${ErrorsNames.MISSING_PROP}: [ ${String(prop).valueOf()} ] of ${receiver.constructor.name}`);
208
110
  },
209
111
  set(_: object, prop: string, value: unknown, receiver: object) {
210
112
  const result = createProperty(prop, value, receiver);
@@ -221,12 +123,6 @@ const BaseTarget = Object.create(null);
221
123
 
222
124
  // const BasePrototype = new Proxy(BaseTarget, handlers);
223
125
 
224
- export type IDEF<T, P = {}, R = {}> = {
225
- new(...args: any[]): T;
226
- (this: T, ...args: any[]): R;
227
- prototype: P;
228
- };
229
-
230
126
  // @ts-ignore
231
127
  const BaseConstructor = function (this: object, InstanceTarget = BaseTarget) {
232
128
  if (!new.target) {
@@ -261,10 +157,24 @@ Object.defineProperty(module, 'exports', {
261
157
 
262
158
  // @ts-ignore
263
159
  export class BaseClass extends BaseConstructor { };
160
+ // export { FieldConstructor } from './fields';
264
161
 
265
162
  Object.defineProperty(module.exports, 'BaseClass', {
266
163
  get() {
267
164
  return BaseClass;
268
165
  },
269
166
  enumerable: true
270
- });
167
+ });
168
+ Object.defineProperty(module.exports, 'FieldConstructor', {
169
+ get() {
170
+ return FieldConstructor;
171
+ },
172
+ enumerable: true
173
+ });
174
+
175
+
176
+ export type IDEF<T, P = {}, R = {}> = {
177
+ new(...args: unknown[]): T;
178
+ (this: T, ...args: unknown[]): R;
179
+ prototype: P;
180
+ };
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ import { ErrorsNames } from '../errors';
4
+
5
+ export const functions = () => {
6
+ throw new TypeError(ErrorsNames.RIP_FUNCTIONS);
7
+ };
@@ -0,0 +1,17 @@
1
+ 'use strict';
2
+
3
+ export { functions } from './functions';
4
+ export { nullish } from './nullish';
5
+ export { objects } from './objects';
6
+ export { primitives } from './primitives';
7
+ export { special } from './special';
8
+
9
+ const PRIMITIVE_TYPES = [
10
+ 'string',
11
+ 'number',
12
+ 'boolean',
13
+ ];
14
+
15
+ export const isPrimitive = (value: unknown) => {
16
+ return PRIMITIVE_TYPES.includes(typeof value);
17
+ };
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ import { ErrorsNames } from '../errors';
4
+
5
+ export const nullish = (value: object) => {
6
+ return {
7
+ get() {
8
+ return value;
9
+ },
10
+ set() {
11
+ const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
12
+ throw error;
13
+ }
14
+ }
15
+ };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ import { ErrorsNames } from '../errors';
4
+
5
+ export const objects = (value: object) => {
6
+ return {
7
+ get() {
8
+ return value;
9
+ },
10
+ set(replacementValue: unknown) {
11
+ if (replacementValue instanceof Object && replacementValue.constructor === value.constructor) {
12
+ value = replacementValue;
13
+ return value;
14
+ }
15
+ const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
16
+ throw error;
17
+ }
18
+ }
19
+ };
@@ -0,0 +1,68 @@
1
+ 'use strict';
2
+
3
+ import { ErrorsNames } from '../errors';
4
+
5
+ export const primitives = (initialValue: object) => {
6
+ let value = Object(initialValue);
7
+ const initialType = typeof initialValue;
8
+
9
+ return {
10
+ get() {
11
+ const proxyAsValue = new Proxy(value, {
12
+ // get(target, prop, receiver) {
13
+ get(_, prop) {
14
+ if (prop === Symbol.toPrimitive) {
15
+ return function (hint: string) {
16
+ if (hint !== initialType) {
17
+ throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
18
+ }
19
+ return value.valueOf();
20
+ }
21
+ }
22
+
23
+ if (prop === 'valueOf') {
24
+ return function () {
25
+ return value.valueOf();
26
+ }
27
+ }
28
+
29
+ // @ts-ignore
30
+ if (value[prop] instanceof Function) {
31
+ return value[prop].bind(value);
32
+ }
33
+
34
+ return value[prop];
35
+ }
36
+ });
37
+ return proxyAsValue;
38
+ },
39
+ // get() {
40
+ // const preparedValue = {
41
+ // [Symbol.toPrimitive]() {
42
+ // return function () {
43
+ // throw new ReferenceError(ErrorsNames.ACCESS_DENIED);
44
+ // };
45
+ // }
46
+ // };
47
+ // Reflect.setPrototypeOf(preparedValue, value);
48
+ // debugger;
49
+ // return preparedValue;
50
+ // },
51
+ set(replacementValue: unknown) {
52
+ if (replacementValue instanceof value.constructor) {
53
+ value = replacementValue;
54
+ return value;
55
+ }
56
+
57
+ const prevalue = Object(replacementValue);
58
+
59
+ if (prevalue instanceof value.constructor) {
60
+ value = prevalue;
61
+ return value;
62
+ }
63
+
64
+ const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
65
+ throw error;
66
+ }
67
+ };
68
+ };
@@ -0,0 +1,19 @@
1
+ 'use strict';
2
+
3
+ import { ErrorsNames } from '../errors';
4
+
5
+ export const special = (value: object) => {
6
+ return {
7
+ get() {
8
+ return value;
9
+ },
10
+ set(replacementValue: object) {
11
+ if (typeof replacementValue === typeof value) {
12
+ value = replacementValue;
13
+ return value;
14
+ }
15
+ const error = new TypeError(ErrorsNames.TYPE_MISMATCH);
16
+ throw error;
17
+ }
18
+ }
19
+ };
package/test/index.ts CHANGED
@@ -5,7 +5,10 @@
5
5
  // or meaningless
6
6
 
7
7
  const BasePrototype = require('..');
8
- import { BaseClass, IDEF } from '..';
8
+ // @ts-ignore
9
+ import { BaseClass, IDEF, FieldConstructor } from '..';
10
+
11
+ debugger;
9
12
 
10
13
  class Base extends BasePrototype({
11
14
  additionalProp: 321,
@@ -14,14 +17,22 @@ class Base extends BasePrototype({
14
17
  },
15
18
  }) {
16
19
  numberValue = 123;
20
+
21
+ get getterField() {
22
+ return '123';
23
+ }
24
+
25
+ set setterField(value: string) {
26
+ this.stringValue = value;
27
+ }
28
+
17
29
  constructor() {
18
30
  super();
19
31
  this.stringValue = '123';
20
32
  this.booleanValue = true;
21
33
  this.objectValue = {};
22
34
  }
23
- };
24
-
35
+ }
25
36
  const baseInstance = new Base;
26
37
 
27
38
  const upperInstance = Object.create(baseInstance);
@@ -29,7 +40,6 @@ const upperInstance = Object.create(baseInstance);
29
40
  class SimpleBase extends BaseClass {
30
41
  stringProp = '123';
31
42
  };
32
-
33
43
  const simpleInstance = new SimpleBase;
34
44
 
35
45
  type MyFunctionalConstructorInstance = {
@@ -37,6 +47,7 @@ type MyFunctionalConstructorInstance = {
37
47
  };
38
48
 
39
49
  const MyFunctionalConstructor = function () {
50
+ // @ts-ignore
40
51
  this.stringProp = '123';
41
52
  } as IDEF<MyFunctionalConstructorInstance>;
42
53
 
@@ -44,7 +55,8 @@ Reflect.setPrototypeOf(MyFunctionalConstructor.prototype, new BasePrototype);
44
55
 
45
56
  const myFunctionalInstance = new MyFunctionalConstructor();
46
57
 
47
- class TripleExtend extends Base { };
58
+ class SecondaryExtend extends Base { second = 123 };
59
+ class TripleExtend extends SecondaryExtend { };
48
60
  const tiripleExtendInstance = new TripleExtend;
49
61
 
50
62
  class NetworkedExtention extends BasePrototype(tiripleExtendInstance) { };
@@ -59,6 +71,38 @@ const extendedSetInstance = new ExtendedSet;
59
71
 
60
72
  const MUTATION_VALUE = -2;
61
73
 
74
+
75
+ class MyFieldConstructor extends FieldConstructor {
76
+ constructor(value: string) {
77
+ super(value);
78
+ Reflect.defineProperty(this, 'enumerable', {
79
+ value: true
80
+ });
81
+ Reflect.defineProperty(this, 'get', {
82
+ get () {
83
+ return function () {
84
+ return value;
85
+ }
86
+ }
87
+ });
88
+ Reflect.defineProperty(this, 'set', {
89
+ get () {
90
+ return function (_value: string) {
91
+ value = _value;
92
+ }
93
+ },
94
+ enumerable: true
95
+ });
96
+ }
97
+ }
98
+
99
+ const myField = new MyFieldConstructor('zzz');
100
+ class MadeFieldClass extends BaseClass { myField = myField };
101
+ class SecondMadeFieldClass extends BaseClass { myField = myField };
102
+ const madeFieldInstance = new MadeFieldClass;
103
+ const secondMadeFieldInstance = new MadeFieldClass;
104
+ const thirdMadeFieldInstance = new SecondMadeFieldClass;
105
+
62
106
  describe('props tests', () => {
63
107
 
64
108
  test('base instance has props', () => {
@@ -127,6 +171,25 @@ describe('props tests', () => {
127
171
  expect(baseInstance.objectValue.a).toEqual(123);
128
172
  });
129
173
 
174
+ test('correct custom field creation', () => {
175
+ expect(madeFieldInstance.myField).toEqual('zzz');
176
+ });
177
+ test('correct custom field assignment', () => {
178
+ madeFieldInstance.myField = 123;
179
+ expect(secondMadeFieldInstance.myField).toEqual(123);
180
+ expect(thirdMadeFieldInstance.myField).toEqual(123);
181
+ });
182
+
183
+ test('correct custom missing prop search creation', () => {
184
+ // @ts-ignore
185
+ expect(madeFieldInstance[Symbol.toStringTag]).toEqual(undefined);
186
+ // @ts-ignore
187
+ expect(madeFieldInstance[Symbol.iterator]).toEqual(undefined);
188
+ const util = require('util');
189
+ // @ts-ignore
190
+ expect(madeFieldInstance[util.inspect.custom]).toEqual(undefined);
191
+ });
192
+
130
193
  test('wrong assignment to objects', () => {
131
194
 
132
195
  expect(() => {
@@ -249,7 +312,7 @@ describe('props tests', () => {
249
312
 
250
313
  baseInstance.missingValue > 1;
251
314
 
252
- }).toThrow(new TypeError('Attempt to Access to Undefined Prop: [ missingValue ]'));
315
+ }).toThrow(new TypeError('Attempt to Access to Undefined Prop: [ missingValue ] of Base'));
253
316
  });
254
317
 
255
318
  });
@@ -368,9 +431,10 @@ describe('deep extend works', () => {
368
431
  test('class extended three times construction', () => {
369
432
 
370
433
  expect(tiripleExtendInstance).toBeInstanceOf(Base);
371
- expect(tiripleExtendInstance).toBeInstanceOf(TripleExtend);
434
+ expect(tiripleExtendInstance).toBeInstanceOf(SecondaryExtend);
372
435
  expect(tiripleExtendInstance).toBeInstanceOf(TripleExtend);
373
436
  expect(`${tiripleExtendInstance.stringValue}`).toEqual('123');
437
+ expect(tiripleExtendInstance.second).toBeInstanceOf(Number);
374
438
 
375
439
  });
376
440
 
@@ -22,9 +22,9 @@
22
22
  "removeComments": true,
23
23
  "experimentalDecorators": true,
24
24
  "forceConsistentCasingInFileNames": true,
25
- "types": [
26
- "jest",
27
- "node"
28
- ]
29
- },
25
+ "types": [
26
+ "jest",
27
+ "node"
28
+ ]
29
+ },
30
30
  }